pywebexec 1.4.6__py3-none-any.whl → 1.4.8__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
pywebexec/pywebexec.py CHANGED
@@ -682,6 +682,10 @@ def list_executables():
682
682
  executables.sort() # Sort the list of executables alphabetically
683
683
  return jsonify(executables)
684
684
 
685
+ @app.route('/popup/<command_id>')
686
+ def popup(command_id):
687
+ return render_template('popup.html', command_id=command_id)
688
+
685
689
  def main():
686
690
  basef = f"{CONFDIR}/pywebexec_{args.listen}:{args.port}"
687
691
  if args.action == "start":
@@ -266,4 +266,16 @@ span {
266
266
  #outputSlider {
267
267
  width: 100%;
268
268
  }
269
+ .popup-button {
270
+ background: none;
271
+ border: none;
272
+ cursor: pointer;
273
+ padding: 0;
274
+ margin-left: 5px;
275
+ vertical-align: middle;
276
+ }
277
+ .popup-button img {
278
+ width: 16px;
279
+ height: 16px;
280
+ }
269
281
 
@@ -0,0 +1 @@
1
+ <svg fill="#000000" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <title>popout</title> <path d="M15.694 13.541l2.666 2.665 5.016-5.017 2.59 2.59 0.004-7.734-7.785-0.046 2.526 2.525-5.017 5.017zM25.926 16.945l-1.92-1.947 0.035 9.007-16.015 0.009 0.016-15.973 8.958-0.040-2-2h-7c-1.104 0-2 0.896-2 2v16c0 1.104 0.896 2 2 2h16c1.104 0 2-0.896 2-2l-0.074-7.056z"></path> </g></svg>
@@ -0,0 +1,133 @@
1
+ let terminal = new Terminal({
2
+ cursorBlink: false,
3
+ cursorInactiveStyle: 'none',
4
+ disableStdin: true,
5
+ convertEol: true,
6
+ fontFamily: 'Consolas NF, monospace, courier-new, courier',
7
+ scrollback: 999999,
8
+ theme: {
9
+ background: '#111412',
10
+ black: '#111412',
11
+ green: '#088a5b',
12
+ blue: "#2760aa",
13
+ red: '#ba1611',
14
+ yellow: "#cf8700",
15
+ magenta: "#4c3d80",
16
+ cyan: "#00a7aa",
17
+ brightBlack: "#243C4F",
18
+ brightBlue: "#5584b1",
19
+ },
20
+ customGlyphs: false,
21
+ rescaleOverlappingGlyphs: true,
22
+ });
23
+
24
+ const fitAddon = new FitAddon.FitAddon();
25
+ terminal.loadAddon(fitAddon);
26
+ terminal.open(document.getElementById('output'));
27
+ fitAddon.fit();
28
+
29
+ let currentCommandId = null;
30
+ let outputInterval = null;
31
+ let nextOutputLink = null;
32
+ let fullOutput = '';
33
+ let outputLength = 0;
34
+ let title = null;
35
+
36
+ function getTokenParam() {
37
+ const urlParams = new URLSearchParams(window.location.search);
38
+ return urlParams.get('token') ? `?token=${urlParams.get('token')}` : '';
39
+ }
40
+ const urlToken = getTokenParam();
41
+
42
+ async function fetchOutput(url) {
43
+ try {
44
+ const response = await fetch(url);
45
+ if (!response.ok) {
46
+ return;
47
+ }
48
+ const data = await response.json();
49
+ if (data.error) {
50
+ terminal.write(data.error);
51
+ clearInterval(outputInterval);
52
+ } else {
53
+ slider = document.getElementById('outputSlider')
54
+ percentage = slider.value;
55
+ fullOutput += data.output;
56
+ if (percentage == 100)
57
+ terminal.write(data.output);
58
+ else {
59
+ percentage = Math.round((outputLength * 100)/fullOutput.length);
60
+ slider.value = percentage;
61
+ document.getElementById('outputPercentage').innerText = `${percentage}%`;
62
+ }
63
+ nextOutputLink = data.links.next;
64
+ if (data.status != 'running') {
65
+ title.innerText = `${data.status} ${title.innerText.split(' ').slice(1).join(' ')}`;
66
+ clearInterval(outputInterval);
67
+ }
68
+ }
69
+ } catch (error) {
70
+ console.log('Error fetching output:', error);
71
+ }
72
+ }
73
+
74
+ async function viewOutput(command_id) {
75
+ document.getElementById('outputSlider').value = 100;
76
+ adjustOutputHeight();
77
+ currentCommandId = command_id;
78
+ nextOutputLink = `/command_output/${command_id}${urlToken}`;
79
+ clearInterval(outputInterval);
80
+ terminal.clear();
81
+ terminal.reset();
82
+ fullOutput = '';
83
+ try {
84
+ const response = await fetch(`/command_status/${command_id}${urlToken}`);
85
+ if (!response.ok) {
86
+ return;
87
+ }
88
+ const data = await response.json();
89
+ title.innerText = `${data.status} ${data.command} ${data.params.join(' ')}`;
90
+ if (data.command == 'term')
91
+ terminal.options.cursorInactiveStyle = 'outline';
92
+ else
93
+ terminal.options.cursorInactiveStyle = 'none';
94
+ if (data.status === 'running') {
95
+ fetchOutput(nextOutputLink);
96
+ outputInterval = setInterval(() => fetchOutput(nextOutputLink), 1000);
97
+ } else {
98
+ fetchOutput(nextOutputLink);
99
+ }
100
+ } catch (error) {
101
+ console.log('Error viewing output:', error);
102
+ }
103
+ }
104
+
105
+ function adjustOutputHeight() {
106
+ const outputDiv = document.getElementById('output');
107
+ const windowHeight = window.innerHeight;
108
+ const outputTop = outputDiv.getBoundingClientRect().top;
109
+ const maxHeight = windowHeight - outputTop - 60; // Adjusted for slider height
110
+ outputDiv.style.height = `${maxHeight}px`;
111
+ fitAddon.fit();
112
+ }
113
+
114
+ function sliderUpdateOutput() {
115
+ const slider = document.getElementById('outputSlider');
116
+ const percentage = slider.value;
117
+ outputLength = Math.floor((fullOutput.length * percentage) / 100);
118
+ const limitedOutput = fullOutput.slice(0, outputLength);
119
+ terminal.clear();
120
+ terminal.reset();
121
+ terminal.write(limitedOutput);
122
+ document.getElementById('outputPercentage').innerText = `${percentage}%`;
123
+ }
124
+
125
+ document.getElementById('outputSlider').addEventListener('input', sliderUpdateOutput);
126
+
127
+ window.addEventListener('resize', adjustOutputHeight);
128
+ window.addEventListener('load', () => {
129
+ title = document.getElementById('outputTitle');
130
+ const commandId = window.location.pathname.split('/').slice(-1)[0];
131
+ viewOutput(commandId);
132
+ });
133
+
@@ -107,7 +107,12 @@ async function fetchCommands() {
107
107
  <td>
108
108
  ${command.command.startsWith('term') ? '' : command.status === 'running' ? `<button onclick="stopCommand('${command.command_id}', event)">Stop</button>` : `<button onclick="relaunchCommand('${command.command_id}', event)">Run</button>`}
109
109
  </td>
110
- <td class="monospace outcol">${command.last_output_line || ''}</td>
110
+ <td class="monospace outcol">
111
+ <button class="popup-button" onclick="openPopup('${command.command_id}', event)">
112
+ <img src="/static/images/popup.svg" alt="Popup">
113
+ </button>
114
+ ${command.last_output_line || ''}
115
+ </td>
111
116
  `;
112
117
  commandsTbody.appendChild(commandRow);
113
118
  });
@@ -180,6 +185,11 @@ async function viewOutput(command_id) {
180
185
  }
181
186
  }
182
187
 
188
+ async function openPopup(command_id) {
189
+ const popupUrl = `/popup/${command_id}${urlToken}`;
190
+ window.open(popupUrl, '_blank', 'width=1000,height=600');
191
+ }
192
+
183
193
  async function relaunchCommand(command_id, event) {
184
194
  event.stopPropagation();
185
195
  event.stopImmediatePropagation();
@@ -0,0 +1,21 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <link rel="icon" href="/static/images/favicon.svg" type="image/svg+xml">
6
+ <title id="outputTitle">Command Output</title>
7
+ <link rel="stylesheet" href="/static/css/style.css">
8
+ <link rel="stylesheet" href="/static/css/xterm.css">
9
+ </head>
10
+ <body>
11
+ <div id="output" class="output"></div>
12
+ <div class="slider-container">
13
+ <input type="range" id="outputSlider" min="0" max="100" value="100">
14
+ <label for="outputSlider"><span id="outputPercentage">100%</span></label>
15
+ </div>
16
+ <script src="/static/js/xterm/ansi_up.min.js"></script>
17
+ <script src="/static/js/xterm/xterm.js"></script>
18
+ <script src="/static/js/xterm/xterm-addon-fit.js"></script>
19
+ <script type="text/javascript" src="/static/js/popup.js"></script>
20
+ </body>
21
+ </html>
pywebexec/version.py CHANGED
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '1.4.6'
16
- __version_tuple__ = version_tuple = (1, 4, 6)
15
+ __version__ = version = '1.4.8'
16
+ __version_tuple__ = version_tuple = (1, 4, 8)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: pywebexec
3
- Version: 1.4.6
3
+ Version: 1.4.8
4
4
  Summary: Simple Python HTTP Exec Server
5
5
  Home-page: https://github.com/joknarf/pywebexec
6
6
  Author: Franck Jouvanceau
@@ -1,8 +1,8 @@
1
1
  pywebexec/__init__.py,sha256=4spIsVaF8RJt8S58AG_wWoORRNkws9Iwqprj27C3ljM,99
2
- pywebexec/pywebexec.py,sha256=w5XUxh9rJqbVO4Um9fJb4DcBd-VoOGc6cNXBjPVPkm8,26003
3
- pywebexec/version.py,sha256=HFQuEZSl62eJNTO3Swl0voif7bfUlhX7pVxUC5X9W7g,411
2
+ pywebexec/pywebexec.py,sha256=wediupUiLmpCaER3b_-07QitIiTimgmEBBxFLGT6-DQ,26125
3
+ pywebexec/version.py,sha256=5V0g1zXAYqZG41mH-4FajHcVE05C9vUQm3ybra2NhKU,411
4
4
  pywebexec/static/css/Consolas NF.ttf,sha256=DJEOzF0eqZ-kxu3Gs_VE8X0NJqiobBzmxWDGpdgGRxI,1313900
5
- pywebexec/static/css/style.css,sha256=b02WQoXwVm00JpedEslvCHjr35txo2Bfjz3Iboco9U8,5500
5
+ pywebexec/static/css/style.css,sha256=sDBhZ-csW5THIKfTDsHqxCSg6rIJ91Oh15sjw_HjJo4,5702
6
6
  pywebexec/static/css/xterm.css,sha256=gy8_LGA7Q61DUf8ElwFQzHqHMBQnbbEmpgZcbdgeSHI,5383
7
7
  pywebexec/static/images/aborted.svg,sha256=_mP43hU5QdRLFZIknBgjx-dIXrHgQG23-QV27ApXK2A,381
8
8
  pywebexec/static/images/copy.svg,sha256=d9OwtGh5GzzZHzYcDrLfNxZYLth1Q64x7bRyYxu4Px0,622
@@ -10,19 +10,22 @@ pywebexec/static/images/copy_ok.svg,sha256=mEqUVUhSq8xaJK2msQkxRawnz_KwlCZ-tok8Q
10
10
  pywebexec/static/images/down-arrow.svg,sha256=4TclEmntMvKk_F_ADXgTpGtviYo826EDmmZiGE7HQBI,121
11
11
  pywebexec/static/images/failed.svg,sha256=ADZ7IKrUyOXtqpivnz3VcH0-Wru-I5MOi3OJAkI3hxk,1439
12
12
  pywebexec/static/images/favicon.svg,sha256=9gSN5Oak1zTWhTCyutlupPBKUxcbdoVt7dvhk8xvEug,1224
13
+ pywebexec/static/images/popup.svg,sha256=0Bl9A_v5cBsMPn6FnOlVWlAQKgd2zqiWQbhjcL9BDzI,559
13
14
  pywebexec/static/images/running.gif,sha256=iYuzQGkMxrakSIwt6gPieKCImGZoSAHmU5MUNZa7cpw,25696
14
15
  pywebexec/static/images/success.svg,sha256=PJDcCSTevJh7rkfSFLtc7P0pbeh8PVQBS8DaOLQemmc,489
15
16
  pywebexec/static/js/commands.js,sha256=8JDb3Q55EJOYf2Q9Uy6qEuqAnn1oGjM0RndgQ4aOjqo,7725
16
- pywebexec/static/js/script.js,sha256=_Z1P65x-s_heHMwXbVpPHJHqfQKcIZavVhRej6i3DIs,11570
17
+ pywebexec/static/js/popup.js,sha256=n5JaFwuoiBkYQJGOIva__qVY7eQBNQ9vHEr0lIKHTY4,4399
18
+ pywebexec/static/js/script.js,sha256=B7_rpQiiwgKpqtAprZx0RcSYjwPvd4SRbvgyF9dNzP0,11973
17
19
  pywebexec/static/js/xterm/LICENSE,sha256=EU1P4eXTull-_T9I80VuwnJXubB-zLzUl3xpEYj2T1M,1083
18
20
  pywebexec/static/js/xterm/ansi_up.min.js,sha256=KNGV0vEr30hNqKQimTAvGVy-icD5A1JqMQTtvYtKR2Y,13203
19
21
  pywebexec/static/js/xterm/xterm-addon-fit.js,sha256=Pprm9pZe4SadVXS5Bc8b9VnC9Ex4QlWwA0pxOH53Gck,1460
20
22
  pywebexec/static/js/xterm/xterm.js,sha256=Bzka76jZwEhVt_LlS0e0qMw7ryGa1p5qfxFyeohphBo,283371
21
23
  pywebexec/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
24
  pywebexec/templates/index.html,sha256=DYtT555wSNhnFtzzHhPMWJireynCJNnAuTytpoORQeE,2321
23
- pywebexec-1.4.6.dist-info/LICENSE,sha256=gRJf0JPT_wsZJsUGlWPTS8Vypfl9vQ1qjp6sNbKykuA,1064
24
- pywebexec-1.4.6.dist-info/METADATA,sha256=qEVPHe_lSiRjwa3YnaLm7ycdCjpUtdOrDL3v1WRxsS0,7399
25
- pywebexec-1.4.6.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
26
- pywebexec-1.4.6.dist-info/entry_points.txt,sha256=l52GBkPCXRkmlHfEyoVauyfBdg8o-CAtC8qQpOIjJK0,55
27
- pywebexec-1.4.6.dist-info/top_level.txt,sha256=vHoHyzngrfGdm_nM7Xn_5iLmaCrf10XO1EhldgNLEQ8,10
28
- pywebexec-1.4.6.dist-info/RECORD,,
25
+ pywebexec/templates/popup.html,sha256=6kmZKb0tGJ7jsr9DqDEriSMlbkW-PJTtCiUE9U5_FOE,837
26
+ pywebexec-1.4.8.dist-info/LICENSE,sha256=gRJf0JPT_wsZJsUGlWPTS8Vypfl9vQ1qjp6sNbKykuA,1064
27
+ pywebexec-1.4.8.dist-info/METADATA,sha256=1yv4C31GoevftBY7JMF3wp14lHRZmkCg4PVZoXjjgx8,7399
28
+ pywebexec-1.4.8.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
29
+ pywebexec-1.4.8.dist-info/entry_points.txt,sha256=l52GBkPCXRkmlHfEyoVauyfBdg8o-CAtC8qQpOIjJK0,55
30
+ pywebexec-1.4.8.dist-info/top_level.txt,sha256=vHoHyzngrfGdm_nM7Xn_5iLmaCrf10XO1EhldgNLEQ8,10
31
+ pywebexec-1.4.8.dist-info/RECORD,,