@yuneta/gobj-ui 7.23.166 → 7.23.168

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.
@@ -24336,7 +24336,8 @@ function request_print_tranger$1(gobj, path) {
24336
24336
  expanded: 1,
24337
24337
  lists_limit: 100,
24338
24338
  dicts_limit: 100,
24339
- path: path || ""
24339
+ path: path || "",
24340
+ __md_command__: { path: path || "" }
24340
24341
  }, gobj);
24341
24342
  if (ret) (0, _yuneta_gobj_js.log_error)(ret);
24342
24343
  }
@@ -27194,8 +27195,9 @@ function transform__treedb_value_2_table_value(gobj, col, value, row, field) {
27194
27195
  * C_YUI_FORM renders a col that is not `writable` read-only on
27195
27196
  * its own (`build_form_field_conf`), so this is the whole of
27196
27197
  * it. What must NOT follow is sending them back:
27197
- * `transform__form_record_2_treedb_record()` drops them, and
27198
- * the reason is written there.
27198
+ * `strip_read_only_cols()` drops them from every write of the
27199
+ * form (`publish_treedb_write()`), and the reason is written at
27200
+ * `col_goes_back_to_treedb()`.
27199
27201
  *
27200
27202
  * Still out: hooks (a hook is not a field of the record, it is
27201
27203
  * the children hanging off it), hidden cols, and the `_`
@@ -27988,18 +27990,61 @@ function get_schema_col(gobj, id) {
27988
27990
  return null;
27989
27991
  }
27990
27992
  /************************************************************
27993
+ * Does column `col` travel back to treedb on a write?
27994
+ *
27995
+ * The form SHOWS every field and sends back only what the topic
27996
+ * accepts: the writable cols, the fkeys (a link is edited by
27997
+ * linking) and the pkey, which is not written but is what
27998
+ * ADDRESSES the record.
27999
+ *
28000
+ * It matters because `treedb_update_node()` does not check
28001
+ * `writable` -- it writes any col it is handed -- so a read-only
28002
+ * field travelling back is written with whatever the form made of
28003
+ * it, and the fields that describe a record are exactly the ones
28004
+ * that do not survive a round trip through a widget: a `time` is an
28005
+ * integer rendered as a `datetime-local`, with no seconds, so every
28006
+ * save moved it back up to 59 s. Nothing looked wrong until the
28007
+ * stored timestamp had moved.
28008
+ *
28009
+ * `is_file` and not the type: a `file` column IS an fkey (it is
28010
+ * flagged ['fkey','file']) but answers `type: "file"`, and the write
28011
+ * goes out with `autolink`, which rebuilds the links from what the
28012
+ * record carries. Dropped, a read-only `file` column -- the one only
28013
+ * a load fills -- was UNLINKED by every save of any other field.
28014
+ ************************************************************/
28015
+ function col_goes_back_to_treedb(gobj, col) {
28016
+ let pkey = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "desc").pkey || "id";
28017
+ const field_desc = (0, _yuneta_gobj_js.treedb_get_field_desc)(col);
28018
+ if (field_desc.is_writable || field_desc.type === "fkey" || field_desc.is_file || col.id === pkey) return true;
28019
+ return false;
28020
+ }
28021
+ /************************************************************
28022
+ * The record the FORM hands over, without the columns that do
28023
+ * not go back to treedb (see col_goes_back_to_treedb()). The
28024
+ * form has already encoded the values, so only the columns are
28025
+ * taken out; keys that are not columns are left as they are.
28026
+ ************************************************************/
28027
+ function strip_read_only_cols(gobj, record) {
28028
+ let row = {};
28029
+ for (let field_name of Object.keys(record || {})) {
28030
+ let col = get_schema_col(gobj, field_name);
28031
+ if (col && !col_goes_back_to_treedb(gobj, col)) continue;
28032
+ row[field_name] = record[field_name];
28033
+ }
28034
+ return row;
28035
+ }
28036
+ /************************************************************
27991
28037
  * Convert from frontend to backend
27992
28038
  * operation: "create" "update"
27993
28039
  ************************************************************/
27994
28040
  function transform__form_record_2_treedb_record(gobj, kw, operation) {
27995
- let pkey = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "desc").pkey || "id";
28041
+ (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "desc").pkey;
27996
28042
  let row = {};
