luci-app-lldpd: Fixes and additions
[project/luci.git] / applications / luci-app-lldpd / htdocs / luci-static / resources / lldpd.js
1 /*
2 * Copyright (c) 2018-2020, Tano Systems LLC. All Rights Reserved.
3 * Anton Kikin <a.kikin@tano-systems.com>
4 * Copyright (c) 2023-2024. All Rights Reserved.
5 * Paul Donald <newtwen+github@gmail.com>
6 */
7
8 'use strict';
9 'require ui';
10 'require form';
11 'require network';
12 'require session';
13 'require uci';
14
15 /*
16 * Filter neighbors (-H)
17 *
18 * The filter column means that filtering is enabled
19 * The 1proto column tells that only one protocol will be kept.
20 * The 1neigh column tells that only one neighbor will be kept.
21 *
22 * incoming outgoing
23 * filter 1proto 1neigh filter 1proto 1neigh
24 * 0
25 * 1 x x x x
26 * 2 x x
27 * 3 x x
28 * 4 x x
29 * 5 x
30 * 6 x
31 * 7 x x x x x
32 * 8 x x x
33 * 9 x x x x
34 * 10 x x
35 * 11 x x
36 * 12 x x x x
37 * 13 x x x
38 * 14 x x x x
39 * 15 x x x
40 * 16 x x x x x
41 * 17 x x x x
42 * 18 x x x
43 * 19 x x x
44 */
45
46 const etitle = _('enable filter');
47 const ptitle = _('keep only one protocol');
48 const ntitle = _('keep only one neighbor');
49
50 var cbiFilterSelect = form.Value.extend({
51 __name__: 'CBI.LLDPD.FilterSelect',
52
53 __init__: function() {
54 this.super('__init__', arguments);
55
56 this.selected = null;
57
58 this.filterVal = [
59 [ 0, 0, 0, 0, 0, 0 ],
60 [ 1, 1, 0, 1, 1, 0 ],
61 [ 1, 1, 0, 0, 0, 0 ],
62 [ 0, 0, 0, 1, 1, 0 ],
63 [ 1, 0, 0, 1, 0, 0 ],
64 [ 1, 0, 0, 0, 0, 0 ],
65 [ 0, 0, 0, 1, 0, 0 ],
66 [ 1, 1, 1, 1, 1, 0 ],
67 [ 1, 1, 1, 0, 0, 0 ],
68 [ 1, 0, 1, 1, 1, 0 ],
69 [ 0, 0, 0, 1, 0, 1 ],
70 [ 1, 0, 1, 0, 0, 0 ],
71 [ 1, 0, 1, 1, 0, 1 ],
72 [ 1, 0, 1, 1, 0, 0 ],
73 [ 1, 1, 0, 1, 0, 1 ],
74 [ 1, 1, 0, 1, 0, 0 ],
75 [ 1, 1, 1, 1, 0, 1 ],
76 [ 1, 1, 1, 1, 0, 0 ],
77 [ 1, 0, 0, 1, 0, 1 ],
78 [ 1, 0, 0, 1, 1, 0 ]
79 ];
80 },
81
82 /** @private */
83 handleRowClick: function(section_id, ev) {
84 var row = ev.currentTarget;
85 var tbody = row.parentNode;
86 var selected = row.getAttribute('data-filter');
87 var input = tbody.querySelector('[id="' + this.cbid(section_id) + '-' + selected + '"]');
88
89 this.selected = selected;
90
91 tbody.querySelectorAll('tr').forEach(function(e) {
92 e.classList.remove('lldpd-filter-selected');
93 });
94
95 input.checked = true;
96 row.classList.add('lldpd-filter-selected');
97 },
98
99 formvalue: function(section_id) {
100 return this.selected || this.cfgvalue(section_id);
101 },
102
103 renderFrame: function(section_id, in_table, option_index, nodes) {
104 var tmp = this.description;
105
106 // Prepend description with table legend
107 this.description =
108 '<ul><li>' + 'E &mdash; ' + etitle + '</li>' +
109 '<li>' + 'P &mdash; ' + ptitle + '</li>' +
110 '<li>' + 'N &mdash; ' + ntitle + '</li>' +
111 '</ul>' + this.description;
112
113 var rendered = this.super('renderFrame', arguments);
114
115 // Restore original description
116 this.description = tmp;
117
118 return rendered;
119 },
120
121 renderWidget: function(section_id, option_index, cfgvalue) {
122 //default value is "15" - rows are zero based
123 var selected = parseInt(cfgvalue) || 15;
124
125 var tbody = [];
126
127 var renderFilterVal = L.bind(function(row, col) {
128 return this.filterVal[row][col] ? '&#x2714;' : '';
129 }, this);
130
131 for (var i = 0; i < this.filterVal.length; i++) {
132 tbody.push(E('tr', {
133 'class': ((selected == i) ? 'lldpd-filter-selected' : ''),
134 'click': L.bind(this.handleRowClick, this, section_id),
135 'data-filter': i,
136 }, [
137 E('td', {}, [
138 E('input', {
139 'class': 'cbi-input-radio',
140 'data-update': 'click change',
141 'type': 'radio',
142 'id': this.cbid(section_id) + '-' + i,
143 'name': this.cbid(section_id),
144 'checked': (selected == i) ? '' : null,
145 'value': i
146 })
147 ]),
148 E('td', {}, i),
149 E('td', {'title': etitle}, renderFilterVal(i, 0)),
150 E('td', {'title': ptitle}, renderFilterVal(i, 1)),
151 E('td', {'title': ntitle}, renderFilterVal(i, 2)),
152 E('td', {'title': etitle}, renderFilterVal(i, 3)),
153 E('td', {'title': ptitle}, renderFilterVal(i, 4)),
154 E('td', {'title': ntitle}, renderFilterVal(i, 5))
155 ]));
156 };
157
158 var table = E('table', { 'class': 'lldpd-filter', 'id': this.cbid(section_id) }, [
159 E('thead', {}, [
160 E('tr', {}, [
161 E('th', { 'rowspan': 2 }),
162 E('th', { 'rowspan': 2 }, _('Filter')),
163 E('th', { 'colspan': 3 }, _('Incoming')),
164 E('th', { 'colspan': 3 }, _('Outgoing'))
165 ]),
166 E('tr', {}, [
167 E('th', {}, 'E'),
168 E('th', {}, 'P'),
169 E('th', {}, 'N'),
170 E('th', {}, 'E'),
171 E('th', {}, 'P'),
172 E('th', {}, 'N'),
173 ])
174 ]),
175 E('tbody', {}, tbody)
176 ]);
177
178 return table;
179 },
180 });
181
182 var CBIMultiIOSelect = form.MultiValue.extend({
183 __name__: 'CBI.MultiIOSelect',
184
185 renderWidget: function(section_id, option_index, cfgvalue) {
186 var value = (cfgvalue != null) ? cfgvalue : this.default ? this.default : '',
187 choices = this.transformChoices() ? this.transformChoices() : '';
188
189 var widget = new ui.Dropdown(L.toArray(value), choices, {
190 id: this.cbid(section_id),
191 sort: this.keylist,
192 multiple: true,
193 optional: true,
194 display_items: 5,
195 dropdown_items: -1,
196 create: true,
197 disabled: (this.readonly != null) ? this.readonly : this.map.readonly,
198 validate: L.bind(this.validate, this, section_id),
199 });
200
201 return widget.render();
202 }
203 });
204
205 function init() {
206 return new Promise(function(resolveFn, rejectFn) {
207 var data = session.getLocalData('luci-app-lldpd');
208 if (data !== null) {
209 return resolveFn();
210 }
211
212 data = {};
213
214 return uci.load('luci').then(function() {
215 session.setLocalData('luci-app-lldpd', data);
216 return resolveFn();
217 });
218 });
219 }
220
221 return L.Class.extend({
222 cbiFilterSelect: cbiFilterSelect,
223 CBIMultiIOSelect: CBIMultiIOSelect,
224 init: init,
225 });