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