pywebexec 1.1.10__py3-none-any.whl → 1.1.12__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.
@@ -139,3 +139,29 @@ input {
139
139
  tr.clickable-row {
140
140
  cursor: pointer;
141
141
  }
142
+ body.dimmed {
143
+ background-color: rgba(0, 0, 0, 0.5);
144
+ pointer-events: none;
145
+ }
146
+ body.dimmed * {
147
+ pointer-events: none;
148
+ }
149
+ .dimmer {
150
+ display: none;
151
+ position: fixed;
152
+ top: 0;
153
+ left: 0;
154
+ width: 100%;
155
+ height: 100%;
156
+ background-color: rgba(0, 0, 0, 0.5);
157
+ z-index: 1000;
158
+ }
159
+ .dimmer-text {
160
+ color: white;
161
+ font-size: 24px;
162
+ text-align: center;
163
+ position: absolute;
164
+ top: 50%;
165
+ left: 50%;
166
+ transform: translate(-50%, -50%);
167
+ }
@@ -5,76 +5,107 @@ document.getElementById('launchForm').addEventListener('submit', async (event) =
5
5
  event.preventDefault();
6
6
  const commandName = document.getElementById('commandName').value;
7
7
  const params = document.getElementById('params').value.split(' ');
8
- const response = await fetch('/run_command', {
9
- method: 'POST',
10
- headers: {
11
- 'Content-Type': 'application/json'
12
- },
13
- body: JSON.stringify({ command: commandName, params: params })
14
- });
15
- const data = await response.json();
16
- fetchCommands();
17
- viewOutput(data.command_id);
8
+ try {
9
+ const response = await fetch('/run_command', {
10
+ method: 'POST',
11
+ headers: {
12
+ 'Content-Type': 'application/json'
13
+ },
14
+ body: JSON.stringify({ command: commandName, params: params })
15
+ });
16
+ if (!response.ok) {
17
+ throw new Error('Failed to launch command');
18
+ }
19
+ const data = await response.json();
20
+ fetchCommands();
21
+ viewOutput(data.command_id);
22
+ } catch (error) {
23
+ console.log('Error running command:', error);
24
+ }
18
25
  });
19
26
 
