cmdbox 0.5.2__py3-none-any.whl → 0.5.3.1__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.

Potentially problematic release.


This version of cmdbox might be problematic. Click here for more details.

Files changed (114) hide show
  1. cmdbox/app/auth/signin.py +1 -0
  2. cmdbox/app/feature.py +2 -0
  3. cmdbox/app/features/cli/audit_base.py +5 -2
  4. cmdbox/app/features/cli/cmdbox_audit_createdb.py +1 -1
  5. cmdbox/app/features/cli/cmdbox_audit_delete.py +27 -18
  6. cmdbox/app/features/cli/cmdbox_audit_search.py +128 -62
  7. cmdbox/app/features/cli/cmdbox_audit_write.py +31 -20
  8. cmdbox/app/features/cli/cmdbox_client_file_copy.py +1 -1
  9. cmdbox/app/features/cli/cmdbox_client_file_download.py +1 -1
  10. cmdbox/app/features/cli/cmdbox_client_file_list.py +1 -1
  11. cmdbox/app/features/cli/cmdbox_client_file_mkdir.py +1 -1
  12. cmdbox/app/features/cli/cmdbox_client_file_move.py +1 -1
  13. cmdbox/app/features/cli/cmdbox_client_file_remove.py +1 -1
  14. cmdbox/app/features/cli/cmdbox_client_file_rmdir.py +1 -1
  15. cmdbox/app/features/cli/cmdbox_client_file_upload.py +1 -1
  16. cmdbox/app/features/cli/cmdbox_client_server_info.py +1 -1
  17. cmdbox/app/features/cli/cmdbox_gui_start.py +1 -1
  18. cmdbox/app/features/cli/cmdbox_server_start.py +1 -1
  19. cmdbox/app/features/cli/cmdbox_server_stop.py +1 -1
  20. cmdbox/app/features/cli/cmdbox_web_apikey_add.py +1 -1
  21. cmdbox/app/features/cli/cmdbox_web_apikey_del.py +1 -1
  22. cmdbox/app/features/cli/cmdbox_web_group_add.py +1 -1
  23. cmdbox/app/features/cli/cmdbox_web_group_del.py +1 -1
  24. cmdbox/app/features/cli/cmdbox_web_group_edit.py +1 -1
  25. cmdbox/app/features/cli/cmdbox_web_group_list.py +1 -1
  26. cmdbox/app/features/cli/cmdbox_web_start.py +1 -1
  27. cmdbox/app/features/cli/cmdbox_web_user_add.py +1 -1
  28. cmdbox/app/features/cli/cmdbox_web_user_del.py +1 -1
  29. cmdbox/app/features/cli/cmdbox_web_user_edit.py +1 -1
  30. cmdbox/app/features/cli/cmdbox_web_user_list.py +1 -1
  31. cmdbox/app/features/web/cmdbox_web_audit.py +87 -0
  32. cmdbox/app/features/web/cmdbox_web_audit_metrics.py +72 -0
  33. cmdbox/app/features/web/cmdbox_web_exec_cmd.py +10 -5
  34. cmdbox/app/features/web/cmdbox_web_user_data.py +58 -0
  35. cmdbox/app/options.py +49 -19
  36. cmdbox/app/server.py +15 -3
  37. cmdbox/app/web.py +7 -1
  38. cmdbox/extensions/features.yml +11 -8
  39. cmdbox/extensions/sample_project/sample/app/features/cli/sample_server_time.py +1 -1
  40. cmdbox/extensions/user_list.yml +5 -0
  41. cmdbox/licenses/LICENSE.Jinja2.3.1.4(BSD License).txt +28 -0
  42. cmdbox/licenses/LICENSE.Pygments.2.18.0(BSD License).txt +25 -0
  43. cmdbox/licenses/LICENSE.Sphinx.8.1.3(BSD License).txt +31 -0
  44. cmdbox/licenses/LICENSE.anyio.4.6.2.post1(MIT License).txt +20 -0
  45. cmdbox/licenses/LICENSE.argcomplete.3.5.1(Apache Software License).txt +177 -0
  46. cmdbox/licenses/LICENSE.argcomplete.3.6.2(Apache Software License).txt +177 -0
  47. cmdbox/licenses/LICENSE.babel.2.16.0(BSD License).txt +27 -0
  48. cmdbox/licenses/LICENSE.certifi.2024.8.30(Mozilla Public License 2.0 (MPL 2.0)).txt +20 -0
  49. cmdbox/licenses/LICENSE.charset-normalizer.3.4.0(MIT License).txt +21 -0
  50. cmdbox/licenses/LICENSE.click.8.1.7(BSD License).txt +28 -0
  51. cmdbox/licenses/LICENSE.cryptography.43.0.3(Apache Software License; BSD License).txt +3 -0
  52. cmdbox/licenses/LICENSE.fastapi.0.115.5(MIT License).txt +21 -0
  53. cmdbox/licenses/LICENSE.gevent.25.4.1(MIT).txt +25 -0
  54. cmdbox/licenses/LICENSE.greenlet.3.2.0(MIT AND Python-2.0).txt +30 -0
  55. cmdbox/licenses/LICENSE.importlib_metadata.8.5.0(Apache Software License).txt +202 -0
  56. cmdbox/licenses/LICENSE.keyring.25.5.0(MIT License).txt +17 -0
  57. cmdbox/licenses/LICENSE.more-itertools.10.5.0(MIT License).txt +19 -0
  58. cmdbox/licenses/LICENSE.nh3.0.2.18(MIT).txt +1 -0
  59. cmdbox/licenses/LICENSE.numpy.2.1.3(BSD License).txt +950 -0
  60. cmdbox/licenses/LICENSE.pillow.11.0.0(CMU License (MIT-CMU)).txt +1226 -0
  61. cmdbox/licenses/LICENSE.pillow.11.2.1(UNKNOWN).txt +1200 -0
  62. cmdbox/licenses/LICENSE.pkginfo.1.10.0(MIT License).txt +21 -0
  63. cmdbox/licenses/LICENSE.prettytable.3.12.0(BSD License).txt +30 -0
  64. cmdbox/licenses/LICENSE.prompt_toolkit.3.0.51(BSD License).txt +27 -0
  65. cmdbox/licenses/LICENSE.pydantic.2.10.2(MIT License).txt +21 -0
  66. cmdbox/licenses/LICENSE.pydantic.2.11.3(MIT License).txt +21 -0
  67. cmdbox/licenses/LICENSE.pydantic_core.2.27.1(MIT License).txt +21 -0
  68. cmdbox/licenses/LICENSE.pydantic_core.2.33.1(MIT License).txt +21 -0
  69. cmdbox/licenses/LICENSE.python-dotenv.1.0.1(BSD License).txt +27 -0
  70. cmdbox/licenses/LICENSE.python-multipart.0.0.17(Apache Software License).txt +14 -0
  71. cmdbox/licenses/LICENSE.redis.5.2.0(MIT License).txt +21 -0
  72. cmdbox/licenses/LICENSE.rich.13.9.4(MIT License).txt +19 -0
  73. cmdbox/licenses/LICENSE.six.1.16.0(MIT License).txt +18 -0
  74. cmdbox/licenses/LICENSE.sphinx-intl.2.3.0(BSD License).txt +25 -0
  75. cmdbox/licenses/LICENSE.starlette.0.41.3(BSD License).txt +27 -0
  76. cmdbox/licenses/LICENSE.starlette.0.46.2(BSD License).txt +27 -0
  77. cmdbox/licenses/LICENSE.tomli.2.1.0(MIT License).txt +21 -0
  78. cmdbox/licenses/LICENSE.twine.5.1.1(Apache Software License).txt +174 -0
  79. cmdbox/licenses/LICENSE.typing_extensions.4.12.2(Python Software Foundation License).txt +279 -0
  80. cmdbox/licenses/LICENSE.typing_extensions.4.13.2(UNKNOWN).txt +279 -0
  81. cmdbox/licenses/LICENSE.urllib3.2.2.3(MIT License).txt +21 -0
  82. cmdbox/licenses/LICENSE.urllib3.2.4.0(UNKNOWN).txt +21 -0
  83. cmdbox/licenses/LICENSE.uvicorn.0.32.1(BSD License).txt +27 -0
  84. cmdbox/licenses/LICENSE.uvicorn.0.34.1(BSD License).txt +27 -0
  85. cmdbox/licenses/LICENSE.watchfiles.1.0.0(MIT License).txt +21 -0
  86. cmdbox/licenses/LICENSE.watchfiles.1.0.5(MIT License).txt +21 -0
  87. cmdbox/licenses/LICENSE.websockets.14.1(BSD License).txt +24 -0
  88. cmdbox/licenses/LICENSE.zope.interface.7.1.1(Zope Public License).txt +44 -0
  89. cmdbox/licenses/files.txt +12 -13
  90. cmdbox/version.py +2 -2
  91. cmdbox/web/assets/apexcharts/apexcharts.css +679 -0
  92. cmdbox/web/assets/apexcharts/apexcharts.min.js +38 -0
  93. cmdbox/web/assets/cmdbox/audit.js +404 -0
  94. cmdbox/web/assets/cmdbox/color_mode.css +4 -0
  95. cmdbox/web/assets/cmdbox/common.js +397 -24
  96. cmdbox/web/assets/cmdbox/filer_modal.js +1 -1
  97. cmdbox/web/assets/cmdbox/list_cmd.js +7 -271
  98. cmdbox/web/assets/cmdbox/list_pipe.js +3 -3
  99. cmdbox/web/assets/cmdbox/users.js +17 -17
  100. cmdbox/web/assets/cmdbox/view_raw.js +1 -1
  101. cmdbox/web/assets/cmdbox/view_result.js +11 -13
  102. cmdbox/web/assets/filer/filer.js +2 -2
  103. cmdbox/web/assets_license_list.txt +4 -1
  104. cmdbox/web/audit.html +293 -0
  105. cmdbox/web/filer.html +21 -10
  106. cmdbox/web/gui.html +21 -52
  107. cmdbox/web/result.html +9 -2
  108. cmdbox/web/users.html +7 -3
  109. {cmdbox-0.5.2.dist-info → cmdbox-0.5.3.1.dist-info}/METADATA +13 -10
  110. {cmdbox-0.5.2.dist-info → cmdbox-0.5.3.1.dist-info}/RECORD +114 -59
  111. {cmdbox-0.5.2.dist-info → cmdbox-0.5.3.1.dist-info}/LICENSE +0 -0
  112. {cmdbox-0.5.2.dist-info → cmdbox-0.5.3.1.dist-info}/WHEEL +0 -0
  113. {cmdbox-0.5.2.dist-info → cmdbox-0.5.3.1.dist-info}/entry_points.txt +0 -0
  114. {cmdbox-0.5.2.dist-info → cmdbox-0.5.3.1.dist-info}/top_level.txt +0 -0
