pywebexec 2.2.0__tar.gz → 2.2.2__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 (83) hide show
  1. {pywebexec-2.2.0/pywebexec.egg-info → pywebexec-2.2.2}/PKG-INFO +3 -2
  2. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/css/form.css +13 -0
  3. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/js/executables.js +29 -35
  4. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/js/schemaform.js +81 -8
  5. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/js/script.js +0 -1
  6. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/js/swagger-form.js +4 -2
  7. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/version.py +2 -2
  8. {pywebexec-2.2.0 → pywebexec-2.2.2/pywebexec.egg-info}/PKG-INFO +3 -2
  9. {pywebexec-2.2.0 → pywebexec-2.2.2}/.github/workflows/python-publish.yml +0 -0
  10. {pywebexec-2.2.0 → pywebexec-2.2.2}/.gitignore +0 -0
  11. {pywebexec-2.2.0 → pywebexec-2.2.2}/LICENSE +0 -0
  12. {pywebexec-2.2.0 → pywebexec-2.2.2}/README.md +0 -0
  13. {pywebexec-2.2.0 → pywebexec-2.2.2}/pyproject.toml +0 -0
  14. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/__init__.py +0 -0
  15. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/host_ip.py +0 -0
  16. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/pywebexec.py +0 -0
  17. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/css/markdown.css +0 -0
  18. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/css/style.css +0 -0
  19. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/css/swagger-ui.css +0 -0
  20. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/css/swagger-ui.css.map +0 -0
  21. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/css/xterm.css +0 -0
  22. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/fonts/CommitMonoNerdFontMono-Regular.ttf +0 -0
  23. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/fonts/LICENSE +0 -0
  24. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/fonts/glyphicons-halflings-regular.eot +0 -0
  25. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/fonts/glyphicons-halflings-regular.svg +0 -0
  26. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/fonts/glyphicons-halflings-regular.ttf +0 -0
  27. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/fonts/glyphicons-halflings-regular.woff +0 -0
  28. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/fonts/glyphicons-halflings-regular.woff2 +0 -0
  29. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/images/aborted.svg +0 -0
  30. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/images/copy.svg +0 -0
  31. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/images/copy_ok.svg +0 -0
  32. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/images/down-arrow.svg +0 -0
  33. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/images/failed.svg +0 -0
  34. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/images/favicon.svg +0 -0
  35. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/images/fit-tty.svg +0 -0
  36. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/images/fit-win.svg +0 -0
  37. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/images/font-decrease.svg +0 -0
  38. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/images/font-increase.svg +0 -0
  39. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/images/norun.svg +0 -0
  40. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/images/pause.svg +0 -0
  41. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/images/popup.svg +0 -0
  42. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/images/resume.svg +0 -0
  43. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/images/running.svg +0 -0
  44. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/images/success.svg +0 -0
  45. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/images/swagger-ui.svg +0 -0
  46. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/js/js-yaml/LICENSE +0 -0
  47. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/js/js-yaml/js-yaml.min.js +0 -0
  48. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/js/marked/LICENSE.md +0 -0
  49. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/js/marked/marked.min.js +0 -0
  50. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/js/popup.js +0 -0
  51. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/js/swagger-ui/LICENSE +0 -0
  52. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/js/swagger-ui/swagger-ui-bundle.js +0 -0
  53. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/js/swagger-ui/swagger-ui-standalone-preset.js +0 -0
  54. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/js/xterm/LICENSE +0 -0
  55. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/js/xterm/addon-canvas.js +0 -0
  56. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/js/xterm/addon-canvas.js.map +0 -0
  57. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/js/xterm/addon-fit.js +0 -0
  58. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/js/xterm/addon-fit.js.map +0 -0
  59. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/js/xterm/addon-unicode-graphemes.js +0 -0
  60. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/js/xterm/addon-unicode-graphemes.js.map +0 -0
  61. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/js/xterm/addon-unicode11.js +0 -0
  62. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/js/xterm/addon-unicode11.js.map +0 -0
  63. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/js/xterm/xterm.js +0 -0
  64. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/js/xterm/xterm.js.map +0 -0
  65. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/jsonform/LICENSE +0 -0
  66. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/jsonform/deps/README.md +0 -0
  67. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/jsonform/deps/img/glyphicons-halflings.png +0 -0
  68. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/jsonform/deps/jquery.min.js +0 -0
  69. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/jsonform/deps/jsv.js +0 -0
  70. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/jsonform/deps/underscore.js +0 -0
  71. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/static/jsonform/lib/jsonform.js +0 -0
  72. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/swagger.yaml +0 -0
  73. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/templates/__init__.py +0 -0
  74. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/templates/index.html +0 -0
  75. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/templates/popup.html +0 -0
  76. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec/templates/swagger_ui.html +0 -0
  77. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec.egg-info/SOURCES.txt +0 -0
  78. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec.egg-info/dependency_links.txt +0 -0
  79. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec.egg-info/entry_points.txt +0 -0
  80. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec.egg-info/requires.txt +0 -0
  81. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexec.egg-info/top_level.txt +0 -0
  82. {pywebexec-2.2.0 → pywebexec-2.2.2}/pywebexecdev +0 -0
  83. {pywebexec-2.2.0 → pywebexec-2.2.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: pywebexec
3
- Version: 2.2.0
3
+ Version: 2.2.2
4
4
  Summary: Simple Python HTTP Exec Server
5
5
  Home-page: https://github.com/joknarf/pywebexec
6
6
  Author: Franck Jouvanceau
@@ -62,6 +62,7 @@ Requires-Dist: ldap3>=2.9.1
62
62
  Requires-Dist: pyte>=0.8.1
63
63
  Requires-Dist: PyYAML>=6.0.1
64
64
  Requires-Dist: run-para>=1.0.2
65
+ Dynamic: license-file
65
66
 
66
67
  [![Pypi version](https://img.shields.io/pypi/v/pywebexec.svg)](https://pypi.org/project/pywebexec/)
67
68
  ![Publish Package](https://github.com/joknarf/pywebexec/actions/workflows/python-publish.yml/badge.svg)
@@ -211,6 +211,19 @@
211
211
  box-shadow: unset;
212
212
  outline: 0;
213
213
  }
214
+ .controls > .checkbox input {
215
+ top: 5px;
216
+ }
217
+ .checkbox {
218
+ label {
219
+ font-weight: normal;
220
+ }
221
+ input {
222
+ top: 1px;
223
+ display: unset;
224
+ margin-right: 4px;
225
+ }
226
+ }
214
227
  }
215
228
 
216
229
  .swagger-ui textarea {
@@ -264,42 +264,36 @@ paramsInput.addEventListener('focus', () => {
264
264
  }
265
265
  if (gExecutables[currentCmd] && gExecutables[currentCmd].schema && gExecutables[currentCmd].schema.properties && paramsContainer.style.display == 'none') {
266
266
  createSchemaForm($('#schemaForm'), gExecutables[currentCmd].schema, async function (errors, values) {
267
- if (errors) {
268
- console.log(errors);
269
- alert(errors[0].message);
270
- return false;
271
- } else {
272
- const commandName = commandInput.value;
273
- fitAddon.fit();
274
- terminal.clear();
275
- payload = { params: values, rows: terminal.rows, cols: terminal.cols }
276
- if ('parallel' in values) {
277
- payload['parallel'] = values['parallel'];
278
- payload['delay'] = values['delay'];
279
- delete payload['params']['parallel'];
280
- delete payload['params']['delay'];
281
- }
282
- try {
283
- const response = await fetch(`/commands/${commandName}`, {
284
- method: 'POST',
285
- headers: {
286
- 'Content-Type': 'application/json'
287
- },
288
- body: JSON.stringify(payload)
289
- });
290
-
291
- if (!response.ok) {
292
- throw new Error('Failed to launch command');
293
- }
294
-
295
- const data = await response.json();
296
- viewOutput(data.command_id);
297
- fetchCommands();
298
- commandInput.focus();
299
- commandInput.setSelectionRange(0, commandInput.value.length);
300
- } catch (error) {
301
- console.log('Error running command:', error);
267
+ const commandName = commandInput.value;
268
+ fitAddon.fit();
269
+ terminal.clear();
270
+ payload = { params: values, rows: terminal.rows, cols: terminal.cols }
271
+ if ('parallel' in values) {
272
+ payload['parallel'] = values['parallel'];
273
+ payload['delay'] = values['delay'];
274
+ delete payload['params']['parallel'];
275
+ delete payload['params']['delay'];
276
+ }
277
+ try {
278
+ const response = await fetch(`/commands/${commandName}`, {
279
+ method: 'POST',
280
+ headers: {
281
+ 'Content-Type': 'application/json'
282
+ },
283
+ body: JSON.stringify(payload)
284
+ });
285
+
286
+ if (!response.ok) {
287
+ throw new Error('Failed to launch command');
302
288
  }
289
+
290
+ const data = await response.json();
291
+ viewOutput(data.command_id);
292
+ fetchCommands();
293
+ commandInput.focus();
294
+ commandInput.setSelectionRange(0, commandInput.value.length);
295
+ } catch (error) {
296
+ console.log('Error running command:', error);
303
297
  }
304
298
  }, currentCmd);
305
299
  setHelpDivPosition();
@@ -54,12 +54,48 @@ function extractKeysAndPlaceholders(obj, formoptions, prefix = '') {
54
54
  return result;
55
55
  }
56
56
 
57
- function createSchemaForm(form, schema, onSubmit, schemaName) {
58
- if (schemaValues[schemaName]) {
59
- value = schemaValues[schemaName];
60
- } else {
61
- value = {};
57
+ // ...existing code...
58
+
59
+ function convertTextareaToArray(values, formDesc, schema) {
60
+ // Helper function to get schema type for a key path
61
+ function getSchemaType(schema, keyPath) {
62
+ const keys = keyPath.split('.');
63
+ let current = schema.properties;
64
+ for (const key of keys) {
65
+ if (!current || !current[key] || !current[key].properties) {
66
+ return current?.[key]?.type;
67
+ }
68
+ current = current[key].properties;
69
+ }
70
+ return null;
71
+ }
72
+
73
+ // Convert textarea values to arrays if schema type matches
74
+ for (let i = 0; i < formDesc.length; i++) {
75
+ if (formDesc[i].type == 'textarea') {
76
+ const schemaType = getSchemaType(schema, formDesc[i].key);
77
+ if (schemaType === 'array') {
78
+ const keys = formDesc[i].key.split('.');
79
+ let obj = values;
80
+ for (let j = 0; j < keys.length - 1; j++) {
81
+ obj = obj[keys[j]];
82
+ }
83
+ const lastKey = keys[keys.length - 1];
84
+ const val = obj[lastKey];
85
+ if (val) {
86
+ obj[lastKey] = val.trim().split(/[\s\r,]+/).filter(x => x);
87
+ } else {
88
+ delete obj[lastKey];
89
+ }
90
+ }
91
+ }
62
92
  }
93
+ return values;
94
+ }
95
+
96
+ // ...existing code...
97
+
98
+ function createSchemaForm(form, schema, onSubmit, schemaName) {
63
99
  if (schema && schema.schema_options) {
64
100
  schema_options = schema.schema_options;
65
101
  } else {
@@ -80,6 +116,33 @@ function createSchemaForm(form, schema, onSubmit, schemaName) {
80
116
  }
81
117
  }
82
118
  formDesc = extractKeysAndPlaceholders(schema, formoptions);
119
+ if (schemaValues[schemaName]) {
120
+ value = schemaValues[schemaName];
121
+ // convert array for textarea formDesc type to string separated by newlines
122
+ // if in formDesc a key has type textarea, convert the value to string separated by newlines
123
+ // formDesc=[{key: 'db.sid', type: 'textarea'}]
124
+ // value = {db: {sid: ['AA', 'BB']}}
125
+ // convert to
126
+ // value = {db: {sid: 'AA\nBB'}}
127
+ for (let i = 0; i < formDesc.length; i++) {
128
+ if (formDesc[i].type === 'textarea') {
129
+ const keys = formDesc[i].key.split('.');
130
+ let obj = value;
131
+ for (let j = 0; j < keys.length - 1; j++) {
132
+ if (!(keys[j] in obj)) obj[keys[j]] = {};
133
+ obj = obj[keys[j]];
134
+ }
135
+ const lastKey = keys[keys.length - 1];
136
+ const val = obj[lastKey];
137
+ if (val && Array.isArray(val)) {
138
+ obj[lastKey] = val.join('\n');
139
+ }
140
+ }
141
+ }
142
+ } else {
143
+ value = {};
144
+ }
145
+
83
146
  schemaForm = form[0];
84
147
  if (onSubmit != null) {
85
148
  if (schema_options && schema_options.batch_param) {
@@ -149,9 +212,20 @@ function createSchemaForm(form, schema, onSubmit, schemaName) {
149
212
  form[0].classList.add('form-inline');
150
213
  jsform = form.jsonForm({
151
214
  schema: schema,
152
- onSubmit: onSubmit,
215
+ onSubmit: function (errors, values) {
216
+ convertTextareaToArray(values, formDesc, schema);
217
+ env = JSV.createEnvironment();
218
+ report = env.validate(values, schema);
219
+ errors = report.errors;
220
+ if (errors.length > 0) {
221
+ alert(errors[0].message);
222
+ return false;
223
+ }
224
+ onSubmit(errors, values);
225
+ },
153
226
  form: formDesc,
154
227
  value: value,
228
+ validate: false,
155
229
  // params: {
156
230
  // fieldHtmlClass: "input-small",
157
231
  // }
@@ -168,9 +242,8 @@ function createSchemaForm(form, schema, onSubmit, schemaName) {
168
242
  txt.setAttribute("spellcheck", "false");
169
243
  txt.addEventListener("input", () => adjustTxtHeight(txt));
170
244
  });
171
-
172
245
  form[0].addEventListener('input', () => {
173
- schemaValues[schemaName] = jsform.root.getFormValues();
246
+ schemaValues[schemaName] = convertTextareaToArray(jsform.root.getFormValues(), formDesc, schema);
174
247
  localStorage.setItem('schemaValues', JSON.stringify(schemaValues));
175
248
  });
176
249
 
@@ -265,7 +265,6 @@ async function viewOutput(command_id) {
265
265
  } else {
266
266
  command = `${data.command.replace(/^\.\//, '')} ${data.params.join(' ')}`;
267
267
  }
268
- console.log(command);
269
268
  setCommandStatus(data.status)
270
269
  commandInfo.innerHTML = command;
271
270
  commandInfo.setAttribute('title', command);
@@ -1,8 +1,9 @@
1
1
  let ui;
2
2
  let swaggerSchemas = {};
3
+
3
4
  function addFormInputListener(textArea, jsform){
4
5
  return function (event) {
5
- jsonString = JSON.stringify(jsform.root.getFormValues(), null, 2);
6
+ jsonString = JSON.stringify(convertTextareaToArray(jsform.root.getFormValues(), jsform.formDesc.form, jsform.formDesc.schema), null, 2);
6
7
  textArea.value = jsonString;
7
8
 
8
9
  // Find the React fiber node
@@ -107,7 +108,8 @@ window.onload = function() {
107
108
  form.id = routePathId;
108
109
  form.classList.add("schema-form");
109
110
  jsform = createSchemaForm($(form), swaggerSchemas[routePath], null, routePath);
110
- // form.addEventListener("input", formInput(node, jsform));
111
+ // form.addEventListener("input", formInput(node, jsform));
112
+ setTimeout(() => addFormInputListener(paramtext, jsform)(), 100);
111
113
  form.addEventListener("input", addFormInputListener(paramtext, jsform));
112
114
  paramtext.parentNode.insertBefore(form, paramtext.nextSibling);
113
115
  item1 = form.querySelector("input, select, textarea");
@@ -17,5 +17,5 @@ __version__: str
17
17
  __version_tuple__: VERSION_TUPLE
18
18
  version_tuple: VERSION_TUPLE
19
19
 
20
- __version__ = version = '2.2.0'
21
- __version_tuple__ = version_tuple = (2, 2, 0)
20
+ __version__ = version = '2.2.2'
21
+ __version_tuple__ = version_tuple = (2, 2, 2)
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: pywebexec
3
- Version: 2.2.0
3
+ Version: 2.2.2
4
4
  Summary: Simple Python HTTP Exec Server
5
5
  Home-page: https://github.com/joknarf/pywebexec
6
6
  Author: Franck Jouvanceau
@@ -62,6 +62,7 @@ Requires-Dist: ldap3>=2.9.1
62
62
  Requires-Dist: pyte>=0.8.1
63
63
  Requires-Dist: PyYAML>=6.0.1
64
64
  Requires-Dist: run-para>=1.0.2
65
+ Dynamic: license-file
65
66
 
66
67
  [![Pypi version](https://img.shields.io/pypi/v/pywebexec.svg)](https://pypi.org/project/pywebexec/)
67
68
  ![Publish Package](https://github.com/joknarf/pywebexec/actions/workflows/python-publish.yml/badge.svg)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes