4d7e9c56ea669b321fd3a10babf25c44cf274f3f
[project/luci.git] / modules / luci-base / luasrc / view / cbi / apply_widget.htm
1 <% export("cbi_apply_widget", function(redirect_ok, rollback_token) -%>
2 <style type="text/css">
3 #cbi_apply_overlay {
4 position: absolute;
5 top: 0;
6 left: 0;
7 bottom: 0;
8 right: 0;
9 background: rgba(0, 0, 0, 0.7);
10 display: none;
11 z-index: 20000;
12 }
13
14 #cbi_apply_overlay .alert-message {
15 position: relative;
16 top: 10%;
17 width: 60%;
18 margin: auto;
19 display: flex;
20 flex-wrap: wrap;
21 min-height: 32px;
22 align-items: center;
23 }
24
25 #cbi_apply_overlay .alert-message > h4,
26 #cbi_apply_overlay .alert-message > p,
27 #cbi_apply_overlay .alert-message > div {
28 flex-basis: 100%;
29 }
30
31 #cbi_apply_overlay .alert-message > img {
32 margin-right: 1em;
33 flex-basis: 32px;
34 }
35
36 body.apply-overlay-active {
37 overflow: hidden;
38 height: 100vh;
39 }
40
41 body.apply-overlay-active #cbi_apply_overlay {
42 display: block;
43 }
44 </style>
45
46 <script type="text/javascript" src="<%=resource%>/cbi.js?v=git-18.138.59467-72fe5dd"></script>
47 <script type="text/javascript">//<![CDATA[
48 var xhr = new XHR(),
49 uci_apply_auth = { sid: '<%=luci.dispatcher.context.authsession%>', token: '<%=token%>' },
50 uci_apply_rollback = <%=math.max(luci.config and luci.config.apply and luci.config.apply.rollback or 30, 30)%>,
51 uci_apply_holdoff = <%=math.max(luci.config and luci.config.apply and luci.config.apply.holdoff or 4, 1)%>,
52 uci_apply_timeout = <%=math.max(luci.config and luci.config.apply and luci.config.apply.timeout or 5, 1)%>,
53 uci_apply_display = <%=math.max(luci.config and luci.config.apply and luci.config.apply.display or 1.5, 1)%>,
54 uci_confirm_auth = <% if rollback_token then %>{ token: '<%=rollback_token%>' }<% else %>null<% end %>,
55 was_xhr_poll_running = false;
56
57 function uci_status_message(type, content) {
58 var overlay = document.getElementById('cbi_apply_overlay') || document.body.appendChild(E('<div id="cbi_apply_overlay"><div class="alert-message"></div></div>')),
59 message = overlay.querySelector('.alert-message');
60
61 if (message && type) {
62 if (!message.classList.contains(type)) {
63 message.classList.remove('notice');
64 message.classList.remove('warning');
65 message.classList.add(type);
66 }
67
68 if (content)
69 message.innerHTML = content;
70
71 document.body.classList.add('apply-overlay-active');
72
73 if (!was_xhr_poll_running) {
74 was_xhr_poll_running = XHR.running();
75 XHR.halt();
76 }
77 }
78 else {
79 document.body.classList.remove('apply-overlay-active');
80
81 if (was_xhr_poll_running)
82 XHR.run();
83 }
84 }
85
86 function uci_rollback(checked) {
87 if (checked) {
88 uci_status_message('warning',
89 '<img src="<%=resource%>/icons/loading.gif" alt="" style="vertical-align:middle" /> ' +
90 '<%:Failed to confirm apply within %ds, waiting for rollback…%>'.format(uci_apply_rollback));
91
92 var call = function(r, data, duration) {
93 if (r.status === 204) {
94 uci_status_message('warning',
95 '<h4><%:Configuration has been rolled back!%></h4>' +
96 '<p><%:The device could not be reached within %d seconds after applying the pending changes, which caused the configuration to be rolled back for safety reasons. If you believe that the configuration changes are correct nonetheless, perform an unchecked configuration apply. Alternatively, you can dismiss this warning and edit changes before attempting to apply again, or revert all pending changes to keep the currently working configuration state.%></p>'.format(uci_apply_rollback) +
97 '<div class="right">' +
98 '<input type="button" class="btn" onclick="uci_status_message(false)" value="<%:Dismiss%>" /> ' +
99 '<input type="button" class="btn cbi-button-action important" onclick="uci_revert()" value="<%:Revert changes%>" /> ' +
100 '<input type="button" class="btn cbi-button-negative important" onclick="uci_apply(false)" value="<%:Apply unchecked%>" />' +
101 '</div>');
102
103 return;
104 }
105
106 var delay = isNaN(duration) ? 0 : Math.max(1000 - duration, 0);
107 window.setTimeout(function() {
108 xhr.post('<%=url("admin/uci/confirm")%>', uci_apply_auth, call, uci_apply_timeout * 1000);
109 }, delay);
110 };
111
112 call({ status: 0 });
113 }
114 else {
115 uci_status_message('warning',
116 '<h4><%:Device unreachable!%></h4>' +
117 '<p><%:Could not regain access to the device after applying the configuration changes. You might need to reconnect if you modified network related settings such as the IP address or wireless security credentials.%></p>');
118 }
119 }
120
121 function uci_confirm(checked, deadline) {
122 var tt;
123 var ts = Date.now();
124
125 uci_status_message('notice');
126
127 var call = function(r, data, duration) {
128 if (Date.now() >= deadline) {
129 uci_rollback(checked);
130 return;
131 }
132 else if (r && (r.status === 200 || r.status === 204)) {
133 var indicator = document.querySelector('.uci_change_indicator');
134 if (indicator) indicator.style.display = 'none';
135
136 uci_status_message('notice', '<%:Configuration has been applied.%>');
137
138 window.clearTimeout(tt);
139 window.setTimeout(function() {
140 <% if redirect_ok then -%>
141 location.href = decodeURIComponent('<%=luci.util.urlencode(redirect_ok)%>');
142 <%- else -%>
143 window.location = window.location.href.split('#')[0];
144 <% end %>
145 }, uci_apply_display * 1000);
146
147 return;
148 }
149
150 var delay = isNaN(duration) ? 0 : Math.max(1000 - duration, 0);
151 window.setTimeout(function() {
152 xhr.post('<%=url("admin/uci/confirm")%>', uci_confirm_auth, call, uci_apply_timeout * 1000);
153 }, delay);
154 };
155
156 var tick = function() {
157 var now = Date.now();
158
159 uci_status_message('notice',
160 '<img src="<%=resource%>/icons/loading.gif" alt="" style="vertical-align:middle" /> ' +
161 '<%:Waiting for configuration to get applied… %ds%>'.format(Math.max(Math.floor((deadline - Date.now()) / 1000), 0)));
162
163 if (now >= deadline)
164 return;
165
166 tt = window.setTimeout(tick, 1000 - (now - ts));
167 ts = now;
168 };
169
170 tick();
171
172 /* wait a few seconds for the settings to become effective */
173 window.setTimeout(call, Math.max(uci_apply_holdoff * 1000 - ((ts + uci_apply_rollback * 1000) - deadline), 1));
174 }
175
176 function uci_apply(checked) {
177 uci_status_message('notice',
178 '<img src="<%=resource%>/icons/loading.gif" alt="" style="vertical-align:middle" /> ' +
179 '<%:Starting configuration apply…%>');
180
181 xhr.post('<%=url("admin/uci")%>/' + (checked ? 'apply_rollback' : 'apply_unchecked'), uci_apply_auth, function(r, tok) {
182 if (r.status === (checked ? 200 : 204)) {
183 if (checked && tok !== null && typeof(tok) === 'object' && typeof(tok.token) === 'string')
184 uci_confirm_auth = tok;
185
186 uci_confirm(checked, Date.now() + uci_apply_rollback * 1000);
187 }
188 else if (checked && r.status === 204) {
189 uci_status_message('notice', '<%:There are no changes to apply.%>');
190 window.setTimeout(function() {
191 <% if redirect_ok then -%>
192 location.href = decodeURIComponent('<%=luci.util.urlencode(redirect_ok)%>');
193 <%- else -%>
194 uci_status_message(false);
195 <%- end %>
196 }, uci_apply_display * 1000);
197 }
198 else {
199 uci_status_message('warning', '<%_Apply request failed with status <code>%h</code>%>'.format(r.responseText || r.statusText || r.status));
200 window.setTimeout(function() { uci_status_message(false); }, uci_apply_display * 1000);
201 }
202 });
203 }
204
205 function uci_revert() {
206 uci_status_message('notice',
207 '<img src="<%=resource%>/icons/loading.gif" alt="" style="vertical-align:middle" /> ' +
208 '<%:Reverting configuration…%>');
209
210 xhr.post('<%=url("admin/uci/revert")%>', uci_apply_auth, function(r) {
211 if (r.status === 200) {
212 uci_status_message('notice', '<%:Changes have been reverted.%>');
213 window.setTimeout(function() {
214 <% if redirect_ok then -%>
215 location.href = decodeURIComponent('<%=luci.util.urlencode(redirect_ok)%>');
216 <%- else -%>
217 window.location = window.location.href.split('#')[0];
218 <%- end %>
219 }, uci_apply_display * 1000);
220 }
221 else {
222 uci_status_message('warning', '<%_Revert request failed with status <code>%h</code>%>'.format(r.statusText || r.status));
223 window.setTimeout(function() { uci_status_message(false); }, uci_apply_display * 1000);
224 }
225 });
226 }
227 //]]></script>
228 <%- end) %>