@@ -148,7 +148,9 @@ cmdbox.passchange = async () => {
148
148
  const form = $(`<form id="chpass_form" class="modal-content novalidate"/>`).appendTo(daialog);
149
149
  const header = $(`<div class="modal-header"/>`).appendTo(form);
150
150
  header.append('<h5 class="modal-title">Change Password</h5>');
151
- header.append('<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" style="margin-left: 0px;"></button>');
151
+ header.append('<button type="button" class="btn btn_close p-0 m-0" data-bs-dismiss="modal" aria-label="Close" style="margin-left: 0px;">'
152
+ +'<svg class="bi bi-x" width="24" height="24" fill="currentColor"><use href="#btn_x"></use></svg>'
153
+ +'</button>');
152
154
  const body = $(`<div class="modal-body"/>`).appendTo(form);
153
155
  const row_content = $(`<div class="row row_content"/>`).appendTo(body);
154
156
  const crrent_pass = $(`<div class="col-12 mb-3"><div class="input-group">`+
@@ -980,18 +982,60 @@ cmdbox.progress = (_min, _max, _now, _text, _show, _cycle) => {
980
982
  }, 20);
981
983
  }
982
984
  };
985
+ /**
986
+ * ユーザーデータを保存
987
+ * @param {string} cat - カテゴリ
988
+ * @param {string} key - キー
989
+ * @param {string} val - 値
990
+ * @returns {Promise}
991
+ */
992
+ cmdbox.save_user_data = async (cat, key, val) => {
993
+ const formData = new FormData();
994
+ formData.append('categoly', cat);
995
+ formData.append('key', key);
996
+ formData.append('val', val);
997
+ const res = await fetch('gui/user_data/save', {method:'POST', body:formData});
998
+ if (!res.ok) cmdbox.message({'error':`${res.status}: ${res.statusText}`});
999
+ const msg = await res.json()
1000
+ return msg;
1001
+ };
1002
+ /**
1003
+ * ユーザーデータを取得
1004
+ * @param {string} cat - カテゴリ
1005
+ * @param {string} key - キー
1006
+ * @returns {Promise}
1007
+ */
1008
+ cmdbox.load_user_data = async (cat, key) => {
1009
+ const formData = new FormData();
1010
+ formData.append('categoly', cat);
1011
+ if (key) formData.append('key', key);
1012
+ const res = await fetch('gui/user_data/load', {method:'POST', body:formData});
1013
+ if (!res.ok) cmdbox.message({'error':`${res.status}: ${res.statusText}`});
1014
+ const data = await res.json();
1015
+ return data;
1016
+ };
1017
+ /**
1018
+ * ユーザーデータを削除
1019
+ * @param {string} cat - カテゴリ
1020
+ * @param {string} key - キー
1021
+ * @returns {Promise}
1022
+ */
1023
+ cmdbox.delete_user_data = async (cat, key) => {
1024
+ const formData = new FormData();
1025
+ formData.append('categoly', cat);
1026
+ formData.append('key', key);
1027
+ const res = await fetch('gui/user_data/delete', {method:'POST', body:formData});
1028
+ if (!res.ok) cmdbox.message({'error':`${res.status}: ${res.statusText}`});
1029
+ const data = await res.json();
1030
+ return data;
1031
+ };
983
1032
  /**
984
1033
  * コマンドピンを保存
985
1034
  * @param {string} title - タイトル
986
1035
  * @param {bool} pin - ピン
987
1036
  */
