pywebexec 2.1.18__tar.gz → 2.2.0__tar.gz

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.
Files changed (84) hide show
  1. {pywebexec-2.1.18/pywebexec.egg-info → pywebexec-2.2.0}/PKG-INFO +1 -1
  2. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/pywebexec.py +23 -22
  3. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/css/markdown.css +1 -1
  4. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/css/style.css +1 -0
  5. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/js/executables.js +1 -1
  6. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/js/popup.js +24 -8
  7. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/js/schemaform.js +16 -8
  8. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/js/script.js +23 -6
  9. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/js/swagger-form.js +36 -18
  10. pywebexec-2.2.0/pywebexec/swagger.yaml +278 -0
  11. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/version.py +2 -2
  12. {pywebexec-2.1.18 → pywebexec-2.2.0/pywebexec.egg-info}/PKG-INFO +1 -1
  13. pywebexec-2.1.18/pywebexec/swagger.yaml +0 -258
  14. {pywebexec-2.1.18 → pywebexec-2.2.0}/.github/workflows/python-publish.yml +0 -0
  15. {pywebexec-2.1.18 → pywebexec-2.2.0}/.gitignore +0 -0
  16. {pywebexec-2.1.18 → pywebexec-2.2.0}/LICENSE +0 -0
  17. {pywebexec-2.1.18 → pywebexec-2.2.0}/README.md +0 -0
  18. {pywebexec-2.1.18 → pywebexec-2.2.0}/pyproject.toml +0 -0
  19. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/__init__.py +0 -0
  20. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/host_ip.py +0 -0
  21. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/css/form.css +0 -0
  22. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/css/swagger-ui.css +0 -0
  23. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/css/swagger-ui.css.map +0 -0
  24. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/css/xterm.css +0 -0
  25. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/fonts/CommitMonoNerdFontMono-Regular.ttf +0 -0
  26. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/fonts/LICENSE +0 -0
  27. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/fonts/glyphicons-halflings-regular.eot +0 -0
  28. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/fonts/glyphicons-halflings-regular.svg +0 -0
  29. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/fonts/glyphicons-halflings-regular.ttf +0 -0
  30. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/fonts/glyphicons-halflings-regular.woff +0 -0
  31. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/fonts/glyphicons-halflings-regular.woff2 +0 -0
  32. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/images/aborted.svg +0 -0
  33. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/images/copy.svg +0 -0
  34. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/images/copy_ok.svg +0 -0
  35. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/images/down-arrow.svg +0 -0
  36. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/images/failed.svg +0 -0
  37. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/images/favicon.svg +0 -0
  38. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/images/fit-tty.svg +0 -0
  39. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/images/fit-win.svg +0 -0
  40. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/images/font-decrease.svg +0 -0
  41. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/images/font-increase.svg +0 -0
  42. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/images/norun.svg +0 -0
  43. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/images/pause.svg +0 -0
  44. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/images/popup.svg +0 -0
  45. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/images/resume.svg +0 -0
  46. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/images/running.svg +0 -0
  47. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/images/success.svg +0 -0
  48. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/images/swagger-ui.svg +0 -0
  49. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/js/js-yaml/LICENSE +0 -0
  50. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/js/js-yaml/js-yaml.min.js +0 -0
  51. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/js/marked/LICENSE.md +0 -0
  52. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/js/marked/marked.min.js +0 -0
  53. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/js/swagger-ui/LICENSE +0 -0
  54. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/js/swagger-ui/swagger-ui-bundle.js +0 -0
  55. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/js/swagger-ui/swagger-ui-standalone-preset.js +0 -0
  56. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/js/xterm/LICENSE +0 -0
  57. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/js/xterm/addon-canvas.js +0 -0
  58. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/js/xterm/addon-canvas.js.map +0 -0
  59. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/js/xterm/addon-fit.js +0 -0
  60. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/js/xterm/addon-fit.js.map +0 -0
  61. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/js/xterm/addon-unicode-graphemes.js +0 -0
  62. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/js/xterm/addon-unicode-graphemes.js.map +0 -0
  63. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/js/xterm/addon-unicode11.js +0 -0
  64. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/js/xterm/addon-unicode11.js.map +0 -0
  65. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/js/xterm/xterm.js +0 -0
  66. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/js/xterm/xterm.js.map +0 -0
  67. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/jsonform/LICENSE +0 -0
  68. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/jsonform/deps/README.md +0 -0
  69. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/jsonform/deps/img/glyphicons-halflings.png +0 -0
  70. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/jsonform/deps/jquery.min.js +0 -0
  71. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/jsonform/deps/jsv.js +0 -0
  72. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/jsonform/deps/underscore.js +0 -0
  73. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/static/jsonform/lib/jsonform.js +0 -0
  74. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/templates/__init__.py +0 -0
  75. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/templates/index.html +0 -0
  76. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/templates/popup.html +0 -0
  77. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec/templates/swagger_ui.html +0 -0
  78. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec.egg-info/SOURCES.txt +0 -0
  79. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec.egg-info/dependency_links.txt +0 -0
  80. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec.egg-info/entry_points.txt +0 -0
  81. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec.egg-info/requires.txt +0 -0
  82. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexec.egg-info/top_level.txt +0 -0
  83. {pywebexec-2.1.18 → pywebexec-2.2.0}/pywebexecdev +0 -0
  84. {pywebexec-2.1.18 → pywebexec-2.2.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: pywebexec
3
- Version: 2.1.18
3
+ Version: 2.2.0
4
4
  Summary: Simple Python HTTP Exec Server
5
5
  Home-page: https://github.com/joknarf/pywebexec
6
6
  Author: Franck Jouvanceau
@@ -1038,15 +1038,12 @@ def swagger_yaml():
1038
1038
  swagger_spec = yaml.safe_load(swagger_spec_str)
1039
1039
  # Update existing POST /commands enum if present
1040
1040
  executables = get_executables()
1041
- post_cmd = swagger_spec.get('paths', {}).get('/commands', {}).get('post')
1042
- if post_cmd:
1043
- params_list = post_cmd.get('parameters', [])
1044
- for param in params_list:
1045
- if param.get('in') == 'body' and 'schema' in param:
1046
- props = param['schema'].get('properties', {})
1047
- if 'command' in props:
1048
- props['command']['enum'] = [e['command'] for e in executables]
1049
- # Add dynamic paths for each
1041
+ post_cmd = swagger_spec.get('paths', {}).get('/commands', {}).get('post', {})
1042
+ if post_cmd and 'requestBody' in post_cmd:
1043
+ schema = post_cmd['requestBody'].get('content', {}).get('application/json', {}).get('schema', {})
1044
+ if 'properties' in schema and 'command' in schema['properties']:
1045
+ schema['properties']['command']['enum'] = [e['command'] for e in executables]
1046
+
1050
1047
  # Add dynamic paths for each executable:
1051
1048
  for exe in executables:
1052
1049
  dynamic_path = "/commands/" + exe["command"]
@@ -1065,28 +1062,32 @@ def swagger_yaml():
1065
1062
  "parallel": {"type": "integer", "description": 'nb parallel jobs', "default": 1, "required": True, "minimum": 1, "maximum": 100},
1066
1063
  "delay": {"type": "number", "description": "initial delay in s between jobs", "default": 10, "required": True, "minimum": 0, "maximum": 600},
1067
1064
  })