27997
28043
  for (let field_name of Object.keys(kw)) {
27998
28044
  if ((0, _yuneta_gobj_js.empty_string)(field_name)) continue;
27999
28045
  let col = get_schema_col(gobj, field_name);
28000
28046
  if (!col) continue;
28001
- const field_desc = (0, _yuneta_gobj_js.treedb_get_field_desc)(col);
28002
- if (!field_desc.is_writable && field_desc.type !== "fkey" && !field_desc.is_file && col.id !== pkey) continue;
28047
+ if (!col_goes_back_to_treedb(gobj, col)) continue;
28003
28048
  let value = kw[field_name];
28004
28049
  row[field_name] = transform__form_value_2_treedb_value(gobj, col, value, operation);
28005
28050
  }
@@ -28314,10 +28359,10 @@ function ac_edition_mode(gobj, event, kw, src) {
28314
28359
  tabulator.showColumn("_operation");
28315
28360
  tabulator.showColumn("_check_box_state_");
28316
28361
  $button_new_record.removeAttribute("disabled");
28317
- $button_paste_record.removeAttribute("disabled");
28362
+ if ($button_paste_record) $button_paste_record.removeAttribute("disabled");
28318
28363
  if (yui_selected_rows(tabulator).length) {
28319
28364
  $button_delete_record.removeAttribute("disabled");
28320
- $button_copy_record.removeAttribute("disabled");
28365
+ if ($button_copy_record) $button_copy_record.removeAttribute("disabled");
28321
28366
  }
28322
28367
  } else {
28323
28368
  $button_edit_record.classList.remove("is-primary");
@@ -28327,8 +28372,8 @@ function ac_edition_mode(gobj, event, kw, src) {
28327
28372
  tabulator.hideColumn("_check_box_state_");
28328
28373
  $button_new_record.setAttribute("disabled", true);
28329
28374
  $button_delete_record.setAttribute("disabled", true);
28330
- $button_copy_record.setAttribute("disabled", true);
28331
- $button_paste_record.setAttribute("disabled", true);
28375
+ if ($button_copy_record) $button_copy_record.setAttribute("disabled", true);
28376
+ if ($button_paste_record) $button_paste_record.setAttribute("disabled", true);
28332
28377
  }
28333
28378
  render_selection_bar(gobj);
28334
28379
  return 0;
@@ -28535,7 +28580,7 @@ function read_is_current(gobj, kw) {
28535
28580
  function publish_treedb_write(gobj, mode, record, jn_files) {
28536
28581
  const kw_write = {
28537
28582
  topic_name: (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "topic_name"),
28538
- record
28583
+ record: strip_read_only_cols(gobj, record)
28539
28584
  };
28540
28585
  if (jn_files && Object.keys(jn_files).length > 0) kw_write.record.__files__ = jn_files;
28541
28586
  (0, _yuneta_gobj_js.gobj_publish_event)(gobj, mode === "create" ? "EV_CREATE_RECORD" : "EV_UPDATE_RECORD", kw_write);
@@ -66411,7 +66456,8 @@ function request_print_tranger(gobj, path) {
66411
66456
  expanded: 1,
66412
66457
  lists_limit: 100,
66413
66458
  dicts_limit: 100,
66414
- path: path || ""
66459
+ path: path || "",
66460
+ __md_command__: { path: path || "" }
66415
66461
  }, gobj);
66416
66462
  if (ret) (0, _yuneta_gobj_js.log_error)(ret);
66417
66463
  }
@@ -24331,7 +24331,8 @@ function request_print_tranger$1(gobj, path) {
24331
24331
  expanded: 1,
24332
24332
  lists_limit: 100,
24333
24333
  dicts_limit: 100,
24334
- path: path || ""
24334
+ path: path || "",
24335
+ __md_command__: { path: path || "" }
24335
24336
  }, gobj);
24336
24337
  if (ret) log_error(ret);
24337
24338
  }
