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.
- pywebexec/static/css/style.css +26 -0
- pywebexec/static/js/script.js +150 -93
- pywebexec/templates/index.html +3 -0
- pywebexec/version.py +2 -2
- {pywebexec-1.1.10.dist-info → pywebexec-1.1.12.dist-info}/METADATA +1 -1
- {pywebexec-1.1.10.dist-info → pywebexec-1.1.12.dist-info}/RECORD +10 -10
- {pywebexec-1.1.10.dist-info → pywebexec-1.1.12.dist-info}/LICENSE +0 -0
- {pywebexec-1.1.10.dist-info → pywebexec-1.1.12.dist-info}/WHEEL +0 -0
- {pywebexec-1.1.10.dist-info → pywebexec-1.1.12.dist-info}/entry_points.txt +0 -0
- {pywebexec-1.1.10.dist-info → pywebexec-1.1.12.dist-info}/top_level.txt +0 -0
pywebexec/static/css/style.css
CHANGED
|
@@ -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
|
+
}
|
pywebexec/static/js/script.js
CHANGED
|
@@ -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
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
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
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
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
|
|
pywebexec/templates/index.html
CHANGED
|
@@ -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
|
@@ -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=
|
|
4
|
-
pywebexec/static/css/style.css,sha256=
|
|
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=
|
|
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=
|
|
15
|
-
pywebexec-1.1.
|
|
16
|
-
pywebexec-1.1.
|
|
17
|
-
pywebexec-1.1.
|
|
18
|
-
pywebexec-1.1.
|
|
19
|
-
pywebexec-1.1.
|
|
20
|
-
pywebexec-1.1.
|
|
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,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|