988
1037
  cmdbox.save_cmd_pin = async (title, pin) => {
989
- const formData = new FormData();
990
- formData.append('title', title);
991
- formData.append('pin', pin?'on':'off');
992
- const res = await fetch('gui/save_cmd_pin', {method:'POST', body:formData});
993
- if (!res.ok) cmdbox.message({'error':`${res.status}: ${res.statusText}`});
994
- const msg = await res.json()
1038
+ return await cmdbox.save_user_data('cmdpins', title, pin?'on':'off');
995
1039
  };
996
1040
  /**
997
1041
  * コマンドピンをロード
@@ -999,12 +1043,7 @@ cmdbox.save_cmd_pin = async (title, pin) => {
999
1043
  * @returns {Promise}
1000
1044
  */
1001
1045
  cmdbox.load_cmd_pin = async (title) => {
1002
- const formData = new FormData();
1003
- if (title) formData.append('title', title);
1004
- const res = await fetch('gui/load_cmd_pin', {method:'POST', body:formData});
1005
- if (!res.ok) cmdbox.message({'error':`${res.status}: ${res.statusText}`});
1006
- const pins = await res.json();
1007
- return pins;
1046
+ return await cmdbox.load_user_data('cmdpins', title);
1008
1047
  };
1009
1048
  /**
1010
1049
  * パイプピンを保存
@@ -1012,12 +1051,7 @@ cmdbox.load_cmd_pin = async (title) => {
1012
1051
  * @param {bool} pin - ピン
1013
1052
  */