@@ -27189,8 +27190,9 @@ function transform__treedb_value_2_table_value(gobj, col, value, row, field) {
27189
27190
  * C_YUI_FORM renders a col that is not `writable` read-only on
27190
27191
  * its own (`build_form_field_conf`), so this is the whole of
27191
27192
  * it. What must NOT follow is sending them back:
27192
- * `transform__form_record_2_treedb_record()` drops them, and
27193
- * the reason is written there.
27193
+ * `strip_read_only_cols()` drops them from every write of the
27194
+ * form (`publish_treedb_write()`), and the reason is written at
27195
+ * `col_goes_back_to_treedb()`.
27194
27196
  *
27195
27197
  * Still out: hooks (a hook is not a field of the record, it is
27196
27198
  * the children hanging off it), hidden cols, and the `_`
@@ -27983,18 +27985,61 @@ function get_schema_col(gobj, id) {
27983
27985
  return null;
27984
27986
  }
27985
27987
  /************************************************************
27988
+ * Does column `col` travel back to treedb on a write?
27989
+ *
27990
+ * The form SHOWS every field and sends back only what the topic
27991
+ * accepts: the writable cols, the fkeys (a link is edited by
27992
+ * linking) and the pkey, which is not written but is what
27993
+ * ADDRESSES the record.
27994
+ *
27995
+ * It matters because `treedb_update_node()` does not check
27996
+ * `writable` -- it writes any col it is handed -- so a read-only
27997
+ * field travelling back is written with whatever the form made of
27998
+ * it, and the fields that describe a record are exactly the ones
27999
+ * that do not survive a round trip through a widget: a `time` is an
28000
+ * integer rendered as a `datetime-local`, with no seconds, so every
28001
+ * save moved it back up to 59 s. Nothing looked wrong until the
28002
+ * stored timestamp had moved.
28003
+ *
28004
+ * `is_file` and not the type: a `file` column IS an fkey (it is
28005
+ * flagged ['fkey','file']) but answers `type: "file"`, and the write
28006
+ * goes out with `autolink`, which rebuilds the links from what the
28007
+ * record carries. Dropped, a read-only `file` column -- the one only
28008
+ * a load fills -- was UNLINKED by every save of any other field.
28009
+ ************************************************************/
28010
+ function col_goes_back_to_treedb(gobj, col) {
28011
+ let pkey = gobj_read_attr(gobj, "desc").pkey || "id";
28012
+ const field_desc = treedb_get_field_desc(col);
28013
+ if (field_desc.is_writable || field_desc.type === "fkey" || field_desc.is_file || col.id === pkey) return true;
28014
+ return false;
28015
+ }
28016
+ /************************************************************
28017
+ * The record the FORM hands over, without the columns that do
28018
+ * not go back to treedb (see col_goes_back_to_treedb()). The
28019
+ * form has already encoded the values, so only the columns are
28020
+ * taken out; keys that are not columns are left as they are.
28021
+ ************************************************************/
28022
+ function strip_read_only_cols(gobj, record) {
28023
+ let row = {};
28024
+ for (let field_name of Object.keys(record || {})) {
28025
+ let col = get_schema_col(gobj, field_name);
28026
+ if (col && !col_goes_back_to_treedb(gobj, col)) continue;
28027
+ row[field_name] = record[field_name];
28028
+ }
28029
+ return row;
28030
+ }
28031
+ /************************************************************
27986
28032
  * Convert from frontend to backend
27987
28033
  * operation: "create" "update"
27988
28034
  ************************************************************/
27989
28035
  function transform__form_record_2_treedb_record(gobj, kw, operation) {
27990
- let pkey = gobj_read_attr(gobj, "desc").pkey || "id";
28036
+ gobj_read_attr(gobj, "desc").pkey;
27991
28037
  let row = {};
27992
28038
  for (let field_name of Object.keys(kw)) {
27993
28039
  if (empty_string(field_name)) continue;
27994
28040
  let col = get_schema_col(gobj, field_name);
27995
28041
  if (!col) continue;
27996
- const field_desc = treedb_get_field_desc(col);
27997
- if (!field_desc.is_writable && field_desc.type !== "fkey" && !field_desc.is_file && col.id !== pkey) continue;
28042
+ if (!col_goes_back_to_treedb(gobj, col)) continue;
27998
28043
  let value = kw[field_name];
27999
28044
  row[field_name] = transform__form_value_2_treedb_value(gobj, col, value, operation);
28000
28045
  }
@@ -28309,10 +28354,10 @@ function ac_edition_mode(gobj, event, kw, src) {
28309
28354
  tabulator.showColumn("_operation");
28310
28355
  tabulator.showColumn("_check_box_state_");
28311
28356
  $button_new_record.removeAttribute("disabled");
28312
- $button_paste_record.removeAttribute("disabled");
28357
+ if ($button_paste_record) $button_paste_record.removeAttribute("disabled");
28313
28358
  if (yui_selected_rows(tabulator).length) {
28314
28359
  $button_delete_record.removeAttribute("disabled");
28315
- $button_copy_record.removeAttribute("disabled");
28360
+ if ($button_copy_record) $button_copy_record.removeAttribute("disabled");
28316
28361
  }
28317
28362
  } else {
28318
28363
  $button_edit_record.classList.remove("is-primary");
@@ -28322,8 +28367,8 @@ function ac_edition_mode(gobj, event, kw, src) {
28322
28367
  tabulator.hideColumn("_check_box_state_");
28323
28368
  $button_new_record.setAttribute("disabled", true);
28324
28369
  $button_delete_record.setAttribute("disabled", true);
28325
- $button_copy_record.setAttribute("disabled", true);
28326
- $button_paste_record.setAttribute("disabled", true);
28370
+ if ($button_copy_record) $button_copy_record.setAttribute("disabled", true);
28371
+ if ($button_paste_record) $button_paste_record.setAttribute("disabled", true);
28327
28372
  }
28328
28373
  render_selection_bar(gobj);
28329
28374
  return 0;
@@ -28530,7 +28575,7 @@ function read_is_current(gobj, kw) {
28530
28575
  function publish_treedb_write(gobj, mode, record, jn_files) {
28531
28576
  const kw_write = {
28532
28577
  topic_name: gobj_read_str_attr(gobj, "topic_name"),
28533
- record
28578
+ record: strip_read_only_cols(gobj, record)
28534
28579
  };
28535
28580
  if (jn_files && Object.keys(jn_files).length > 0) kw_write.record.__files__ = jn_files;
28536
28581
  gobj_publish_event(gobj, mode === "create" ? "EV_CREATE_RECORD" : "EV_UPDATE_RECORD", kw_write);
@@ -66406,7 +66451,8 @@ function request_print_tranger(gobj, path) {
66406
66451
  expanded: 1,
66407
66452
  lists_limit: 100,
66408
66453
  dicts_limit: 100,
66409
- path: path || ""
66454
+ path: path || "",
66455
+ __md_command__: { path: path || "" }
66410
66456
  }, gobj);
66411
66457
  if (ret) log_error(ret);
66412
66458
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yuneta/gobj-ui",
3
- "version": "7.23.166",
3
+ "version": "7.23.168",
4
4
  "type": "module",
5
5
  "main": "dist/gobj-ui.cjs.js",
6
6
  "module": "dist/gobj-ui.es.js",
@@ -1335,7 +1335,10 @@ function request_print_tranger(gobj, path)
1335
1335
  expanded: 1,
1336
1336
  lists_limit: 100,
1337
1337
  dicts_limit: 100,
1338
- path: path || ""
1338
+ path: path || "",
1339
+ /* What comes BACK: the answer carries only this frame, and
1340
+ * without the path a drill replaced the whole document. */
1341
+ __md_command__: {path: path || ""}
1339
1342
  }, gobj);
1340
1343
  if(ret) {
1341
1344
  log_error(ret);
@@ -2182,8 +2182,9 @@ function transform__treedb_value_2_table_value(gobj, col, value, row, field)
2182
2182
  * C_YUI_FORM renders a col that is not `writable` read-only on
2183
2183
  * its own (`build_form_field_conf`), so this is the whole of
2184
2184
  * it. What must NOT follow is sending them back:
2185
- * `transform__form_record_2_treedb_record()` drops them, and
2186
- * the reason is written there.
2185
+ * `strip_read_only_cols()` drops them from every write of the
2186
+ * form (`publish_treedb_write()`), and the reason is written at
2187
+ * `col_goes_back_to_treedb()`.
2187
2188
  *
2188
2189
  * Still out: hooks (a hook is not a field of the record, it is
2189
2190
  * the children hanging off it), hidden cols, and the `_`
@@ -3203,6 +3204,61 @@ function get_schema_col(gobj, id)
3203
3204
  return null;
3204
3205
  }
3205
3206
 
3207
+ /************************************************************
3208
+ * Does column `col` travel back to treedb on a write?
3209
+ *
3210
+ * The form SHOWS every field and sends back only what the topic
3211
+ * accepts: the writable cols, the fkeys (a link is edited by
3212
+ * linking) and the pkey, which is not written but is what
3213
+ * ADDRESSES the record.
3214
+ *
3215
+ * It matters because `treedb_update_node()` does not check
3216
+ * `writable` -- it writes any col it is handed -- so a read-only
3217
+ * field travelling back is written with whatever the form made of
3218
+ * it, and the fields that describe a record are exactly the ones
3219
+ * that do not survive a round trip through a widget: a `time` is an
3220
+ * integer rendered as a `datetime-local`, with no seconds, so every
3221
+ * save moved it back up to 59 s. Nothing looked wrong until the
3222
+ * stored timestamp had moved.
3223
+ *
3224
+ * `is_file` and not the type: a `file` column IS an fkey (it is
3225
+ * flagged ['fkey','file']) but answers `type: "file"`, and the write
3226
+ * goes out with `autolink`, which rebuilds the links from what the
3227
+ * record carries. Dropped, a read-only `file` column -- the one only
3228
+ * a load fills -- was UNLINKED by every save of any other field.
3229
+ ************************************************************/
3230
+ function col_goes_back_to_treedb(gobj, col)
3231
+ {
3232
+ let desc = gobj_read_attr(gobj, "desc");
3233
+ let pkey = desc.pkey || "id";
3234
+ const field_desc = treedb_get_field_desc(col);
3235
+
3236
+ if(field_desc.is_writable || field_desc.type === "fkey" ||
3237
+ field_desc.is_file || col.id === pkey) {
3238
+ return true;
3239
+ }
3240
+ return false;
3241
+ }
3242
+
3243
+ /************************************************************
3244
+ * The record the FORM hands over, without the columns that do
3245
+ * not go back to treedb (see col_goes_back_to_treedb()). The
3246
+ * form has already encoded the values, so only the columns are
3247
+ * taken out; keys that are not columns are left as they are.
3248
+ ************************************************************/
3249
+ function strip_read_only_cols(gobj, record)
3250
+ {
3251
+ let row = {};
3252
+ for(let field_name of Object.keys(record || {})) {
3253
+ let col = get_schema_col(gobj, field_name);
3254
+ if(col && !col_goes_back_to_treedb(gobj, col)) {
3255
+ continue;
3256
+ }
3257
+ row[field_name] = record[field_name];
3258
+ }
3259
+ return row;
3260
+ }
3261
+
3206
3262
  /************************************************************
3207
3263
  * Convert from frontend to backend
3208
3264
  * operation: "create" "update"
@@ -3222,29 +3278,7 @@ function transform__form_record_2_treedb_record(gobj, kw, operation)
3222
3278
  continue;
3223
3279
  }
3224
3280
 
3225
- /* The form SHOWS every field and sends back only what the topic
3226
- * accepts: the writable cols, the fkeys (a link is edited by
3227
- * linking) and the pkey, which is not written but is what
3228
- * ADDRESSES the record.
3229
- *
3230
- * It matters because `treedb_update_node()` does not check
3231
- * `writable` -- it writes any col it is handed -- so a read-only
3232
- * field travelling back is written with whatever the form made of
3233
- * it, and the fields that describe a record are exactly the ones
3234
- * that do not survive a round trip through a widget: `t` is an
3235
- * integer rendered as a date. Nothing would look wrong until the
3236
- * stored timestamp had moved.
3237
- */
3238
- const field_desc = treedb_get_field_desc(col);
3239
- if(!field_desc.is_writable &&
3240
- field_desc.type !== "fkey" && !field_desc.is_file &&
3241
- col.id !== pkey) {
3242
- /* `is_file` and not the type: a `file` column IS an fkey (it
3243
- * is flagged ['fkey','file']) but answers `type: "file"`, and
3244
- * the write goes out with `autolink`, which rebuilds the links
3245
- * from what the record carries. Dropped here, a read-only
3246
- * `file` column -- the one only a load fills -- was UNLINKED
3247
- * by every save of any other field of its record. */
3281
+ if(!col_goes_back_to_treedb(gobj, col)) {
3248
3282
  continue;
3249
3283
  }
3250
3284
 
@@ -3792,12 +3826,17 @@ function ac_edition_mode(gobj, event, kw, src)
3792
3826
  tabulator.showColumn('_check_box_state_');
3793
3827
 
3794
3828
  $button_new_record.removeAttribute("disabled");
3795
- $button_paste_record.removeAttribute("disabled");
3829
+ /* with_copy_button / with_paste_button = false build no button */
3830
+ if($button_paste_record) {
3831
+ $button_paste_record.removeAttribute("disabled");
3832
+ }
3796
3833
 
3797
3834
  let rows = yui_selected_rows(tabulator);
3798
3835
  if (rows.length) {
3799
3836
  $button_delete_record.removeAttribute("disabled");
3800
- $button_copy_record.removeAttribute("disabled");
3837
+ if($button_copy_record) {
3838
+ $button_copy_record.removeAttribute("disabled");
3839
+ }
3801
3840
  }
3802
3841
 
3803
3842
  } else {
@@ -3813,8 +3852,12 @@ function ac_edition_mode(gobj, event, kw, src)
3813
3852
 
3814
3853
  $button_new_record.setAttribute("disabled", true);
3815
3854
  $button_delete_record.setAttribute("disabled", true);
3816
- $button_copy_record.setAttribute("disabled", true);
3817
- $button_paste_record.setAttribute("disabled", true);
3855
+ if($button_copy_record) {
3856
+ $button_copy_record.setAttribute("disabled", true);
3857
+ }
3858
+ if($button_paste_record) {
3859
+ $button_paste_record.setAttribute("disabled", true);
3860
+ }
3818
3861
  }
3819
3862
 
3820
3863
  render_selection_bar(gobj);
@@ -4136,9 +4179,11 @@ function read_is_current(gobj, kw)
4136
4179
  ************************************************************/
4137
4180
  function publish_treedb_write(gobj, mode, record, jn_files)
4138
4181
  {
4182
+ /* Both writes of the form pass here, with and without files: the
4183
+ * read-only columns it shows stay on screen and off the wire. */
4139
4184
  const kw_write = {
4140
4185
  topic_name: gobj_read_str_attr(gobj, "topic_name"),
4141
- record: record
4186
+ record: strip_read_only_cols(gobj, record)
4142
4187
  };
4143
4188
  if(jn_files && Object.keys(jn_files).length > 0) {
4144
4189
  /* Not a column: an instruction to the treedb write path,
@@ -1806,7 +1806,10 @@ function request_print_tranger(gobj, path)
1806
1806
  expanded: 1,
1807
1807
  lists_limit: 100,
1808
1808
  dicts_limit: 100,
1809
- path: path || ""
1809
+ path: path || "",
1810
+ /* What comes BACK: the answer carries only this frame, and
1811
+ * without the path a drill replaced the whole document. */
1812
+ __md_command__: {path: path || ""}
1810
1813
  }, gobj);
1811
1814
  if(ret) {
1812
1815
  log_error(ret);
@@ -93,3 +93,20 @@
93
93
  .FILE_FIELD .FILE_PREVIEW iframe.FILE_PREVIEW_MEDIA {
94
94
  min-height: 18rem;
95
95
  }
96
+
97
+ /*
98
+ * The row a file control sits in must be allowed to be NARROWER than the
99
+ * file's name. The name is one line cut with an ellipsis, but a flex item
100
+ * with `min-width: auto` -- Bulma's `.field-body` in a horizontal field,
101
+ * and the `.field` inside it -- measures its minimum with the WHOLE text,
102
+ * so a long name ("Chicago - "25 or 6 to 4" Historic Live...") widened the
103
+ * column past the form and the dialog grew a horizontal scroll. The audio
104
+ * preview, `width: 100%`, followed the column out. Measured the same in
105
+ * Firefox and Chromium: 674px where a text row is 473px.
106
+ *
107
+ * Only these rows: the other controls keep Bulma's sizing.
108
+ */
109
+ .field-body:has(.FILE_FIELD),
110
+ .field-body:has(.FILE_FIELD) > .field {
111
+ min-width: 0;
112
+ }