]>
Commit | Line | Data |
---|---|---|
4a580e60 DM |
1 | Ext.define('PVE.storage.ContentView', { |
2 | extend: 'Ext.grid.GridPanel', | |
3 | ||
3f90858a | 4 | alias: 'widget.pveStorageContentView', |
4a580e60 | 5 | |
62580ab8 TL |
6 | itemdblclick: Ext.emptyFn, |
7 | ||
c90539de DC |
8 | viewConfig: { |
9 | trackOver: false, | |
1d8306e4 | 10 | loadMask: false, |
c90539de | 11 | }, |
1d8306e4 | 12 | initComponent: function() { |
4a580e60 DM |
13 | var me = this; |
14 | ||
dbeddeb3 FE |
15 | if (!me.nodename) { |
16 | me.nodename = me.pveSelNode.data.node; | |
17 | if (!me.nodename) { | |
18 | throw "no node name specified"; | |
19 | } | |
4a580e60 | 20 | } |
1d8306e4 | 21 | const nodename = me.nodename; |
4a580e60 | 22 | |
dbeddeb3 FE |
23 | if (!me.storage) { |
24 | me.storage = me.pveSelNode.data.storage; | |
25 | if (!me.storage) { | |
26 | throw "no storage ID specified"; | |
27 | } | |
4a580e60 | 28 | } |
1d8306e4 | 29 | const storage = me.storage; |
4a580e60 | 30 | |
e8b422bc FE |
31 | var content = me.content; |
32 | if (!content) { | |
33 | throw "no content type specified"; | |
34 | } | |
35 | ||
1d8306e4 TL |
36 | const baseurl = `/nodes/${nodename}/storage/${storage}/content`; |
37 | let store = me.store = Ext.create('Ext.data.Store', { | |
4a580e60 | 38 | model: 'pve-storage-content', |
4a580e60 | 39 | proxy: { |
56a353b9 | 40 | type: 'proxmox', |
e8b422bc FE |
41 | url: '/api2/json' + baseurl, |
42 | extraParams: { | |
43 | content: content, | |
44 | }, | |
4a580e60 | 45 | }, |
177de3de DC |
46 | sorters: { |
47 | property: 'volid', | |
392e3cf1 | 48 | direction: 'ASC', |
1d8306e4 | 49 | }, |
4a580e60 DM |
50 | }); |
51 | ||
dbeddeb3 FE |
52 | if (!me.sm) { |
53 | me.sm = Ext.create('Ext.selection.RowModel', {}); | |
54 | } | |
1d8306e4 | 55 | let sm = me.sm; |
4a580e60 | 56 | |
1d8306e4 | 57 | let reload = () => store.load(); |
4a580e60 | 58 | |
e7ade592 | 59 | Proxmox.Utils.monStoreErrors(me, store); |
4a580e60 | 60 | |
3dd9c5c8 | 61 | let tbar = me.tbar ? [...me.tbar] : []; |
8798c35b | 62 | if (me.useUploadButton) { |
3dd9c5c8 | 63 | tbar.unshift( |
af3c0a92 LS |
64 | { |
65 | xtype: 'button', | |
66 | text: gettext('Upload'), | |
67 | disabled: !me.enableUploadButton, | |
68 | handler: function() { | |
26bfeca1 | 69 | Ext.create('PVE.window.UploadToStorage', { |
af3c0a92 LS |
70 | nodename: nodename, |
71 | storage: storage, | |
f9f45aac | 72 | content: content, |
af3c0a92 LS |
73 | autoShow: true, |
74 | taskDone: () => reload(), | |
75 | }); | |
76 | }, | |
77 | }, | |
78 | { | |
79 | xtype: 'button', | |
80 | text: gettext('Download from URL'), | |
81 | disabled: !me.enableDownloadUrlButton, | |
82 | handler: function() { | |
01366f9e | 83 | Ext.create('PVE.window.DownloadUrlToStorage', { |
af3c0a92 LS |
84 | nodename: nodename, |
85 | storage: storage, | |
86 | content: content, | |
87 | autoShow: true, | |
88 | taskDone: () => reload(), | |
89 | }); | |
90 | }, | |
91 | }, | |
92 | '-', | |
93 | ); | |
8798c35b | 94 | } |
f5e17f15 | 95 | if (!me.useCustomRemoveButton) { |
3dd9c5c8 | 96 | tbar.push({ |
af3c0a92 LS |
97 | xtype: 'proxmoxStdRemoveButton', |
98 | selModel: sm, | |
2b289547 | 99 | enableFn: rec => !rec?.data?.protected, |
af3c0a92 LS |
100 | delay: 5, |
101 | callback: () => reload(), | |
102 | baseurl: baseurl + '/', | |
103 | }); | |
f5e17f15 | 104 | } |
3dd9c5c8 | 105 | tbar.push( |
9ce0c258 | 106 | '->', |
1d8306e4 TL |
107 | gettext('Search') + ':', |
108 | ' ', | |
9ce0c258 FE |
109 | { |
110 | xtype: 'textfield', | |
111 | width: 200, | |
112 | enableKeyEvents: true, | |
5a912de3 | 113 | emptyText: content === 'backup' ? gettext('Name, Format, Notes') : gettext('Name, Format'), |
9ce0c258 | 114 | listeners: { |
c8a71b9e TL |
115 | keyup: { |
116 | buffer: 500, | |
117 | fn: function(field) { | |
5a912de3 | 118 | let needle = field.getValue().toLocaleLowerCase(); |
c8a71b9e TL |
119 | store.clearFilter(true); |
120 | store.filter([ | |
121 | { | |
5a912de3 TL |
122 | filterFn: ({ data }) => |
123 | data.text?.toLocaleLowerCase().includes(needle) || | |
124 | data.notes?.toLocaleLowerCase().includes(needle), | |
c8a71b9e TL |
125 | }, |
126 | ]); | |
127 | }, | |
128 | }, | |
129 | change: function(field, newValue, oldValue) { | |
130 | if (newValue !== this.originalValue) { | |
131 | this.triggers.clear.setVisible(true); | |
132 | } | |
133 | }, | |
134 | }, | |
135 | triggers: { | |
136 | clear: { | |
137 | cls: 'pmx-clear-trigger', | |
138 | weight: -1, | |
139 | hidden: true, | |
140 | handler: function() { | |
141 | this.triggers.clear.setVisible(false); | |
142 | this.setValue(this.originalValue); | |
143 | store.clearFilter(); | |
144 | }, | |
145 | }, | |
146 | }, | |
147 | }, | |
9ce0c258 FE |
148 | ); |
149 | ||
6ecc7420 | 150 | let availableColumns = { |
7ef0f4c3 FE |
151 | 'name': { |
152 | header: gettext('Name'), | |
153 | flex: 2, | |
154 | sortable: true, | |
155 | renderer: PVE.Utils.render_storage_content, | |
1d8306e4 | 156 | dataIndex: 'text', |
7ef0f4c3 | 157 | }, |
ef402242 DC |
158 | 'notes': { |
159 | header: gettext('Notes'), | |
7ef0f4c3 FE |
160 | flex: 1, |
161 | renderer: Ext.htmlEncode, | |
ef402242 | 162 | dataIndex: 'notes', |
7ef0f4c3 | 163 | }, |
61cf2658 | 164 | 'protected': { |
528c24b5 TL |
165 | header: `<i class="fa fa-shield"></i>`, |
166 | tooltip: gettext('Protected'), | |
167 | width: 30, | |
168 | renderer: v => v ? `<i data-qtip="${gettext('Protected')}" class="fa fa-shield"></i>` : '', | |
bc54c473 | 169 | sorter: (a, b) => (b.data.protected || 0) - (a.data.protected || 0), |
61cf2658 FE |
170 | dataIndex: 'protected', |
171 | }, | |
7ef0f4c3 FE |
172 | 'date': { |
173 | header: gettext('Date'), | |
174 | width: 150, | |
1d8306e4 | 175 | dataIndex: 'vdate', |
7ef0f4c3 FE |
176 | }, |
177 | 'format': { | |
178 | header: gettext('Format'), | |
179 | width: 100, | |
1d8306e4 | 180 | dataIndex: 'format', |
7ef0f4c3 FE |
181 | }, |
182 | 'size': { | |
183 | header: gettext('Size'), | |
184 | width: 100, | |
185 | renderer: Proxmox.Utils.format_size, | |
1d8306e4 | 186 | dataIndex: 'size', |
7ef0f4c3 FE |
187 | }, |
188 | }; | |
189 | ||
c0eadd55 FE |
190 | let showColumns = me.showColumns || ['name', 'date', 'format', 'size']; |
191 | ||
192 | Object.keys(availableColumns).forEach(function(key) { | |
193 | if (!showColumns.includes(key)) { | |
194 | delete availableColumns[key]; | |
195 | } | |
196 | }); | |
197 | ||
ebea3f45 TL |
198 | if (me.extraColumns && typeof me.extraColumns === 'object') { |
199 | Object.assign(availableColumns, me.extraColumns); | |
200 | } | |
6ecc7420 | 201 | const columns = Object.values(availableColumns); |
7ef0f4c3 | 202 | |
9ce0c258 | 203 | Ext.apply(me, { |
1826922d | 204 | store, |
9ce0c258 | 205 | selModel: sm, |
3dd9c5c8 | 206 | tbar, |
1826922d | 207 | columns, |
4a580e60 | 208 | listeners: { |
1d8306e4 | 209 | activate: reload, |
62580ab8 | 210 | itemdblclick: (view, record) => me.itemdblclick(view, record), |
1d8306e4 | 211 | }, |
4a580e60 DM |
212 | }); |
213 | ||
214 | me.callParent(); | |
1d8306e4 | 215 | }, |
4a580e60 | 216 | }, function() { |
4a580e60 DM |
217 | Ext.define('pve-storage-content', { |
218 | extend: 'Ext.data.Model', | |
177de3de DC |
219 | fields: [ |
220 | 'volid', 'content', 'format', 'size', 'used', 'vmid', | |
ef402242 | 221 | 'channel', 'id', 'lun', 'notes', 'verification', |
177de3de DC |
222 | { |
223 | name: 'text', | |
4a580e60 | 224 | convert: function(value, record) { |
86cc7049 DC |
225 | // check for volid, because if you click on a grouping header, |
226 | // it calls convert (but with an empty volid) | |
227 | if (value || record.data.volid === null) { | |
4a580e60 DM |
228 | return value; |
229 | } | |
230 | return PVE.Utils.render_storage_content(value, {}, record); | |
1d8306e4 | 231 | }, |
12d50fcd TL |
232 | }, |
233 | { | |
234 | name: 'vdate', | |
235 | convert: function(value, record) { | |
236 | // check for volid, because if you click on a grouping header, | |
237 | // it calls convert (but with an empty volid) | |
238 | if (value || record.data.volid === null) { | |
239 | return value; | |
240 | } | |
241 | let t = record.data.content; | |
242 | if (t === "backup") { | |
243 | let v = record.data.volid; | |
244 | let match = v.match(/(\d{4}_\d{2}_\d{2})-(\d{2}_\d{2}_\d{2})/); | |
245 | if (match) { | |
a4a86fe9 | 246 | let date = match[1].replace(/_/g, '-'); |
12d50fcd TL |
247 | let time = match[2].replace(/_/g, ':'); |
248 | return date + " " + time; | |
249 | } | |
250 | } | |
a4a86fe9 DM |
251 | if (record.data.ctime) { |
252 | let ctime = new Date(record.data.ctime * 1000); | |
1d8306e4 | 253 | return Ext.Date.format(ctime, 'Y-m-d H:i:s'); |
a4a86fe9 | 254 | } |
12d50fcd | 255 | return ''; |
1d8306e4 | 256 | }, |
12d50fcd | 257 | }, |
4a580e60 | 258 | ], |
1d8306e4 | 259 | idProperty: 'volid', |
4a580e60 | 260 | }); |
4a580e60 | 261 | }); |