commands.ut 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. {#
  2. Copyright 2012-2022 Jo-Philipp Wich <jo@mein.io>
  3. Licensed to the public under the Apache License 2.0.
  4. -#}
  5. {%
  6. include('header', { css: `
  7. .commands {
  8. display: flex;
  9. flex-wrap: wrap;
  10. }
  11. .commandbox {
  12. flex: 0 0 30%;
  13. margin: .5em;
  14. display: flex;
  15. flex-direction: column;
  16. }
  17. .commandbox > p,
  18. .commandbox > p > * {
  19. display: block;
  20. }
  21. .commandbox div {
  22. margin-top: auto;
  23. }
  24. ` });
  25. -%}
  26. <script type="text/javascript">//<![CDATA[
  27. var stxhr = new XHR();
  28. function command_run(ev, id)
  29. {
  30. var args;
  31. var field = document.getElementById(id);
  32. if (field)
  33. args = encodeURIComponent(field.value);
  34. var legend = document.getElementById('command-rc-legend');
  35. var output = document.getElementById('command-rc-output');
  36. if (legend && output)
  37. {
  38. output.innerHTML =
  39. '<img src="{{ resource }}/icons/loading.gif" alt="{{ _('Loading') }}" style="vertical-align:middle" /> ' +
  40. '{{ _('Waiting for command to complete...') }}'
  41. ;
  42. legend.parentNode.style.display = 'block';
  43. legend.style.display = 'inline';
  44. stxhr.get('{{ dispatcher.build_url('admin/system/commands/run') }}/' + id + (args ? '?args=' + args : ''), null,
  45. function(x, st)
  46. {
  47. if (st)
  48. {
  49. if (st.binary)
  50. st.stdout = '[{{ _('Binary data not displayed, download instead.') }}]';
  51. legend.style.display = 'none';
  52. output.innerHTML = String.format(
  53. '<pre><strong># %h\n</strong>%h<span style="color:red">%h</span></pre>' +
  54. '<div class="alert-message warning">%s ({{ _('Code:') }} %d)</div>',
  55. st.command, st.stdout, st.stderr,
  56. (st.exitcode == 0) ? '{{ _('Command successful') }}' : '{{ _('Command failed') }}',
  57. st.exitcode);
  58. }
  59. else
  60. {
  61. legend.style.display = 'none';
  62. output.innerHTML = '<span class="error">{{ _('Failed to execute command!') }}</span>';
  63. }
  64. location.hash = '#output';
  65. }
  66. );
  67. }
  68. ev.preventDefault();
  69. }
  70. function command_download(ev, id)
  71. {
  72. var args;
  73. var field = document.getElementById(id);
  74. if (field)
  75. args = encodeURIComponent(field.value);
  76. location.href = '{{ dispatcher.build_url('admin/system/commands/download') }}/' + id + (args ? '/' + args : '');
  77. ev.preventDefault();
  78. }
  79. function command_link(ev, id)
  80. {
  81. var legend = document.getElementById('command-rc-legend');
  82. var output = document.getElementById('command-rc-output');
  83. var args;
  84. var field = document.getElementById(id);
  85. if (field)
  86. args = encodeURIComponent(field.value);
  87. if (legend && output)
  88. {
  89. var prefix = location.protocol + '//' + location.host + '{{ dispatcher.build_url('command') }}/';
  90. var suffix = (args ? '?args=' + args : '');
  91. var link = prefix + id + suffix;
  92. var link_nodownload = prefix + id + "s" + suffix;
  93. legend.style.display = 'none';
  94. output.parentNode.style.display = 'block';
  95. output.innerHTML = String.format(
  96. '<div class="alert-message"><p>{{ _('Download execution result') }} <a href="%s">%s</a></p><p>{{ _('Or display result') }} <a href="%s">%s</a></p></div>',
  97. link, link, link_nodownload, link_nodownload
  98. );
  99. location.hash = '#output';
  100. }
  101. ev.preventDefault();
  102. }
  103. //]]></script>
  104. {%
  105. const commands = [];
  106. uci.foreach('luci', 'command', s => push(commands, s));
  107. -%}
  108. <form method="get" action="{{ entityencode(FULL_REQUEST_URI) }}">
  109. <div class="cbi-map">
  110. <h2 name="content">{{ _('Custom Commands') }}</h2>
  111. {% if (length(commands) == 0): %}
  112. <div class="cbi-section">
  113. <div class="table cbi-section-table">
  114. <div class="tr cbi-section-table-row">
  115. <p>
  116. <em>{{ _('This section contains no values yet') }}</em>
  117. </p>
  118. </div>
  119. </div>
  120. </div>
  121. {% else %}
  122. <div class="commands">
  123. {% for (let command in commands): %}
  124. <div class="commandbox">
  125. <h3>{{ entityencode(command.name) }}</h3>
  126. <p>{{ _('Command:') }} <code>{{ entityencode(command.command) }}</code></p>
  127. {% if (command.param == "1"): %}
  128. <p>{{ _('Arguments:') }} <input type="text" id="{{ command['.name'] }}" /></p>
  129. {% endif %}
  130. <div>
  131. <button class="cbi-button cbi-button-apply" onclick="command_run(event, '{{ command['.name'] }}')">{{ _('Run') }}</button>
  132. <button class="cbi-button cbi-button-download" onclick="command_download(event, '{{ command['.name'] }}')">{{ _('Download') }}</button>
  133. {% if (command.public == "1"): %}
  134. <button class="cbi-button cbi-button-link" onclick="command_link(event, '{{ command['.name'] }}')">{{ _('Link') }}</button>
  135. {% endif %}
  136. </div>
  137. </div>
  138. {% endfor %}
  139. <a name="output"></a>
  140. </div>
  141. {% endif %}
  142. </div>
  143. <fieldset class="cbi-section" style="display:none">
  144. <legend id="command-rc-legend">{{ _('Collecting data...') }}</legend>
  145. <span id="command-rc-output"></span>
  146. </fieldset>
  147. </form>
  148. {% include('footer') %}