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