commands.ut 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  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>
  27. function command_run(ev, id)
  28. {
  29. var field = document.getElementById(id);
  30. var legend = document.getElementById('command-rc-legend');
  31. var output = document.getElementById('command-rc-output');
  32. if (legend && output)
  33. {
  34. output.innerHTML =
  35. '<img src="{{ resource }}/icons/loading.gif" alt="{{ _('Loading') }}" style="vertical-align:middle" /> ' +
  36. _('Waiting for command to complete...')
  37. ;
  38. legend.parentNode.style.display = 'block';
  39. legend.style.display = 'inline';
  40. var options = field ? { query: { args: field.value } } : null;
  41. L.Request.get(L.url('admin/system/commands/run', id), options).then(function(reply) {
  42. var st = reply.json();
  43. if (st.binary)
  44. st.stdout = '[' + _('Binary data not displayed, download instead.') + ']';
  45. output.innerHTML = String.format(
  46. '<pre><strong># %h\n</strong>%h<span style="color:red">%h</span></pre>' +
  47. '<div class="alert-message warning">%h (%h %d)</div>',
  48. st.command, st.stdout, st.stderr,
  49. (st.exitcode == 0) ? _('Command successful') : _('Command failed'),
  50. _('Code:'), st.exitcode);
  51. }).catch(function() {
  52. output.innerHTML = '<span class="error">%h</span>'.format(_('Failed to execute command!'));
  53. }).finally(function() {
  54. legend.style.display = 'none';
  55. location.hash = '#output';
  56. });
  57. }
  58. ev.preventDefault();
  59. }
  60. function command_download(ev, id)
  61. {
  62. var args;
  63. var field = document.getElementById(id);
  64. if (field)
  65. args = encodeURIComponent(field.value);
  66. location.href = L.url('admin/system/commands/download', id) + (args ? '/' + args : '');
  67. ev.preventDefault();
  68. }
  69. function command_link(ev, id)
  70. {
  71. var legend = document.getElementById('command-rc-legend');
  72. var output = document.getElementById('command-rc-output');
  73. var args;
  74. var field = document.getElementById(id);
  75. if (field)
  76. args = encodeURIComponent(field.value);
  77. if (legend && output)
  78. {
  79. var prefix = location.protocol + '//' + location.host + L.url('command') + '/';
  80. var suffix = (args ? '?args=' + args : '');
  81. var link = prefix + id + suffix;
  82. var link_nodownload = prefix + id + "s" + suffix;
  83. legend.style.display = 'none';
  84. output.parentNode.style.display = 'block';
  85. output.innerHTML = String.format(
  86. '<div class="alert-message"><p>%h <a href="%s">%s</a></p><p>%h <a href="%s">%s</a></p></div>',
  87. _('Download execution result'), link, link,
  88. _('Or display result'), link_nodownload, link_nodownload
  89. );
  90. location.hash = '#output';
  91. }
  92. ev.preventDefault();
  93. }
  94. </script>
  95. {%
  96. const commands = [];
  97. uci.foreach('luci', 'command', s => push(commands, s));
  98. -%}
  99. <form method="get" action="{{ entityencode(FULL_REQUEST_URI) }}">
  100. <div class="cbi-map">
  101. <h2 name="content">{{ _('Custom Commands') }}</h2>
  102. {% if (length(commands) == 0): %}
  103. <div class="cbi-section">
  104. <div class="table cbi-section-table">
  105. <div class="tr cbi-section-table-row">
  106. <p>
  107. <em>{{ _('This section contains no values yet') }}</em>
  108. </p>
  109. </div>
  110. </div>
  111. </div>
  112. {% else %}
  113. <div class="commands">
  114. {% for (let command in commands): %}
  115. <div class="commandbox">
  116. <h3>{{ entityencode(command.name) }}</h3>
  117. <p>{{ _('Command:') }} <code>{{ entityencode(command.command) }}</code></p>
  118. {% if (command.param == "1"): %}
  119. <p>{{ _('Arguments:') }} <input type="text" id="{{ command['.name'] }}" /></p>
  120. {% endif %}
  121. <div>
  122. <button class="cbi-button cbi-button-apply" onclick="command_run(event, '{{ command['.name'] }}')">{{ _('Run') }}</button>
  123. <button class="cbi-button cbi-button-download" onclick="command_download(event, '{{ command['.name'] }}')">{{ _('Download') }}</button>
  124. {% if (command.public == "1"): %}
  125. <button class="cbi-button cbi-button-link" onclick="command_link(event, '{{ command['.name'] }}')">{{ _('Link') }}</button>
  126. {% endif %}
  127. </div>
  128. </div>
  129. {% endfor %}
  130. <a name="output"></a>
  131. </div>
  132. {% endif %}
  133. </div>
  134. <fieldset class="cbi-section" style="display:none">
  135. <legend id="command-rc-legend">{{ _('Collecting data...') }}</legend>
  136. <span id="command-rc-output"></span>
  137. </fieldset>
  138. </form>
  139. {% include('footer') %}