20
27
  async function fetchCommands() {
21
- const response = await fetch('/commands');
22
- const commands = await response.json();
23
- commands.sort((a, b) => new Date(b.start_time) - new Date(a.start_time));
24
- const commandsTbody = document.getElementById('commands');
25
- commandsTbody.innerHTML = '';
26
- if (!currentCommandId && commands.length) {
27
- currentCommandId = commands[0].command_id;
28
- viewOutput(currentCommandId);
28
+ try {
29
+ const response = await fetch('/commands');
30
+ if (!response.ok) {
31
+ document.getElementById('dimmer').style.display = 'block';
32
+ return;
33
+ }
34
+ const commands = await response.json();
35
+ commands.sort((a, b) => new Date(b.start_time) - new Date(a.start_time));
36
+ const commandsTbody = document.getElementById('commands');
37
+ commandsTbody.innerHTML = '';
38
+ if (!currentCommandId && commands.length) {
39
+ currentCommandId = commands[0].command_id;
40
+ viewOutput(currentCommandId);
41
+ }
42
+ commands.forEach(command => {
43
+ const commandRow = document.createElement('tr');
44
+ commandRow.className = `clickable-row ${command.command_id === currentCommandId ? 'currentcommand' : ''}`;
45
+ commandRow.onclick = () => viewOutput(command.command_id);
46
+ commandRow.innerHTML = `
47
+ <td class="monospace">
48
+ ${navigator.clipboard == undefined ? `${command.command_id}` : `<span class="copy_clip" onclick="copyToClipboard('${command.command_id.slice(0, 8)}', this, event)">${command.command_id.slice(0, 8)}</span>`}
49
+ </td>
50
+ <td><span class="status-icon status-${command.status}"></span>${command.status}</td>
51
+ <td>${formatTime(command.start_time)}</td>
52
+ <td>${command.status === 'running' ? formatDuration(command.start_time, new Date().toISOString()) : formatDuration(command.start_time, command.end_time)}</td>
53
+ <td>${command.exit_code}</td>
54
+ <td>${command.command.replace(/^\.\//, '')}</td>
55
+ <td>
56
+ ${command.status === 'running' ? `<button onclick="stopCommand('${command.command_id}')">Stop</button>` : `<button onclick="relaunchCommand('${command.command_id}')">Run</button>`}
57
+ </td>
58
+ <td class="monospace outcol">${command.last_output_line || ''}</td>
59
+ `;
60
+ commandsTbody.appendChild(commandRow);
61
+ });
62
+ document.getElementById('dimmer').style.display = 'none';
63
+ } catch (error) {
64
+ console.log('Error fetching commands:', error);
29
65
  }
30
- commands.forEach(command => {
31
- const commandRow = document.createElement('tr');
32
- commandRow.className = `clickable-row ${command.command_id === currentCommandId ? 'currentcommand' : ''}`;
33
- commandRow.onclick = () => viewOutput(command.command_id);
34
- commandRow.innerHTML = `
35
- <td class="monospace">
36
- <span class="copy_clip" onclick="copyToClipboard('${command.command_id}', this, event)">${command.command_id.slice(0, 8)}</span>
37
- </td>
38
- <td><span class="status-icon status-${command.status}"></span>${command.status}</td>
39
- <td>${formatTime(command.start_time)}</td>
40
- <td>${command.status === 'running' ? formatDuration(command.start_time, new Date().toISOString()) : formatDuration(command.start_time, command.end_time)}</td>
41
- <td>${command.exit_code}</td>
42
- <td>${command.command.replace(/^\.\//, '')}</td>
43
- <td>
44
- ${command.status === 'running' ? `<button onclick="stopCommand('${command.command_id}')">Stop</button>` : `<button onclick="relaunchCommand('${command.command_id}')">Run</button>`}
45
- </td>
46
- <td class="monospace outcol">${command.last_output_line || ''}</td>
47
- `;
48
- commandsTbody.appendChild(commandRow);
49
- });
50
66
  }
51
67
 
52
68
  async function fetchExecutables() {
53
- const response = await fetch('/executables');
54
- const executables = await response.json();
55
- const commandNameSelect = document.getElementById('commandName');
56
- commandNameSelect.innerHTML = '';
57
- executables.forEach(executable => {
58
- const option = document.createElement('option');
59
- option.value = executable;
60
- option.textContent = executable;
61
- commandNameSelect.appendChild(option);
62
- });
69
+ try {
70
+ const response = await fetch('/executables');
71
+ if (!response.ok) {
72
+ throw new Error('Failed to fetch command status');
73
+ }
74
+ const executables = await response.json();
75
+ const commandNameSelect = document.getElementById('commandName');
76
+ commandNameSelect.innerHTML = '';
77
+ executables.forEach(executable => {
78
+ const option = document.createElement('option');
79
+ option.value = executable;
80
+ option.textContent = executable;
81
+ commandNameSelect.appendChild(option);
82
+ });
83
+ } catch (error) {
84
+ console.log('Error fetching executables:', error);
85
+ alert("Failed to fetch executables");
86
+ }
63
87
  }
64
88
 
65
89
  async function fetchOutput(command_id) {
66
- const outputDiv = document.getElementById('output');
67
- const response = await fetch(`/command_output/${command_id}`);
68
- const data = await response.json();
69
- if (data.error) {
70
- outputDiv.innerHTML = data.error;
71
- clearInterval(outputInterval);
72
- } else {
73
- outputDiv.innerHTML = data.output;
74
- outputDiv.scrollTop = outputDiv.scrollHeight;
75
- if (data.status != 'running') {
90
+ try {
91
+ const outputDiv = document.getElementById('output');
92
+ const response = await fetch(`/command_output/${command_id}`);
93
+ if (!response.ok) {
94
+ return;
95
+ }
96
+ const data = await response.json();
97
+ if (data.error) {
98
+ outputDiv.innerHTML = data.error;
76
99
  clearInterval(outputInterval);
100
+ } else {
101
+ outputDiv.innerHTML = data.output;
102
+ outputDiv.scrollTop = outputDiv.scrollHeight;
103
+ if (data.status != 'running') {
104
+ clearInterval(outputInterval);
105
+ }
77
106
  }
107
+ } catch (error) {
108
+ console.log('Error fetching output:', error);
78
109
  }
79
110
  }
80
111
 
@@ -82,49 +113,75 @@ async function viewOutput(command_id) {
82
113
  adjustOutputHeight();
83
114
  currentCommandId = command_id;
84
115
  clearInterval(outputInterval);
85
- const response = await fetch(`/command_status/${command_id}`);
86
- const data = await response.json();
87
- if (data.status === 'running') {
88
- fetchOutput(command_id);
89
- outputInterval = setInterval(() => fetchOutput(command_id), 1000);
90
- } else {
91
- fetchOutput(command_id);
116
+ try {
117
+ const response = await fetch(`/command_status/${command_id}`);
118
+ if (!response.ok) {
119
+ return;
120
+ }
121
+ const data = await response.json();
122
+ if (data.status === 'running') {
123
+ fetchOutput(command_id);
124
+ outputInterval = setInterval(() => fetchOutput(command_id), 1000);
125
+ } else {
126
+ fetchOutput(command_id);
127
+ }
128
+ fetchCommands(); // Refresh the command list to highlight the current command
129
+ } catch (error) {
130
+ console.log('Error viewing output:', error);
92
131
  }
93
- fetchCommands(); // Refresh the command list to highlight the current command
94
132
  }
95
133
 
96
134
  async function relaunchCommand(command_id) {
97
- const response = await fetch(`/command_status/${command_id}`);
98
- const data = await response.json();
99
- if (data.error) {
100
- alert(data.error);
101
- return;
135
+ try {
136
+ const response = await fetch(`/command_status/${command_id}`);
137
+ if (!response.ok) {
138
+ throw new Error('Failed to fetch command status');
139
+ }
140
+ const data = await response.json();
141
+ if (data.error) {
142
+ alert(data.error);
143
+ return;
144
+ }
145
+ const relaunchResponse = await fetch('/run_command', {
146
+ method: 'POST',
147
+ headers: {
148
+ 'Content-Type': 'application/json'
149
+ },
150
+ body: JSON.stringify({
151
+ command: data.command,
152
+ params: data.params
153
+ })
154
+ });
155
+ if (!relaunchResponse.ok) {
156
+ throw new Error('Failed to relaunch command');
157
+ }
158
+ const relaunchData = await relaunchResponse.json();
159
+ fetchCommands();
160
+ viewOutput(relaunchData.command_id);
161
+ } catch (error) {
162
+ console.log('Error relaunching command:', error);
163
+ alert('Failed to relaunch command. Please try again.');
102
164
  }
103
- const relaunchResponse = await fetch('/run_command', {
104
- method: 'POST',
105
- headers: {
106
- 'Content-Type': 'application/json'
107
- },
108
- body: JSON.stringify({
109
- command: data.command,
110
- params: data.params
111
- })
112
- });
113
- const relaunchData = await relaunchResponse.json();
114
- fetchCommands();
115
- viewOutput(relaunchData.command_id);
116
165
  }
117
166
 
118
167
  async function stopCommand(command_id) {
119
- const response = await fetch(`/stop_command/${command_id}`, {
120
- method: 'POST'
121
- });
122
- const data = await response.json();
123
- if (data.error) {
124
- alert(data.error);
125
- } else {
126
- alert(data.message);
127
- fetchCommands();
168
+ try {
169
+ const response = await fetch(`/stop_command/${command_id}`, {
170
+ method: 'POST'
171
+ });
172
+ if (!response.ok) {
173
+ throw new Error('Failed to stop command');
174
+ }
175
+ const data = await response.json();
176
+ if (data.error) {
177
+ alert(data.error);
178
+ } else {
179
+ alert(data.message);
180
+ fetchCommands();
181
+ }
182
+ } catch (error) {
183
+ console.log('Error stopping command:', error);
184
+ alert('Failed to stop command. Please try again.');
128
185
  }
129
186
  }
130
187
 
@@ -7,6 +7,9 @@
7
7
  <link rel="stylesheet" href="/static/css/style.css">
8
8
  </head>
9
9
  <body>
10
+ <div id="dimmer" class="dimmer">
11
+ <div class="dimmer-text">Server not reachable</div>
12
+ </div>
10
13
  <h2><span class="status-icon title-icon"></span>{{ title }}</h2>
11
14
  <form id="launchForm">
12
15
  <label for="commandName">Command</label>
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.1.10'
16
- __version_tuple__ = version_tuple = (1, 1, 10)
15
+ __version__ = version = '1.1.12'
16
+ __version_tuple__ = version_tuple = (1, 1, 12)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: pywebexec
3
- Version: 1.1.10
3
+ Version: 1.1.12
4
4
  Summary: Simple Python HTTP Exec Server
5
5
  Home-page: https://github.com/joknarf/pywebexec
6
6
  Author: Franck Jouvanceau
@@ -1,7 +1,7 @@
1
1
  pywebexec/__init__.py,sha256=4spIsVaF8RJt8S58AG_wWoORRNkws9Iwqprj27C3ljM,99
2
2
  pywebexec/pywebexec.py,sha256=nXo0K6dBS9zKRUEP1hFyGWpL3BV2sUku3CFeGi0QQ-w,21479
3
- pywebexec/version.py,sha256=fMp4T8goXmzg6VCL_DrRlmTWnEa-W8ZBSuhlUd7orjI,413
4
- pywebexec/static/css/style.css,sha256=rYpzhBftpZ9pw_FTZFwcAnGC9-EhVOOSy6w56Ybe-Wk,2902
3
+ pywebexec/version.py,sha256=dXcZMQahMY7EOK75sY27vK2B0WeL9UmI9j4IwQSxd34,413
4
+ pywebexec/static/css/style.css,sha256=BFiRkGhGrNoEmD2M3grfQXwsdI_bJWgB7GPHDoyT7R4,3374
5
5
  pywebexec/static/images/aborted.svg,sha256=_mP43hU5QdRLFZIknBgjx-dIXrHgQG23-QV27ApXK2A,381
6
6
  pywebexec/static/images/copy.svg,sha256=d9OwtGh5GzzZHzYcDrLfNxZYLth1Q64x7bRyYxu4Px0,622
7
7
  pywebexec/static/images/copy_ok.svg,sha256=mEqUVUhSq8xaJK2msQkxRawnz_KwlCZ-tok8QS6hJ3g,451
@@ -9,12 +9,12 @@ pywebexec/static/images/failed.svg,sha256=ADZ7IKrUyOXtqpivnz3VcH0-Wru-I5MOi3OJAk
9
9
  pywebexec/static/images/favicon.svg,sha256=ti80IfuDZwIvQcmJxkOeUaB1iMsiyOPmQmVO-h0y1IU,1126
10
10
  pywebexec/static/images/running.gif,sha256=iYuzQGkMxrakSIwt6gPieKCImGZoSAHmU5MUNZa7cpw,25696
11
11
  pywebexec/static/images/success.svg,sha256=PJDcCSTevJh7rkfSFLtc7P0pbeh8PVQBS8DaOLQemmc,489
12
- pywebexec/static/js/script.js,sha256=3TGSrREfpBzp37yvTs0uCcs_hxWibEeApzJDvcC2JMY,7152
12
+ pywebexec/static/js/script.js,sha256=9XFHiOqJAfhENy9UwieA8YmFwuqyzBiH0pDCs2x_e-M,9261
13
13
  pywebexec/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
- pywebexec/templates/index.html,sha256=7dFHAmHXGMrK1-M6PIAbMS0bv7Pi5-6vDoyUk3irnQc,1346
15
- pywebexec-1.1.10.dist-info/LICENSE,sha256=gRJf0JPT_wsZJsUGlWPTS8Vypfl9vQ1qjp6sNbKykuA,1064
16
- pywebexec-1.1.10.dist-info/METADATA,sha256=T9ocxAPjMleGfkYgb3pNVhhqKfkRiTV-awLYvBMsq-c,6906
17
- pywebexec-1.1.10.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
18
- pywebexec-1.1.10.dist-info/entry_points.txt,sha256=l52GBkPCXRkmlHfEyoVauyfBdg8o-CAtC8qQpOIjJK0,55
19
- pywebexec-1.1.10.dist-info/top_level.txt,sha256=vHoHyzngrfGdm_nM7Xn_5iLmaCrf10XO1EhldgNLEQ8,10
20
- pywebexec-1.1.10.dist-info/RECORD,,
14
+ pywebexec/templates/index.html,sha256=X0TsF1-fEuanpGPQo0GpCvvE87BWUEkYyrWA7IOu20Q,1454
15
+ pywebexec-1.1.12.dist-info/LICENSE,sha256=gRJf0JPT_wsZJsUGlWPTS8Vypfl9vQ1qjp6sNbKykuA,1064
16
+ pywebexec-1.1.12.dist-info/METADATA,sha256=-G4Xwrr7soD09QUSHiSNReWHh179UTjJ6kB04bVkeDk,6906
17
+ pywebexec-1.1.12.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
18
+ pywebexec-1.1.12.dist-info/entry_points.txt,sha256=l52GBkPCXRkmlHfEyoVauyfBdg8o-CAtC8qQpOIjJK0,55
19
+ pywebexec-1.1.12.dist-info/top_level.txt,sha256=vHoHyzngrfGdm_nM7Xn_5iLmaCrf10XO1EhldgNLEQ8,10
20
+ pywebexec-1.1.12.dist-info/RECORD,,