1014
1053
  cmdbox.save_pipe_pin = async (title, pin) => {
1015
- const formData = new FormData();
1016
- formData.append('title', title);
1017
- formData.append('pin', pin?'on':'off');
1018
- const res = await fetch('gui/save_pipe_pin', {method:'POST', body:formData});
1019
- if (!res.ok) cmdbox.message({'error':`${res.status}: ${res.statusText}`});
1020
- const msg = await res.json()
1054
+ return await cmdbox.save_user_data('pipepins', title, pin?'on':'off');
1021
1055
  };
1022
1056
  /**
1023
1057
  * パイプピンをロード
@@ -1025,10 +1059,349 @@ cmdbox.save_pipe_pin = async (title, pin) => {
1025
1059
  * @returns {Promise}
1026
1060
  */
1027
1061
  cmdbox.load_pipe_pin = async (title) => {
1062
+ return await cmdbox.load_user_data('pipepins', title);
1063
+ }
1064
+ /**
1065
+ * コマンドモーダルのフォームを追加
1066
+ * @param {number} i - インデックス
1067
+ * @param {$} cmd_modal - コマンドモーダル
1068
+ * @param {$} row_content - 行コンテンツ
1069
+ * @param {object} row - 行データ(コマンドオプション)
1070
+ * @param {$} next_elem - 次の要素
1071
+ * @param {number} lcolsize - 横長のカラムサイズ
1072
+ * @param {number} scolsize - 通常のカラムサイズ
1073
+ * @returns {void}
1074
+ */
1075
+ cmdbox.add_form_func = (i, cmd_modal, row_content, row, next_elem, lcolsize=12, scolsize=6) => {
1076
+ const target_name = row.opt;
1077
+ // clmsg_idのオプションは隠しオプション扱い。restapiで指定はできる。
1078
+ if (target_name=='clmsg_id') return;
1079
+ let input_elem, elem;
1080
+ if(!row.choice) {
1081
+ // 選択肢がない場合
1082
+ if(row.type=='text') {
1083
+ elem = $(`<div class="col-${lcolsize} mb-3">` // row_content_template_text
1084
+ +'<div class="input-group">'
1085
+ +'<label class="input-group-text row_content_template_title">title</label>'
1086
+ +'<textarea class="form-control row_content_template_input" rows="1" style="field-sizing:content;"></textarea>'
1087
+ +'</div></div>');
1088
+ } else if(row.type=='dict') {
1089
+ elem = $(`<div class="col-${lcolsize} mb-3">` // row_content_template_dict
1090
+ +'<div class="input-group">'
1091
+ +'<label class="input-group-text row_content_template_title">title</label>'
1092
+ +'<input type="text" class="form-control row_content_key row_content_template_input">'
1093
+ +'<label class="input-group-text">=</label>'
1094
+ +'<input type="text" class="form-control row_content_val row_content_template_input">'
1095
+ +'</div></div>');
1096
+ } else {
1097
+ elem = $(`<div class="col-${scolsize} mb-3">` // row_content_template_str
1098
+ +'<div class="input-group">'
1099
+ +'<label class="input-group-text row_content_template_title">title</label>'
1100
+ +'<input type="text" class="form-control row_content_template_input">'
1101
+ +'</div></div>');
1102
+ }
1103
+ if (next_elem) next_elem.after(elem);
1104
+ else row_content.append(elem);
1105
+ input_elem = elem.find('.row_content_template_input');
1106
+ if(row.type=='date') input_elem.attr('type', 'date');
1107
+ else if(row.type=='datetime') input_elem.attr('type', 'datetime-local');
1108
+ input_elem.removeClass('row_content_template_input');
1109
+ input_elem.val(row.default);
1110
+ }
1111
+ else {
1112
+ // 選択肢がある場合
1113
+ if(row.type=='dict') {
1114
+ if (Array.isArray(row.choice)) {
1115
+ elem = $(`<div class="col-${lcolsize} mb-3">` // row_content_template_dict_choice
1116
+ +'<div class="input-group">'
1117
+ +'<label class="input-group-text row_content_template_title">title</label>'
1118
+ +'<input type="text" class="form-control row_content_key row_content_template_input">'
1119
+ +'<label class="input-group-text">=</label>'
1120
+ +'<select class="form-select row_content_template_select"></select>'
1121
+ +'</div></div>');
1122
+ }
1123
+ else {
1124
+ elem = $(`<div class="col-${lcolsize} mb-3">` // row_content_template_dict_choice
1125
+ +'<div class="input-group">'
1126
+ +'<label class="input-group-text row_content_template_title">title</label>'
1127
+ +'<select class="form-select row_content_key row_content_template_select"></select>'
1128
+ +'<label class="input-group-text">=</label>'
1129
+ +'<select class="form-select row_content_template_select"></select>'
1130
+ +'</div></div>');
1131
+ }
1132
+ } else {
1133
+ elem = $(`<div class="col-${scolsize} mb-3">` // row_content_template_choice
1134
+ +'<div class="input-group">'
1135
+ +'<label class="input-group-text row_content_template_title">title</label>'
1136
+ +'<select class="form-select row_content_template_select"></select>'
1137
+ +'</div></div>');
1138
+ }
1139
+ if (next_elem) next_elem.after(elem);
1140
+ else row_content.append(elem);
1141
+ input_elem = elem.find('.row_content_template_select,.row_content_template_input');
1142
+ input_elem.removeClass('row_content_template_select').removeClass('row_content_template_input');
1143
+ if (row.choice_show) {
1144
+ input_elem.addClass('choice_show');
1145
+ input_elem.change(() => {
1146
+ let names = []
1147
+ for (const ns of Object.values(row.choice_show)) {
1148
+ if (Array.isArray(ns)) {
1149
+ ns.forEach(n => names.push(n));
1150
+ } else {
1151
+ names.push(ns);
1152
+ }
1153
+ }
1154
+ names = [...new Set(names)];
1155
+ names.forEach(name => row_content.find(`[name="${name}"]`).parent().parent().hide());
1156
+ const v = input_elem.val();
1157
+ if (!row.choice_show[v]) return;
1158
+ row.choice_show[v].forEach(n => row_content.find(`[name="${n}"]`).parent().parent().show());
1159
+ });
1160
+ }
1161
+ // 配列をoptionタグに変換
1162
+ const mkopt = (arr) => {
1163
+ if (!arr) return '';
1164
+ const opt = arr.map(row => {
1165
+ if (row && typeof row === 'object') {
1166
+ key = Object.keys(row)[0];
1167
+ d = window.navigator.language=='ja'?row[key].discription_ja:row[key].discription_en;
1168
+ return `<option value="${key}" discription="${d}">${key}</option>`;
1169
+ }
1170
+ return `<option value="${row}" discription="">${row}</option>`;
1171
+ }).join('');
1172
+ return opt;
1173
+ }
1174
+ if (Array.isArray(row.choice)) {
1175
+ // 配列の場合
1176
+ input_elem.html(mkopt(row.choice));
1177
+ input_elem.val(`${row.default!=null?row.default:''}`);
1178
+ } else {
1179
+ // 辞書の場合
1180
+ const cho = [row.choice['key'], row.choice['val']];
1181
+ let def = row.default!=null?[row.default, row.default]:null;
1182
+ if (row.default && typeof row.default === 'object') {
1183
+ def[0] = Object.keys(row.default)[0];
1184
+ def[1] = row.default[def[0]];
1185
+ }
1186
+ input_elem.each((i, e) => {
1187
+ $(e).html(mkopt(cho[i]));
1188
+ $(e).val(`${def!=null?def[i]:''}`);
1189
+ });
1190
+ }
1191
+ }
1192
+ let index = 0;
1193
+ if (cmd_modal.find(`[name="${target_name}"]`).length > 0) {
1194
+ index = 0;
1195
+ cmd_modal.find(`[name="${target_name}"][param_data_index]`).each((i, val) => {
1196
+ v = Number($(val).attr('param_data_index'));
1197
+ if (index <= v) index = v + 1;
1198
+ });
1199
+ }
1200
+ input_elem.attr('name', target_name);
1201
+ if(row.type=='dict') {
1202
+ input_elem.each((i, e) => {
1203
+ $(e).attr('id', target_name + (index + i));
1204
+ $(e).attr('param_data_index', (index + i));
1205
+ });
1206
+ } else {
1207
+ input_elem.attr('id', target_name + index);
1208
+ input_elem.attr('param_data_index', index);
1209
+ }
1210
+ input_elem.attr('required', row.required);
1211
+ input_elem.attr('param_data_type', row.type);
1212
+ input_elem.attr('param_data_multi', row.multi);
1213
+ input_elem.attr('param_data_web', row.web);
1214
+ if (row.web=='mask' || row.web=='readonly') {
1215
+ input_elem.attr('disabled', 'disabled');
1216
+ }
1217
+ // ファイルタイプの場合はファイラーモーダルを開くボタンを追加
1218
+ if(row.type=='file'){
1219
+ const btn = $('<button class="btn btn-secondary" type="button">file</button>');
1220
+ input_elem.parent().append(btn);
1221
+ const mk_func = (tid, tn) => {
1222
+ // tid, tnの値を残すためにクロージャーにする
1223
+ return () => {
1224
+ const current_path = $(`[id="${tid}"]`).val();
1225
+ fmodal.filer_modal_func(tid, tn, current_path, false, true);
1226
+ }
1227
+ }
1228
+ btn.click(mk_func(input_elem.attr('id'), input_elem.attr('name')));
1229
+ }
1230
+ // ディレクトリタイプの場合はファイラーモーダルを開くボタンを追加
1231
+ if(row.type=='dir'){
1232
+ const btn = $('<button class="btn btn-secondary" type="button">dir</button>');
1233
+ input_elem.parent().append(btn);
1234
+ const mk_func = (tid, tn) => {
1235
+ // tid, tnの値を残すためにクロージャーにする
1236
+ return () => {
1237
+ const current_path = $(`[id="${tid}"]`).val();
1238
+ fmodal.filer_modal_func(tid, tn, current_path, true, true);
1239
+ }
1240
+ }
1241
+ btn.click(mk_func(input_elem.attr('id'), input_elem.attr('name')));
1242
+ }
1243
+ // マルチの場合は追加ボタンを追加
1244
+ if(row.multi){
1245
+ const btn_a = $('<button class="btn btn-secondary add_buton" type="button"></button>');
1246
+ btn_a.append('<svg class="bi bi-plus" width="16" height="16" fill="currentColor"><use href="#btn_plus"></use></svg>');
1247
+ input_elem.parent().append(btn_a);
1248
+ let mk_func = (row, next_elem) => {
1249
+ // row, next_elemの値を残すためにクロージャーにする
1250
+ return () => {
1251
+ const r = {...row};
1252
+ //r.hide = next_elem.is(':hidden');
1253
+ cmdbox.add_form_func(0, cmd_modal, row_content, r, next_elem, lcolsize, scolsize);
1254
+ }
1255
+ }
1256
+ btn_a.click(mk_func(row, input_elem.parent().parent()));
1257
+ // 2個目以降は削除ボタンを追加
1258
+ const len = cmd_modal.find(`[name="${target_name}"]`).length;
1259
+ if (row.type!='dict' && len > 1 || row.type=='dict' && len > 2) {
1260
+ mk_func = (del_elem, row) => {
1261
+ // del_elemの値を残すためにクロージャーにする
1262
+ return () => del_elem.remove();
1263
+ }
1264
+ const btn_t = $('<button class="btn btn-secondary" type="button"></button>');
1265
+ btn_trash
1266
+ btn_t.append('<svg class="bi bi-trash" width="16" height="16" fill="currentColor"><use href="#btn_trash"></use></svg>');
1267
+ input_elem.parent().append(btn_t);
1268
+ btn_t.click(mk_func(input_elem.parent().parent(), row));
1269
+ }
1270
+ }
1271
+ const title = elem.find('.row_content_template_title');
1272
+ title.html('');
1273
+ title.attr('title', window.navigator.language=='ja'?row.discription_ja:row.discription_en)
1274
+ if (row.required) {
1275
+ title.append('<span class="text-danger" title="required">*</span>');
1276
+ }
1277
+ if (row.choice_show) {
1278
+ title.append('<span class="text-primary" title="choice_show">*</span>');
1279
+ }
1280
+ title.append(`<span>${row.opt}</span>`);
1281
+ if (row.hide) {
1282
+ if (row_content.find('.row_content_hide').is(':hidden')) elem.hide();
1283
+ elem.addClass('row_content_hide');
1284
+ } else {
1285
+ title.addClass('text-decoration-underline');
1286
+ }
1287
+ }
1288
+ /**
1289
+ * コマンド選択肢取得
1290
+ * @param {string} mode - モード
1291
+ * @param {string} cmd - コマンド
1292
+ * @returns {Promise} - コマンドオプション
1293
+ */
1294
+ cmdbox.get_cmd_choices = async (mode, cmd) => {
1028
1295
  const formData = new FormData();
1029
- if (title) formData.append('title', title);
1030
- const res = await fetch('gui/load_pipe_pin', {method:'POST', body:formData});
1031
- if (!res.ok) cmdbox.message({'error':`${res.status}: ${res.statusText}`});
1032
- const pins = await res.json();
1033
- return pins;
1296
+ formData.append('mode', mode);
1297
+ formData.append('cmd', cmd);
1298
+ const res = await fetch('gui/get_cmd_choices', {method: 'POST', body: formData});
1299
+ if (res.status != 200) cmdbox.message({'error':`${res.status}: ${res.statusText}`});
1300
+ return await res.json();
1301
+ }
1302
+ // コマンドフォームからパラメータを取得
1303
+ cmdbox.get_param = (modal_elem) => {
1304
+ modal_elem.find('.is-invalid, .is-valid').removeClass('is-invalid').removeClass('is-valid');
1305
+ const opt = {};
1306
+ const title = modal_elem.find('[name="title"]').val();
1307
+ opt["modal_mode"] = modal_elem.find('[name="modal_mode"]').val();
1308
+ opt["mode"] = modal_elem.find('[name="mode"]').val();
1309
+ opt["cmd"] = modal_elem.find('[name="cmd"]').val();
1310
+ if(!opt["mode"]) delete opt["mode"];
1311
+ if(!opt["cmd"]) delete opt["cmd"];
1312
+ opt["title"] = title;
1313
+ const isFloat = (i) => {
1314
+ try {
1315
+ n = Number(i);
1316
+ return n % 1 !== 0;
1317
+ } catch(e) {
1318
+ return false;
1319
+ }
1320
+ }
1321
+ const isInt = (i) => {
1322
+ try {
1323
+ n = Number(i);
1324
+ return n % 1 === 0;
1325
+ } catch(e) {
1326
+ return false;
1327
+ }
1328
+ }
1329
+ // フォームの入力値をチェック(不正な値があればフォームに'is-invalid'クラスを付加する)
1330
+ const dict_buf = {};
1331
+ modal_elem.find('.row_content, .row_content_common').find('input, select, textarea').each((i, elem) => {
1332
+ const data_name = $(elem).attr('name');
1333
+ let data_val = $(elem).val();
1334
+ const data_type = $(elem).attr('param_data_type');
1335
+ const data_web = $(elem).attr('param_data_web');
1336
+ const data_index = parseInt($(elem).attr('param_data_index'));
1337
+ const data_multi = $(elem).attr('param_data_multi');
1338
+ if ($(elem).attr('required') && (!data_val || data_val=='')) {
1339
+ $(elem).addClass('is-invalid');
1340
+ } else if (data_type=='int' && !data_web) {
1341
+ if(data_val && data_val!='') {
1342
+ if(!isInt(data_val)) $(elem).addClass('is-invalid');
1343
+ else {
1344
+ $(elem).removeClass('is-invalid');
1345
+ $(elem).addClass('is-valid');
1346
+ data_val = parseInt(data_val);
1347
+ }
1348
+ } else {
1349
+ $(elem).removeClass('is-invalid');
1350
+ $(elem).addClass('is-valid');
1351
+ }
1352
+ } else if (data_type=='float') {
1353
+ if(data_val && data_val!='') {
1354
+ if(!isFloat(data_val) && !isInt(data_val)) $(elem).addClass('is-invalid');
1355
+ else {
1356
+ $(elem).removeClass('is-invalid');
1357
+ $(elem).addClass('is-valid');
1358
+ data_val = parseFloat(data_val);
1359
+ }
1360
+ } else {
1361
+ $(elem).removeClass('is-invalid');
1362
+ $(elem).addClass('is-valid');
1363
+ }
1364
+ } else if (data_type=='bool') {
1365
+ if(data_val!='true' && data_val!='false' && !$(elem).prop('disabled')) $(elem).addClass('is-invalid');
1366
+ else {
1367
+ data_val = data_val=='true';
1368
+ $(elem).removeClass('is-invalid');
1369
+ $(elem).addClass('is-valid');
1370
+ }
1371
+ } else if (data_type=='dict') {
1372
+ data_val = data_val ? data_val : '';
1373
+ if(data_val.indexOf(' ')>=0) $(elem).addClass('is-invalid');
1374
+ else {
1375
+ $(elem).removeClass('is-invalid');
1376
+ $(elem).addClass('is-valid');
1377
+ }
1378
+ } else if (data_type=='text') {
1379
+ $(elem).removeClass('is-invalid');
1380
+ $(elem).addClass('is-valid');
1381
+ } else {
1382
+ $(elem).removeClass('is-invalid');
1383
+ $(elem).addClass('is-valid');
1384
+ }
1385
+ if(data_multi=='true' || data_type=='dict') {
1386
+ if (data_type=='dict') {
1387
+ if(!opt[data_name]) {
1388
+ opt[data_name] = {};
1389
+ dict_buf[data_name] = {};
1390
+ }
1391
+ if(data_index%2==0) dict_buf[data_name]['key'] = data_val;
1392
+ else if (dict_buf[data_name]['key']) {
1393
+ opt[data_name][dict_buf[data_name]['key']] = data_val;
1394
+ delete dict_buf[data_name]['key'];
1395
+ }
1396
+ } else {
1397
+ if(!opt[data_name]) opt[data_name] = [];
1398
+ if(data_val && data_val!='') opt[data_name].push(data_val);
1399
+ else if(data_val==false) opt[data_name].push(data_val);
1400
+ }
1401
+ } else {
1402
+ if(data_val && data_val!='') opt[data_name] = data_val;
1403
+ else if(data_val==false) opt[data_name] = data_val;
1404
+ }
1405
+ });
1406
+ return [title, opt];
1034
1407
  }
@@ -62,7 +62,7 @@ fmodal.filer_modal_func = async (target_id, modal_title, current_path, select_di
62
62
  filer_modal.find('.file-list').html('');
63
63
  filer_modal.find('.file-list').append(table);
64
64
  const table_head = $('<thead></thead>');
65
- table_head.append($('<tr><th scope="col">-</th><th scope="col">name</th><th scope="col">size</th><th scope="col">last</th></tr>'));
65
+ table_head.append($('<tr><th class="th" scope="col">-</th><th class="th" scope="col">name</th><th class="th" scope="col">size</th><th class="th" scope="col">last</th></tr>'));
66
66
  table.append(table_head);
67
67
  const table_body = $('<tbody></tbody>');
68
68
  table.append(table_body);