9f208d3255dd1cd1e7f096d3f21ed22512a614bf
[project/luci2/ui.git] / luci2 / htdocs / luci2 / view / system.software.js
1 L.ui.view.extend({
2 updateDiskSpace: function()
3 {
4 return L.system.getDiskInfo().then(function(info) {
5 $('#package_space').empty().append(
6 new L.ui.progress({
7 value: info.root.used / 1024,
8 max: info.root.total / 1024,
9 format: '%d ' + L.tr('kB') + ' / %d ' + L.tr('kB') + ' ' + L.trc('Used disk space', 'used') + ' (%d%%)'
10 }).render());
11 });
12 },
13
14 installRemovePackage: function(pkgname, installed)
15 {
16 var dspname = pkgname.replace(/^.+\//, '');
17 var action = installed ? L.opkg.removePackage : L.opkg.installPackage;
18 var title = (installed ? L.tr('Removing package "%s" …') : L.tr('Installing package "%s" …')).format(dspname);
19 var confirm = (installed ? L.tr('Really remove package "%h" ?') : L.tr('Really install package "%h" ?')).format(dspname);
20
21 var self = this;
22
23 L.ui.dialog(title, confirm, {
24 style: 'confirm',
25 confirm: function() {
26 L.ui.dialog(title, L.tr('Waiting for package manager …'), { style: 'wait' });
27
28 action(pkgname).then(function(res) {
29 self.fetchInstalledList().then(function() { return self.fetchPackageList(); }).then(function() {
30 var output = [ ];
31
32 if (res.stdout)
33 output.push($('<pre />').text(res.stdout));
34
35 if (res.stderr)
36 output.push($('<pre />').addClass('alert-message').text(res.stderr));
37
38 output.push(res.code ? L.tr('Package manager failed with status %d.').format(res.code) : L.tr('Package manager finished successfully.'));
39
40 L.ui.dialog(title, output, { style: 'close' });
41
42 if (name)
43 $('#package_url').val('');
44 });
45 });
46 }
47 });
48 },
49
50 fetchInstalledList: function()
51 {
52 var self = this;
53 return L.opkg.installedPackages(0, 0, '*').then(function(list) {
54 self.installedList = { };
55 for (var i = 0; i < list.length; i++)
56 self.installedList[list[i][0]] = true;
57 });
58 },
59
60 fetchPackageList: function(offset, interactive)
61 {
62 if (interactive)
63 L.ui.loading(true);
64
65 if (typeof(offset) == 'undefined')
66 offset = parseInt($('#package_filter').attr('offset')) || 0;
67
68 var pattern = $('#package_filter').val() || '';
69 var action;
70
71 if (pattern.length)
72 {
73 action = $('#package_which').prop('checked') ? L.opkg.installedPackages : L.opkg.findPackages;
74 pattern = '*' + pattern + '*';
75
76 $('#package_filter').next().attr('src', L.globals.resource + '/icons/cbi/remove.gif');
77 }
78 else
79 {
80 action = $('#package_which').prop('checked') ? L.opkg.installedPackages : L.opkg.listPackages;
81 pattern = '*';
82
83 $('#package_filter').next().attr('src', L.globals.resource + '/icons/cbi/find.gif');
84 }
85
86 $('#package_filter').attr('offset', offset);
87
88 var install_disabled = $('#package_install').attr('disabled');
89 var self = this;
90
91 return action(offset, 100, pattern).then(function(list) {
92 var packageTable = new L.ui.table({
93 placeholder: L.tr('No matching packages found.'),
94 columns: [ {
95 caption: L.trc('Package table header', 'Package'),
96 key: 0
97 }, {
98 caption: L.trc('Package table header', 'Version'),
99 key: 1,
100 format: function(v) {
101 return (v.length > 15 ? v.substring(0, 14) + '…' : v);
102 }
103 }, {
104 caption: L.trc('Package table header', 'Description'),
105 key: 2
106 }, {
107 caption: L.trc('Package table header', 'Installation Status'),
108 key: 0,
109 width: '120px',
110 format: function(v, n) {
111 var inst = self.installedList[list[n][0]];
112 return $('<button />')
113 .css('width', '100%')
114 .attr('disabled', install_disabled)
115 .attr('pkgname', list[n][0])
116 .attr('installed', inst)
117 .addClass('cbi-button')
118 .addClass(inst ? 'cbi-button-apply' : 'cbi-button-reset')
119 .text(inst ? L.trc('Package state', 'Installed') : L.trc('Package state', 'Not installed'))
120 .click(function() {
121 self.installRemovePackage(this.getAttribute('pkgname'), this.getAttribute('installed') == 'true');
122 });
123 }
124 } ]
125 });
126
127 packageTable.rows(list);
128 packageTable.insertInto('#package_table');
129
130 if (offset > 0)
131 $('#package_prev')
132 .attr('offset', offset - 100)
133 .attr('disabled', false)
134 .val('« %d - %d'.format(offset - 100 + 1, offset));
135 else
136 $('#package_prev')
137 .attr('disabled', true)
138 .val('« %d - %d'.format(1, Math.min(100, list.total)));
139
140 if ((offset + 100) < list.total)
141 $('#package_next')
142 .attr('offset', offset + 100)
143 .attr('disabled', false)
144 .val('%d - %d »'.format(offset + 100 + 1, Math.min(offset + 200, list.total)));
145 else
146 $('#package_next')
147 .attr('disabled', true)
148 .val('%d - %d »'.format(list.total - (list.total % 100) + 1, list.total));
149
150 if (interactive)
151 L.ui.loading(false);
152 }).then(self.updateDiskSpace);
153 },
154
155 execute: function()
156 {
157 var self = this;
158
159 $('textarea, input.cbi-button-save').attr('disabled', !this.options.acls.software);
160 $('#package_update, #package_url, #package_install').attr('disabled', !this.options.acls.software);
161
162 return $.when(
163 L.opkg.getConfig().then(function(config) {
164 $('textarea')
165 .attr('rows', (config.match(/\n/g) || [ ]).length + 1)
166 .val(config);
167
168 $('input.cbi-button-save')
169 .click(function() {
170 var data = ($('textarea').val() || '').replace(/\r/g, '').replace(/\n?$/, '\n');
171 L.ui.loading(true);
172 L.opkg.setConfig(data).then(function() {
173 $('textarea')
174 .attr('rows', (data.match(/\n/g) || [ ]).length + 1)
175 .val(data);
176
177 L.ui.loading(false);
178 });
179 });
180 }),
181 self.fetchInstalledList(),
182 self.updateDiskSpace()
183 ).then(function() {
184 $('#tabs').show().tabs();
185
186 $('#package_prev, #package_next').click(function(ev) {
187 if (!this.getAttribute('disabled'))
188 {
189 self.fetchPackageList(parseInt(this.getAttribute('offset')), true);
190 this.blur();
191 }
192 });
193
194 $('#package_filter').next().click(function(ev) {
195 if (this.getAttribute('src').indexOf('remove.gif') > -1)
196 $('#package_filter').val('');
197
198 self.fetchPackageList(0, true);
199 });
200
201 $('#package_filter').keyup(function(ev) {
202 if (ev.which != 13)
203 return true;
204
205 ev.preventDefault();
206 self.fetchPackageList(0, true);
207 return false;
208 });
209
210 $('#package_which').click(function(ev) {
211 this.blur();
212 self.fetchPackageList(0, true);
213 });
214
215 $('#package_url').keyup(function(ev) {
216 if (ev.which != 13)
217 return true;
218
219 ev.preventDefault();
220
221 if (this.value)
222 self.installRemovePackage(this.value, false);
223 });
224
225 $('#package_install').click(function(ev) {
226 var name = $('#package_url').val();
227 if (name)
228 self.installRemovePackage(name, false);
229 });
230
231 $('#package_update').click(function(ev) {
232 L.ui.dialog(L.tr('Updating package lists'), L.tr('Waiting for package manager …'), { style: 'wait' });
233 L.opkg.updateLists().then(function(res) {
234 var output = [ ];
235
236 if (res.stdout)
237 output.push($('<pre />').text(res.stdout));
238
239 if (res.stderr)
240 output.push($('<pre />').addClass('alert-message').text(res.stderr));
241
242 output.push(res.code ? L.tr('Package manager failed with status %d.').format(res.code) : L.tr('Package manager finished successfully.'));
243
244 L.ui.dialog(L.tr('Updating package lists'), output, { style: 'close' });
245 });
246 });
247
248 return self.fetchPackageList(0);
249 });
250 }
251 });