1065
+
1068
1066
  swagger_spec.setdefault("paths", {})[dynamic_path] = {
1069
1067
  "post": {
1070
1068
  "summary": f"Run command {exe['command']}",
1071
1069
  "tags": ["run_commands"],
1072
1070
  "description": f"{exe['help']}",
1073
- "consumes": ["application/json"],
1074
- "produces": ["application/json"],
1075
- "parameters": [
1076
- {
1077
- "in": "body",
1078
- "name": "requestBody",
1079
- "schema": cmd_schema
1071
+ "requestBody": {
1072
+ "required": True,
1073
+ "content": {
1074
+ "application/json": {
1075
+ "schema": cmd_schema
1076
+ }
1080
1077
  }
1081
- ],
1078
+ },
1082
1079
  "responses": {
1083
1080
  "200": {
1084
1081
  "description": "Command started",
1085
- "schema": {
1086
- "type": "object",
1087
- "properties": {
1088
- "message": {"type": "string"},
1089
- "command_id": {"type": "string"}
1082
+ "content": {
1083
+ "application/json": {
1084
+ "schema": {
1085
+ "type": "object",
1086
+ "properties": {
1087
+ "message": {"type": "string"},
1088
+ "command_id": {"type": "string"}
1089
+ }
1090
+ }
1090
1091
  }
1091
1092
  }
1092
1093
  }
@@ -1,5 +1,5 @@
1
1
 
2
- .markdown, .swagger-ui .markdown {
2
+ .markdown, .swagger-ui .markdown, .swagger-ui .renderedMarkdown {
3
3
  /* background-color: #e0e0ff; */
4
4
  border: 1px solid #ccc;
5
5
  padding: 0px 8px 8px 8px;
@@ -449,6 +449,7 @@ body.dimmed * {
449
449
  .command-line:hover {
450
450
  text-overflow: unset;
451
451
  max-width: unset;
452
+ white-space: pre;
452
453
  }
453
454
  .nbrunning {
454
455
  display: inline-block;
@@ -301,7 +301,7 @@ paramsInput.addEventListener('focus', () => {
301
301
  console.log('Error running command:', error);
302
302
  }
303
303
  }
304
- }, currentCmd.toString());
304
+ }, currentCmd);
305
305
  setHelpDivPosition();
306
306
  paramsContainer.style.display = 'block';
307
307
  const input1 = schemaFormPW.querySelector('input, select, textarea');
@@ -1,6 +1,6 @@
1
1
  const maxScrollback = 99999;
2
2
  const maxSize = 10485760; // 10MB
3
- let fontSize = 14;
3
+ let fontSize = +localStorage.getItem('popupFontSize') || 14;
4
4
  let terminal = new Terminal({
5
5
  cursorBlink: false,
6
6
  cursorInactiveStyle: 'none',
@@ -75,8 +75,8 @@ let slider = null;
75
75
  let isPaused = false;
76
76
  let cols = 0;
77
77
  let rows = 0;
78
- let fitWindow = false;
79
-
78
+ let fitWindow = localStorage.getItem('popupFitWindow') === 'false' ? false : true;
79
+ console.log(localStorage.getItem('popupFitWindow'));
80
80
  const toggleButton = document.getElementById('toggleFetch');
81
81
  const pausedMessage = document.getElementById('pausedMessage');
82
82
  const toggleFitButton = document.getElementById('toggleFit');
@@ -169,9 +169,13 @@ async function viewOutput(command_id) {
169
169
  }
170
170
  const data = await response.json();
171
171
  const commandInfo = document.getElementById('commandInfo');
172
- const command = `${data.command.replace(/^\.\//, '')} ${data.params.join(' ')}`;
172
+ if (data.command.endsWith('/run-para')) {
173
+ command = `${data.params.join(' ').replace(/^.* -- run .\//, 'batch ')}`;
174
+ } else {
175
+ command = `${data.command.replace(/^\.\//, '')} ${data.params.join(' ')}`;
176
+ }
173
177
  setCommandStatus(data.status);
174
- commandInfo.innerText = command;
178
+ commandInfo.innerHTML = command;
175
179
  commandInfo.setAttribute('title', command);
176
180
  document.title = `${data.command} ${data.params.join(' ')} - [${data.status}]`;
177
181
  if (data.command == 'term')
@@ -232,21 +236,31 @@ function toggleFetchOutput() {
232
236
  }
233
237
  isPaused = !isPaused;
234
238
  }
235
- function toggleFit() {
236
- fitWindow = ! fitWindow;
239
+ function setFitIcon()
240
+ {
241
+ console.log(fitWindow);
237
242
  if (fitWindow) {
243
+ toggleFitButton.classList.remove('fit-window');
238
244
  toggleFitButton.classList.add('fit-tty');
239
245
  toggleFitButton.setAttribute('title', 'terminal fit tty');
240
246
  } else {
241
247
  toggleFitButton.classList.remove('fit-tty');
248
+ toggleFitButton.classList.add('fit-window');
242
249
  toggleFitButton.setAttribute('title', 'terminal fit window');
243
- }
250
+ }
251
+ }
252
+
253
+ function toggleFit() {
254
+ fitWindow = ! fitWindow;
255
+ setFitIcon();
256
+ localStorage.setItem('popupFitWindow', fitWindow);
244
257
  autoFit();
245
258
  viewOutput(currentCommandId);
246
259
  }
247
260
 
248
261
  toggleButton.addEventListener('click', toggleFetchOutput);
249
262
  toggleFitButton.addEventListener('click', toggleFit);
263
+ setFitIcon();
250
264
  window.addEventListener('resize', adjustOutputHeight);
251
265
  window.addEventListener('load', () => {
252
266
  slider = document.getElementById('outputSlider');
@@ -259,11 +273,13 @@ window.addEventListener('load', () => {
259
273
  document.getElementById('decreaseFontSize').addEventListener('click', () => {
260
274
  fontSize = Math.max(8, fontSize - 1);
261
275
  terminal.options.fontSize = fontSize;
276
+ localStorage.setItem('popupFontSize', fontSize);
262
277
  autoFit();
263
278
  });
264
279
 
265
280
  document.getElementById('increaseFontSize').addEventListener('click', () => {
266
281
  fontSize = Math.min(32, fontSize + 1);
267
282
  terminal.options.fontSize = fontSize;
283
+ localStorage.setItem('popupFontSize', fontSize);
268
284
  autoFit();
269
285
  });
@@ -11,7 +11,7 @@ function adjustInputWidth(input) {
11
11
  function formInputHandle() {
12
12
  schemaForm.querySelectorAll('input[type="text"], input[type="number"]').forEach(input => {
13
13
  if (! inputHandlers.includes(input)) {
14
- val = input.value || input.placeholder;
14
+ val = input.placeholder;
15
15
  if (val) {
16
16
  size = Math.max(val.length, 2)
17
17
  if (input.type== 'number') {
@@ -35,16 +35,17 @@ function extractKeysAndPlaceholders(obj, formoptions, prefix = '') {
35
35
  let result = [];
36
36
 
37
37
  for (let key in obj.properties) {
38
+ k = prefix ? `${prefix}.${key}` : key;
38
39
  if (obj.properties[key].type === 'object' && obj.properties[key].properties) {
39
- result = result.concat(extractKeysAndPlaceholders(obj.properties[key], formoptions, prefix ? `${prefix}.${key}` : key));
40
+ result = result.concat(extractKeysAndPlaceholders(obj.properties[key], formoptions, k));
40
41
  } else {
41
- if (formoptions[`${prefix}.${key}`]) {
42
- foptions = formoptions[`${prefix}.${key}`];
42
+ if (formoptions[k]) {
43
+ foptions = formoptions[k];
43
44
  } else {
44
45
  foptions = {};
45
46
  }
46
47
  result.push({
47
- key: prefix ? `${prefix}.${key}` : key,
48
+ key: k,
48
49
  placeholder: obj.properties[key].example || null,
49
50
  ... foptions
50
51
  });
@@ -52,7 +53,7 @@ function extractKeysAndPlaceholders(obj, formoptions, prefix = '') {
52
53
  }
53
54
  return result;
54
55
  }
55
- let schemaValues = {};
56
+
56
57
  function createSchemaForm(form, schema, onSubmit, schemaName) {
57
58
  if (schemaValues[schemaName]) {
58
59
  value = schemaValues[schemaName];
@@ -167,16 +168,22 @@ function createSchemaForm(form, schema, onSubmit, schemaName) {
167
168
  txt.setAttribute("spellcheck", "false");
168
169
  txt.addEventListener("input", () => adjustTxtHeight(txt));
169
170
  });
171
+
170
172
  form[0].addEventListener('input', () => {
171
173
  schemaValues[schemaName] = jsform.root.getFormValues();
172
- // localStorage.setItem('schemaValues', JSON.stringify(schemaValues));
174
+ localStorage.setItem('schemaValues', JSON.stringify(schemaValues));
173
175
  });
174
176
 
175
177
  return jsform;
176
178
  }
177
179
  function adjustTxtHeight(txt) {
180
+ if (txt.value.includes('\n')) {
181
+ delta = 2;
182
+ } else {
183
+ delta = 0;
184
+ }
178
185
  txt.style.height = "0";
179
- txt.style.height = txt.scrollHeight + "px";
186
+ txt.style.height = `${txt.scrollHeight+delta}px`;
180
187
  }
181
188
  async function getSwaggerSpec() {
182
189
  const response = await fetch('/swagger.yaml');
@@ -209,5 +216,6 @@ async function getPostParametersSchema() {
209
216
 
210
217
  let schemaForm;
211
218
  let inputHandlers = [];
219
+ let schemaValues = JSON.parse(localStorage.getItem('schemaValues')) || {};
212
220
 
213
221
 
@@ -7,11 +7,11 @@ let fullOutput = '';
7
7
  let outputLength = 0;
8
8
  const maxScrollback = 99999;
9
9
  const maxSize = 10485760; // 10MB
10
- let fontSize = 14;
10
+ let fontSize = +localStorage.getItem('fontSize') || 14;
11
11
  let isPaused = false;
12
12
  let showRunningOnly = false;
13
13
  let hiddenCommandIds = [];
14
- let fitWindow = false;
14
+ let fitWindow = localStorage.getItem('fitWindow') === 'false' ? false : true;
15
15
  let cols = 0;
16
16
  let rows = 0;
17
17
 
@@ -260,7 +260,12 @@ async function viewOutput(command_id) {
260
260
  }
261
261
  const data = await response.json();
262
262
  const commandInfo = document.getElementById('commandInfo');
263
- const command = `${data.command.replace(/^\.\//, '')} ${data.params.join(' ')}`;
263
+ if (data.command.endsWith('/run-para')) {
264
+ command = `${data.params.join(' ').replace(/^.* -- run .\//, 'batch ')}`;
265
+ } else {
266
+ command = `${data.command.replace(/^\.\//, '')} ${data.params.join(' ')}`;
267
+ }
268
+ console.log(command);
264
269
  setCommandStatus(data.status)
265
270
  commandInfo.innerHTML = command;
266
271
  commandInfo.setAttribute('title', command);
@@ -415,12 +420,14 @@ slider.addEventListener('input', sliderUpdateOutput);
415
420
  document.getElementById('decreaseFontSize').addEventListener('click', () => {
416
421
  fontSize = Math.max(8, fontSize - 1);
417
422
  terminal.options.fontSize = fontSize;
423
+ localStorage.setItem('fontSize', fontSize);
418
424
  autoFit();
419
425
  });
420
426
 
421
427
  document.getElementById('increaseFontSize').addEventListener('click', () => {
422
428
  fontSize = Math.min(32, fontSize + 1);
423
429
  terminal.options.fontSize = fontSize;
430
+ localStorage.setItem('fontSize', fontSize);
424
431
  autoFit();
425
432
  });
426
433
 
@@ -451,21 +458,31 @@ function toggleFetchOutput() {
451
458
  }
452
459
  isPaused = !isPaused;
453
460
  }
454
- function toggleFit() {
455
- fitWindow = ! fitWindow;
461
+
462
+ function setFitIcon()
463
+ {
456
464
  if (fitWindow) {
465
+ toggleFitButton.classList.remove('fit-window');
457
466
  toggleFitButton.classList.add('fit-tty');
458
467
  toggleFitButton.setAttribute('title', 'terminal fit tty');
459
468
  } else {
460
469
  toggleFitButton.classList.remove('fit-tty');
470
+ toggleFitButton.classList.add('fit-window');
461
471
  toggleFitButton.setAttribute('title', 'terminal fit window');
462
- }
472
+ }
473
+ }
474
+
475
+ function toggleFit() {
476
+ fitWindow = ! fitWindow;
477
+ setFitIcon();
478
+ localStorage.setItem('fitWindow', fitWindow);
463
479
  autoFit();
464
480
  viewOutput(currentCommandId);
465
481
  }
466
482
 
467
483
  toggleButton.addEventListener('click', toggleFetchOutput);
468
484
  toggleFitButton.addEventListener('click', toggleFit);
485
+ setFitIcon();
469
486
 
470
487
  document.getElementById('thStatus').addEventListener('click', () => {
471
488
  showRunningOnly = !showRunningOnly;
@@ -26,6 +26,28 @@ function addFormInputListener(textArea, jsform){
26
26
  };
27
27
  }
28
28
 
29
+ async function getPostParametersSchema() {
30
+ const swaggerSpec = await getSwaggerSpec();
31
+ const result = {};
32
+ for (const path in swaggerSpec.paths) {
33
+ const pathItem = swaggerSpec.paths[path];
34
+ if (pathItem.post) {
35
+ const postDef = pathItem.post;
36
+ // Look for requestBody with JSON schema in OpenAPI 3.0
37
+ if (postDef.requestBody && postDef.requestBody.content && postDef.requestBody.content['application/json']) {
38
+ result[path] = postDef.requestBody.content['application/json'].schema;
39
+ } else {
40
+ result[path] = null;
41
+ }
42
+ }
43
+ }
44
+ return result;
45
+ }
46
+ function adjustTxtHeight2(paramtext) {
47
+ paramtext.style.height = "0";
48
+ paramtext.style.height = `${paramtext.scrollHeight+2}px`;
49
+ }
50
+
29
51
  window.onload = function() {
30
52
  ui = SwaggerUIBundle({
31
53
  url: "/swagger.yaml",
@@ -69,29 +91,25 @@ window.onload = function() {
69
91
  const observer = new MutationObserver((mutations) => {
70
92
  mutations.forEach(mutation => {
71
93
  mutation.addedNodes.forEach(node => {
72
- if (node.classList && (node.classList.contains("highlight-code") ||
73
- node.classList.contains("body-param__text"))) {
74
- // Retrieve the data-path attribute from the first opblock-summary-path element
75
- const routePath = $(node).closest('.opblock').find('.opblock-summary-path').first().attr('data-path');
76
- const routePathId = `schemaForm${routePath.replaceAll("/", "_")}`;
77
- const prevForm = node.parentNode.querySelector(`#${routePathId}`)
78
- if (prevForm) {
79
- prevForm.remove();
80
- }
81
- if (node.classList.contains("body-param__text")) {
82
- node.addEventListener("input", (e) => {
83
- e.target.style.height = "0"
84
- e.target.style.height = e.target.scrollHeight + "px";
85
- });
86
- node.style.height = "0"
87
- node.style.height = node.scrollHeight + "px";
94
+ if (node.nodeType === Node.ELEMENT_NODE) {
95
+ const paramtext = node.querySelector(".body-param__text");
96
+ if (paramtext) {
97
+ // Retrieve the data-path attribute from the first opblock-summary-path element
98
+ const routePath = $(node).closest('.opblock').find('.opblock-summary-path').first().attr('data-path');
99
+ const routePathId = `schemaForm${routePath.replaceAll("/", "_")}`;
100
+ const prevForm = paramtext.parentNode.querySelector(`#${routePathId}`)
101
+ if (prevForm) {
102
+ prevForm.remove();
103
+ }
104
+ paramtext.addEventListener("input", () => adjustTxtHeight2(paramtext));
105
+ setTimeout(() => adjustTxtHeight2(paramtext), 100);
88
106
  const form = document.createElement("form");
89
107
  form.id = routePathId;
90
108
  form.classList.add("schema-form");
91
109
  jsform = createSchemaForm($(form), swaggerSchemas[routePath], null, routePath);
92
110
  // form.addEventListener("input", formInput(node, jsform));
93
- form.addEventListener("input", addFormInputListener(node, jsform));
94
- node.parentNode.insertBefore(form, node.nextSibling);
111
+ form.addEventListener("input", addFormInputListener(paramtext, jsform));
112
+ paramtext.parentNode.insertBefore(form, paramtext.nextSibling);
95
113
  item1 = form.querySelector("input, select, textarea");
96
114
  if (item1) {
97
115
  item1.focus();
@@ -0,0 +1,278 @@
1
+ openapi: "3.0.0"
2
+ info:
3
+ title: PyWebExec API
4
+ version: "1.0"
5
+ paths:
6
+ /commands:
7
+ get:
8
+ summary: "List commands status"
9
+ tags:
10
+ - commands
11
+ responses:
12
+ "200":
13
+ description: "List of all commands status"
14
+ content:
15
+ application/json:
16
+ schema:
17
+ type: object
18
+ properties:
19
+ commands:
20
+ type: array
21
+ items:
22
+ type: object
23
+ properties:
24
+ command_id:
25
+ type: string
26
+ command:
27
+ type: string
28
+ status:
29
+ type: string
30
+ start_time:
31
+ type: string
32
+ format: date-time
33
+ end_time:
34
+ type: string
35
+ format: date-time
36
+ exit_code:
37
+ type: integer
38
+ last_output_line:
39
+ type: string
40
+ user:
41
+ type: string
42
+ post:
43
+ summary: "Run a command"
44
+ tags:
45
+ - commands
46
+ requestBody:
47
+ required: true
48
+ content:
49
+ application/json:
50
+ schema:
51
+ type: object
52
+ properties:
53
+ command:
54
+ type: string
55
+ description: "Command to run"
56
+ # Enum will be added dynamically by the APIs
57
+ default: commandName
58
+ required: true
59
+ params:
60
+ type: array
61
+ description: "Command parameters"
62
+ items:
63
+ type: string
64
+ default: []
65
+ rows:
66
+ type: integer
67
+ description: "tty nb rows"
68
+ default: 24
69
+ cols:
70
+ type: integer
71
+ description: "tty nb columns"
72
+ default: 125
73
+ required:
74
+ - command
75
+ responses:
76
+ "200":
77
+ description: "Command started"
78
+ content:
79
+ application/json:
80
+ schema:
81
+ type: object
82
+ properties:
83
+ command_id:
84
+ type: string
85
+ message:
86
+ type: string
87
+
88
+ /commands/{command_id}:
89
+ get:
90
+ summary: "Get command status"
91
+ tags:
92
+ - commands
93
+ parameters:
94
+ - in: path
95
+ name: command_id
96
+ required: true
97
+ schema:
98
+ type: string
99
+ responses:
100
+ "200":
101
+ description: "Command status returned"
102
+ content:
103
+ application/json:
104
+ schema:
105
+ type: object
106
+ properties:
107
+ command_id:
108
+ type: string
109
+ command:
110
+ type: string
111
+ params:
112
+ type: array
113
+ items:
114
+ type: string
115
+ status:
116
+ type: string
117
+ start_time:
118
+ type: string
119
+ format: date-time
120
+ end_time:
121
+ type: string
122
+ format: date-time
123
+ exit_code:
124
+ type: integer
125
+ last_output_line:
126
+ type: string
127
+ cols:
128
+ type: integer
129
+ rows:
130
+ type: integer
131
+ user:
132
+ type: string
133
+ from:
134
+ type: string
135
+ pid:
136
+ type: integer
137
+
138
+ /commands/{command_id}/output:
139
+ get:
140
+ summary: "Get command output"
141
+ tags:
142
+ - commands
143
+ parameters:
144
+ - in: path
145
+ name: command_id
146
+ required: true
147
+ schema:
148
+ type: string
149
+ - in: query
150
+ name: offset
151
+ schema:
152
+ type: integer
153
+ default: 0
154
+ - in: query
155
+ name: maxsize
156
+ schema:
157
+ type: integer
158
+ default: 10485760
159
+ - in: query
160
+ name: maxlines
161
+ schema:
162
+ type: integer
163
+ default: 5000
164
+ responses:
165
+ "200":
166
+ description: "Command output returned"
167
+ content:
168
+ application/json:
169
+ schema:
170
+ type: object
171
+ properties:
172
+ output:
173
+ type: string
174
+ status:
175
+ type: string
176
+ rows:
177
+ type: integer
178
+ cols:
179
+ type: integer
180
+ links:
181
+ type: object
182
+ properties:
183
+ next:
184
+ type: string
185
+ format: uri
186
+ text/plain:
187
+ schema:
188
+ type: string
189
+
190
+ /commands/{command_id}/stop:
191
+ patch:
192
+ summary: "Stop a running command"
193
+ tags:
194
+ - commands
195
+ parameters:
196
+ - in: path
197
+ name: command_id
198
+ required: true
199
+ schema:
200
+ type: string
201
+ responses:
202
+ "200":
203
+ description: "Command stopped successfully"
204
+ content:
205
+ application/json:
206
+ schema:
207
+ type: object
208
+ properties:
209
+ message:
210
+ type: string
211
+
212
+ /commands/{command_id}/run:
213
+ post:
214
+ summary: "Relaunch a command"
215
+ tags:
216
+ - commands
217
+ parameters:
218
+ - in: path
219
+ name: command_id
220
+ required: true
221
+ schema:
222
+ type: string
223
+ requestBody:
224
+ required: true
225
+ content:
226
+ application/json:
227
+ schema:
228
+ type: object
229
+ properties:
230
+ rows:
231
+ type: integer
232
+ description: "tty nb rows"
233
+ default: 24
234
+ cols:
235
+ type: integer
236
+ description: "tty nb columns"
237
+ default: 125
238
+ responses:
239
+ "200":
240
+ description: "Command relaunched"
241
+ content:
242
+ application/json:
243
+ schema:
244
+ type: object
245
+ properties:
246
+ message:
247
+ type: string
248
+ command_id:
249
+ type: string
250
+
251
+ /commands/exposed:
252
+ get:
253
+ summary: "List available executable commands"
254
+ tags:
255
+ - commands
256
+ responses:
257
+ "200":
258
+ description: "List of commands with markdown help"
259
+ content:
260
+ application/json:
261
+ schema:
262
+ type: object
263
+ properties:
264
+ commands:
265
+ type: array
266
+ items:
267
+ type: object
268
+ properties:
269
+ command:
270
+ type: string
271
+ help:
272
+ type: string
273
+ example:
274
+ commands:
275
+ - command: ls
276
+ help: "List directory contents \n**params**:\n* `<ls_params>`"
277
+ - command: cat
278
+ help: "Concatenate and display files \n**params**:\n* `<cat_params>`"
@@ -17,5 +17,5 @@ __version__: str
17
17
  __version_tuple__: VERSION_TUPLE
18
18
  version_tuple: VERSION_TUPLE
19
19
 
20
- __version__ = version = '2.1.18'
21
- __version_tuple__ = version_tuple = (2, 1, 18)
20
+ __version__ = version = '2.2.0'
21
+ __version_tuple__ = version_tuple = (2, 2, 0)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: pywebexec
3
- Version: 2.1.18
3
+ Version: 2.2.0
4
4
  Summary: Simple Python HTTP Exec Server
5
5
  Home-page: https://github.com/joknarf/pywebexec
6
6
  Author: Franck Jouvanceau
@@ -1,258 +0,0 @@
1
- swagger: "2.0"
2
- info:
3
- title: PyWebExec API
4
- version: "1.0"
5
- paths:
6
- /commands:
7
- get:
8
- summary: "List commands status"
9
- tags:
10
- - commands
11
- responses:
12
- "200":
13
- description: "List of all commands status"
14
- schema:
15
- type: object
16
- properties:
17
- commands:
18
- type: array
19
- items:
20
- type: object
21
- properties:
22
- command_id:
23
- type: string
24
- command:
25
- type: string
26
- status:
27
- type: string
28
- start_time:
29
- type: string
30
- format: date-time
31
- end_time:
32
- type: string
33
- format: date-time
34
- exit_code:
35
- type: integer
36
- last_output_line:
37
- type: string
38
- user:
39
- type: string
40
- post:
41
- summary: "Run a command"
42
- tags:
43
- - commands
44
- consumes:
45
- - application/json
46
- produces:
47
- - application/json
48
- parameters:
49
- - in: body
50
- name: requestBody
51
- schema:
52
- type: object
53
- properties:
54
- command:
55
- type: string
56
- description: "Command to run"
57
- # Enum will be added dynamically by the APIs
58
- default: commandName
59
- params:
60
- type: array
61
- description: "Command parameters"
62
- items:
63
- type: string
64
- default: []
65
- rows:
66
- type: integer
67
- description: "tty nb rows"
68
- default: 24
69
- cols:
70
- type: integer
71
- description: "tty nb columns"
72
- default: 125
73
- required:
74
- - command
75
- responses:
76
- "200":
77
- description: "Command started"
78
- schema:
79
- type: object
80
- properties:
81
- command_id:
82
- type: string
83
- message:
84
- type: string
85
- /commands/{command_id}:
86
- get:
87
- summary: "Get command status"
88
- tags:
89
- - commands
90
- parameters:
91
- - in: path
92
- name: command_id
93
- required: true
94
- type: string
95
- responses:
96
- "200":
97
- description: "Command status returned"
98
- schema:
99
- type: object
100
- properties:
101
- command_id:
102
- type: string
103
- command:
104
- type: string
105
- params:
106
- type: array
107
- items:
108
- type: string
109
- status:
110
- type: string
111
- start_time:
112
- type: string
113
- format: date-time
114
- end_time:
115
- type: string
116
- format: date-time
117
- exit_code:
118
- type: integer
119
- last_output_line:
120
- type: string
121
- cols:
122
- type: integer
123
- rows:
124
- type: integer
125
- user:
126
- type: string
127
- from:
128
- type: string
129
- pid:
130
- type: integer
131
-
132
- /commands/{command_id}/output:
133
- get:
134
- summary: "Get command output"
135
- tags:
136
- - commands
137
- parameters:
138
- - in: path
139
- name: command_id
140
- required: true
141
- type: string
142
- - in: query
143
- name: offset
144
- type: integer
145
- default: 0
146
- - in: query
147
- name: maxsize
148
- type: integer
149
- default: 10485760
150
- - in: query
151
- name: maxlines
152
- type: integer
153
- default: 5000
154
- consumes:
155
- - application/json
156
- produces:
157
- - application/json
158
- - text/plain
159
- responses:
160
- "200":
161
- description: "Command output returned"
162
- schema:
163
- type: object
164
- properties:
165
- output:
166
- type: string
167
- status:
168
- type: string
169
- rows:
170
- type: integer
171
- cols:
172
- type: integer
173
- links:
174
- type: object
175
- properties:
176
- next:
177
- type: string
178
- format: uri
179
- /commands/{command_id}/stop:
180
- patch:
181
- summary: "Stop a running command"
182
- tags:
183
- - commands
184
- parameters:
185
- - in: path
186
- name: command_id
187
- required: true
188
- type: string
189
- responses:
190
- "200":
191
- description: "Command stopped successfully"
192
- schema:
193
- type: object
194
- properties:
195
- message:
196
- type: string
197
- /commands/{command_id}/run:
198
- post:
199
- summary: "Relaunch a command"
200
- tags:
201
- - commands
202
- parameters:
203
- - in: path
204
- name: command_id
205
- required: true
206
- type: string
207
- - in: body
208
- name: requestBody
209
- schema:
210
- type: object
211
- properties:
212
- rows:
213
- type: integer
214
- description: "tty nb rows"
215
- default: 24
216
- cols:
217
- type: integer
218
- description: "tty nb columns"
219
- default: 125
220
- responses:
221
- "200":
222
- description: "Command relaunched"
223
- schema:
224
- type: object
225
- properties:
226
- message:
227
- type: string
228
- command_id:
229
- type: string
230
- /commands/exposed:
231
- get:
232
- summary: "List available executable commands"
233
- tags:
234
- - commands
235
- produces:
236
- - application/json
237
- responses:
238
- "200":
239
- description: "List of commands with markdown help"
240
- schema:
241
- type: object
242
- properties:
243
- commands:
244
- type: array
245
- items:
246
- type: object
247
- properties:
248
- command:
249
- type: string
250
- help:
251
- type: string
252
- examples:
253
- application/json:
254
- commands:
255
- - command: ls
256
- help: "List directory contents \n**params**:\n* `<ls_params>`"
257
- - command: cat
258
- help: "Concatenate and display files \n**params**:\n* `<cat_params>`"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes