@@ -10,14 +10,16 @@ window.app = Vue.createApp({
1010 data ( ) {
1111 return {
1212 loading : false ,
13- selectedWallet : null ,
13+ selectedWallet : 'all' ,
1414 devices : [ ] ,
1515 filter : '' ,
1616 currencies : [ 'sat' , 'EUR' , 'USD' , 'GBP' , 'CHF' , 'CAD' , 'JPY' , 'INR' , 'ZAR' , 'CZK' ] ,
1717 timezones : [ 'Europe/Amsterdam' ] ,
1818 lnurlValue : '' ,
1919 qrcodeUrl : '' ,
2020 websocketMessage : '' ,
21+ activeWebsocketDeviceId : null ,
22+ activeWebsocket : null ,
2123 protocol : window . location . protocol ,
2224 wsLocation : '' ,
2325
@@ -28,6 +30,7 @@ window.app = Vue.createApp({
2830 } ,
2931
3032 deviceColumns : [
33+ { name : 'id' , label : 'ID' , field : 'id' , align : 'left' } ,
3134 { name : 'title' , label : 'Device' , field : 'title' , align : 'left' , sortable : true } ,
3235 { name : 'currency' , label : 'Currency' , field : 'currency' , align : 'left' } ,
3336 { name : 'timezone' , label : 'Timezone' , field : 'timezone' , align : 'left' } ,
@@ -61,6 +64,19 @@ window.app = Vue.createApp({
6164 selectedSwitch : null
6265 } ,
6366
67+ websocketDialog : {
68+ show : false ,
69+ url : '' ,
70+ deviceTitle : ''
71+ } ,
72+
73+ deleteDialog : {
74+ show : false ,
75+ deviceId : null ,
76+ deviceTitle : '' ,
77+ switchCount : 0
78+ } ,
79+
6480 drawerRight : false
6581 }
6682 } ,
@@ -70,30 +86,48 @@ window.app = Vue.createApp({
7086 return this . websocketMessage
7187 } ,
7288 filteredDevices ( ) {
73- if ( ! this . filter ) return this . devices
74- const search = this . filter . toLowerCase ( )
75- return this . devices . filter ( d =>
76- d . title . toLowerCase ( ) . includes ( search ) ||
77- d . currency . toLowerCase ( ) . includes ( search )
78- )
89+ let devices = this . devices
90+ // Filter by wallet if not "all"
91+ if ( this . selectedWallet && this . selectedWallet !== 'all' ) {
92+ devices = devices . filter ( d => d . wallet === this . selectedWallet )
93+ }
94+ // Filter by search term
95+ if ( this . filter ) {
96+ const search = this . filter . toLowerCase ( )
97+ devices = devices . filter ( d =>
98+ d . title . toLowerCase ( ) . includes ( search ) ||
99+ d . currency . toLowerCase ( ) . includes ( search )
100+ )
101+ }
102+ return devices
79103 } ,
80104 walletsWithCount ( ) {
81- return this . g . user . wallets . map ( w => ( {
105+ const wallets = this . g . user . wallets . map ( w => ( {
82106 ...w ,
83107 deviceCount : this . devices . filter ( d => d . wallet === w . id ) . length
84108 } ) )
109+ return [
110+ { id : 'all' , name : 'All Wallets' , deviceCount : this . devices . length } ,
111+ ...wallets
112+ ]
85113 }
86114 } ,
87115
88116 methods : {
89117 onWalletChange ( ) {
90- this . getDevices ( )
118+ // Filtering is handled by filteredDevices computed property
119+ this . calculateStats ( )
91120 } ,
92121
93122 calculateStats ( ) {
94- this . stats . totalDevices = this . devices . length
95- this . stats . activeDevices = this . devices . length
96- this . stats . totalSwitches = this . devices . reduce ( ( sum , d ) => sum + ( d . switches ?. length || 0 ) , 0 )
123+ // Use filtered devices for stats when wallet is selected
124+ let devices = this . devices
125+ if ( this . selectedWallet && this . selectedWallet !== 'all' ) {
126+ devices = this . devices . filter ( d => d . wallet === this . selectedWallet )
127+ }
128+ this . stats . totalDevices = devices . length
129+ this . stats . activeDevices = devices . length
130+ this . stats . totalSwitches = devices . reduce ( ( sum , d ) => sum + ( d . switches ?. length || 0 ) , 0 )
97131 } ,
98132
99133 formatHours ( device ) {
@@ -103,11 +137,11 @@ window.app = Vue.createApp({
103137 async getDevices ( ) {
104138 this . loading = true
105139 try {
106- const wallet = _ . findWhere ( this . g . user . wallets , { id : this . selectedWallet } )
140+ // Always fetch all devices using the first wallet's adminkey
107141 const response = await LNbits . api . request (
108142 'GET' ,
109143 '/devicetimer/api/v1/device' ,
110- wallet ?. adminkey || this . g . user . wallets [ 0 ] . adminkey
144+ this . g . user . wallets [ 0 ] . adminkey
111145 )
112146 if ( response . data ) {
113147 this . devices = response . data . map ( mapDevice )
@@ -187,23 +221,30 @@ window.app = Vue.createApp({
187221
188222 deleteDevice ( deviceId ) {
189223 const device = this . devices . find ( d => d . id === deviceId )
190- LNbits . utils
191- . confirmDialog ( `Delete "${ device ?. title } "?` )
192- . onOk ( async ( ) => {
193- try {
194- const wallet = _ . findWhere ( this . g . user . wallets , { id : device . wallet } )
195- await LNbits . api . request (
196- 'DELETE' ,
197- '/devicetimer/api/v1/device/' + deviceId ,
198- wallet ?. adminkey || this . g . user . wallets [ 0 ] . adminkey
199- )
200- this . devices = this . devices . filter ( d => d . id !== deviceId )
201- this . calculateStats ( )
202- this . $q . notify ( { type : 'positive' , message : 'Device deleted' } )
203- } catch ( error ) {
204- LNbits . utils . notifyApiError ( error )
205- }
206- } )
224+ if ( ! device ) return
225+ this . deleteDialog . deviceId = deviceId
226+ this . deleteDialog . deviceTitle = device . title
227+ this . deleteDialog . switchCount = device . switches ?. length || 0
228+ this . deleteDialog . show = true
229+ } ,
230+
231+ async confirmDeleteDevice ( ) {
232+ const deviceId = this . deleteDialog . deviceId
233+ const device = this . devices . find ( d => d . id === deviceId )
234+ try {
235+ const wallet = _ . findWhere ( this . g . user . wallets , { id : device ?. wallet } )
236+ await LNbits . api . request (
237+ 'DELETE' ,
238+ '/devicetimer/api/v1/device/' + deviceId ,
239+ wallet ?. adminkey || this . g . user . wallets [ 0 ] . adminkey
240+ )
241+ this . devices = this . devices . filter ( d => d . id !== deviceId )
242+ this . calculateStats ( )
243+ this . deleteDialog . show = false
244+ this . $q . notify ( { type : 'positive' , message : 'Device deleted' } )
245+ } catch ( error ) {
246+ LNbits . utils . notifyApiError ( error )
247+ }
207248 } ,
208249
209250 openDeviceDialog ( device = null ) {
@@ -251,7 +292,7 @@ window.app = Vue.createApp({
251292 this . qrCodeDialog . selectedSwitch = device . switches [ 0 ]
252293 this . lnurlValue = device . switches [ 0 ] . lnurl
253294 this . qrcodeUrl = '/devicetimer/device/' + device . id + '/' + device . switches [ 0 ] . id + '/qrcode?' + Date . now ( )
254- this . websocketConnector ( this . wsLocation + '/api/v1/ws/' + device . id )
295+ this . websocketConnector ( this . wsLocation + '/api/v1/ws/' + device . id , device . id )
255296 this . qrCodeDialog . show = true
256297 } ,
257298
@@ -264,7 +305,7 @@ window.app = Vue.createApp({
264305 this . qrCodeDialog . selectedSwitch = sw
265306 this . lnurlValue = sw . lnurl
266307 this . qrcodeUrl = '/devicetimer/device/' + device . id + '/' + sw . id + '/qrcode?' + Date . now ( )
267- this . websocketConnector ( this . wsLocation + '/api/v1/ws/' + device . id )
308+ this . websocketConnector ( this . wsLocation + '/api/v1/ws/' + device . id , device . id )
268309 this . qrCodeDialog . show = true
269310 } ,
270311
@@ -290,14 +331,19 @@ window.app = Vue.createApp({
290331 this . deviceDialog . data . switches . splice ( index , 1 )
291332 } ,
292333
293- websocketConnector ( websocketUrl ) {
334+ websocketConnector ( websocketUrl , deviceId ) {
335+ if ( this . activeWebsocket ) {
336+ this . activeWebsocket . close ( )
337+ }
294338 if ( ! ( 'WebSocket' in window ) ) {
295339 this . websocketMessage = 'WebSocket not supported'
296340 return
297341 }
298342 try {
299343 this . websocketMessage = 'Connecting...'
344+ this . activeWebsocketDeviceId = deviceId
300345 const ws = new WebSocket ( websocketUrl )
346+ this . activeWebsocket = ws
301347 ws . onopen = ( ) => {
302348 this . websocketMessage = 'connected'
303349 }
@@ -306,12 +352,17 @@ window.app = Vue.createApp({
306352 }
307353 ws . onclose = ( ) => {
308354 this . websocketMessage = 'Disconnected'
355+ this . activeWebsocketDeviceId = null
356+ this . activeWebsocket = null
309357 }
310358 ws . onerror = ( ) => {
311359 this . websocketMessage = 'Connection error'
360+ this . activeWebsocketDeviceId = null
361+ this . activeWebsocket = null
312362 }
313363 } catch ( e ) {
314364 this . websocketMessage = 'WebSocket error'
365+ this . activeWebsocketDeviceId = null
315366 }
316367 } ,
317368
@@ -321,9 +372,10 @@ window.app = Vue.createApp({
321372 } )
322373 } ,
323374
324- copyWebsocketUrl ( deviceId ) {
325- const url = this . wsLocation + '/api/v1/ws/' + deviceId
326- this . copyText ( url , 'WebSocket URL copied' )
375+ openWebsocketDialog ( device ) {
376+ this . websocketDialog . url = this . wsLocation + '/api/v1/ws/' + device . id
377+ this . websocketDialog . deviceTitle = device . title
378+ this . websocketDialog . show = true
327379 } ,
328380
329381 exportCSV ( ) {
@@ -336,7 +388,7 @@ window.app = Vue.createApp({
336388 } ,
337389
338390 async created ( ) {
339- this . selectedWallet = this . g . user . wallets [ 0 ] ?. id
391+ this . selectedWallet = 'all'
340392 this . wsLocation = ( window . location . protocol === 'https:' ? 'wss://' : 'ws://' ) + window . location . host
341393
342394 await this . getDevices ( )
0 commit comments