@saltcorn/data 0.8.6-beta.2 → 0.8.6-beta.4

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 (114) hide show
  1. package/dist/base-plugin/actions.js +1 -1
  2. package/dist/base-plugin/actions.js.map +1 -1
  3. package/dist/base-plugin/index.d.ts +5 -1
  4. package/dist/base-plugin/index.d.ts.map +1 -1
  5. package/dist/base-plugin/types.d.ts +51 -44
  6. package/dist/base-plugin/types.d.ts.map +1 -1
  7. package/dist/base-plugin/types.js +20 -12
  8. package/dist/base-plugin/types.js.map +1 -1
  9. package/dist/base-plugin/viewtemplates/edit.d.ts.map +1 -1
  10. package/dist/base-plugin/viewtemplates/edit.js +15 -5
  11. package/dist/base-plugin/viewtemplates/edit.js.map +1 -1
  12. package/dist/base-plugin/viewtemplates/feed.js +1 -1
  13. package/dist/base-plugin/viewtemplates/feed.js.map +1 -1
  14. package/dist/base-plugin/viewtemplates/filter.js +3 -3
  15. package/dist/base-plugin/viewtemplates/filter.js.map +1 -1
  16. package/dist/base-plugin/viewtemplates/list.js +3 -3
  17. package/dist/base-plugin/viewtemplates/list.js.map +1 -1
  18. package/dist/base-plugin/viewtemplates/room.js +2 -2
  19. package/dist/base-plugin/viewtemplates/room.js.map +1 -1
  20. package/dist/base-plugin/viewtemplates/show.d.ts.map +1 -1
  21. package/dist/base-plugin/viewtemplates/show.js +18 -8
  22. package/dist/base-plugin/viewtemplates/show.js.map +1 -1
  23. package/dist/base-plugin/viewtemplates/viewable_fields.d.ts +7 -4
  24. package/dist/base-plugin/viewtemplates/viewable_fields.d.ts.map +1 -1
  25. package/dist/base-plugin/viewtemplates/viewable_fields.js +113 -83
  26. package/dist/base-plugin/viewtemplates/viewable_fields.js.map +1 -1
  27. package/dist/db/fixtures.d.ts.map +1 -1
  28. package/dist/db/fixtures.js +422 -20
  29. package/dist/db/fixtures.js.map +1 -1
  30. package/dist/db/state.d.ts +1 -0
  31. package/dist/db/state.d.ts.map +1 -1
  32. package/dist/db/state.js +9 -2
  33. package/dist/db/state.js.map +1 -1
  34. package/dist/diagram/node_extract_utils.d.ts.map +1 -1
  35. package/dist/diagram/node_extract_utils.js +7 -3
  36. package/dist/diagram/node_extract_utils.js.map +1 -1
  37. package/dist/migrations/202304281224.d.ts +3 -0
  38. package/dist/migrations/202304281224.d.ts.map +1 -0
  39. package/dist/migrations/202304281224.js +117 -0
  40. package/dist/migrations/202304281224.js.map +1 -0
  41. package/dist/migrations/202305081143.d.ts +2 -0
  42. package/dist/migrations/202305081143.d.ts.map +1 -0
  43. package/dist/migrations/202305081143.js +17 -0
  44. package/dist/migrations/202305081143.js.map +1 -0
  45. package/dist/models/config.d.ts +1 -0
  46. package/dist/models/config.d.ts.map +1 -1
  47. package/dist/models/config.js +11 -4
  48. package/dist/models/config.js.map +1 -1
  49. package/dist/models/email.js +1 -1
  50. package/dist/models/field.d.ts.map +1 -1
  51. package/dist/models/field.js +21 -1
  52. package/dist/models/field.js.map +1 -1
  53. package/dist/models/file.d.ts +36 -1
  54. package/dist/models/file.d.ts.map +1 -1
  55. package/dist/models/file.js +48 -5
  56. package/dist/models/file.js.map +1 -1
  57. package/dist/models/index.d.ts +2 -1
  58. package/dist/models/index.d.ts.map +1 -1
  59. package/dist/models/layout.d.ts +1 -1
  60. package/dist/models/layout.d.ts.map +1 -1
  61. package/dist/models/layout.js +3 -1
  62. package/dist/models/layout.js.map +1 -1
  63. package/dist/models/page.js +1 -1
  64. package/dist/models/page.js.map +1 -1
  65. package/dist/models/random.js +1 -1
  66. package/dist/models/random.js.map +1 -1
  67. package/dist/models/table.d.ts +7 -1
  68. package/dist/models/table.d.ts.map +1 -1
  69. package/dist/models/table.js +22 -10
  70. package/dist/models/table.js.map +1 -1
  71. package/dist/models/user.js +1 -1
  72. package/dist/models/user.js.map +1 -1
  73. package/dist/models/view.d.ts +1 -0
  74. package/dist/models/view.d.ts.map +1 -1
  75. package/dist/models/view.js +27 -4
  76. package/dist/models/view.js.map +1 -1
  77. package/dist/models/workflow.d.ts.map +1 -1
  78. package/dist/models/workflow.js +5 -1
  79. package/dist/models/workflow.js.map +1 -1
  80. package/dist/plugin-helper.d.ts +27 -1
  81. package/dist/plugin-helper.d.ts.map +1 -1
  82. package/dist/plugin-helper.js +266 -15
  83. package/dist/plugin-helper.js.map +1 -1
  84. package/dist/tests/auth.test.js +12 -12
  85. package/dist/tests/auth.test.js.map +1 -1
  86. package/dist/tests/auxtest.test.js +132 -3
  87. package/dist/tests/auxtest.test.js.map +1 -1
  88. package/dist/tests/common_helpers.d.ts +8 -0
  89. package/dist/tests/common_helpers.d.ts.map +1 -0
  90. package/dist/tests/common_helpers.js +362 -0
  91. package/dist/tests/common_helpers.js.map +1 -0
  92. package/dist/tests/email.test.js +4 -4
  93. package/dist/tests/email.test.js.map +1 -1
  94. package/dist/tests/exact_views.test.js +10 -10
  95. package/dist/tests/exact_views.test.js.map +1 -1
  96. package/dist/tests/mocks.js +1 -1
  97. package/dist/tests/mocks.js.map +1 -1
  98. package/dist/tests/models.test.js +4 -4
  99. package/dist/tests/models.test.js.map +1 -1
  100. package/dist/tests/remote_query_helper.js +6 -6
  101. package/dist/tests/remote_query_helper.js.map +1 -1
  102. package/dist/tests/state.test.js +1 -1
  103. package/dist/tests/state.test.js.map +1 -1
  104. package/dist/tests/table.test.js +23 -8
  105. package/dist/tests/table.test.js.map +1 -1
  106. package/dist/tests/user.test.js +3 -3
  107. package/dist/tests/user.test.js.map +1 -1
  108. package/dist/tests/view.test.js +230 -10
  109. package/dist/tests/view.test.js.map +1 -1
  110. package/dist/utils.d.ts +17 -0
  111. package/dist/utils.d.ts.map +1 -1
  112. package/dist/utils.js +32 -0
  113. package/dist/utils.js.map +1 -1
  114. package/package.json +7 -7
@@ -11,7 +11,7 @@ const Trigger = require("./models/trigger");
11
11
  const { getState } = require("./db/state");
12
12
  const db = require("./db");
13
13
  const { button, a, text, i } = require("@saltcorn/markup/tags");
14
- const { applyAsync, InvalidConfiguration } = require("./utils");
14
+ const { applyAsync, InvalidConfiguration, parseRelationPath, buildRelationPath, } = require("./utils");
15
15
  const { jsexprToWhere, freeVariables, add_free_variables_to_joinfields, } = require("./models/expression");
16
16
  const { traverseSync } = require("./models/layout");
17
17
  const { isNode } = require("./utils");
@@ -82,7 +82,11 @@ const stateToQueryString = (state) => {
82
82
  return "";
83
83
  return ("?" +
84
84
  Object.entries(state)
85
- .map(([k, v]) => k === "id" ? null : `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
85
+ .map(([k, v]) => k === "id"
86
+ ? null
87
+ : `${encodeURIComponent(k)}=${encodeURIComponent(k === "_inbound_relation_path_" && typeof v !== "string"
88
+ ? queryToString(v)
89
+ : v)}`)
86
90
  .filter((s) => !!s)
87
91
  .join("&"));
88
92
  };
@@ -233,6 +237,154 @@ const calcfldViewConfig = async (fields, isEdit, nrecurse = 2) => {
233
237
  }
234
238
  return fieldViewConfigForms;
235
239
  };
240
+ /**
241
+ * helper for 'get_inbound_relation_opts'
242
+ * @param {Table} targetTbl table to check for an Inbound relation
243
+ * @param {Table} srcTable table of the top view
244
+ * @param {string[]} levelPath inbound levels already visited
245
+ * @param {*} tableCache helper cache so that we don't have to call Table.findOne() all the time
246
+ * @param {*} fieldCache helper cache so that we don't have to call Field.find() all the time
247
+ * @returns
248
+ */
249
+ const get_inbound_path_suffixes = async (targetTbl, srcTable, levelPath, tableCache, fieldCache) => {
250
+ const result = [];
251
+ // fks from targetTbl
252
+ for (const fkToRelTbl of targetTbl.getForeignKeys()) {
253
+ const relTblName = fkToRelTbl.reftable_name;
254
+ if (relTblName === srcTable.name)
255
+ continue;
256
+ // inbounds to the target of fk
257
+ const inboundFks = fieldCache[relTblName]
258
+ ? fieldCache[relTblName].filter((field) => field.table_id !== targetTbl.id &&
259
+ !levelPath.find((val) => val.tbl === targetTbl.name && val.fk === fkToRelTbl.name))
260
+ : [];
261
+ for (const inboundFk of inboundFks) {
262
+ const inboundTable = tableCache[inboundFk.table_id];
263
+ if (inboundTable) {
264
+ const relTblRefs = inboundTable
265
+ .getForeignKeys()
266
+ .filter((f) => f.reftable_name === relTblName);
267
+ // the inbound comes from 'srcTable'
268
+ if (inboundTable.id === srcTable.id) {
269
+ const levels = levelPath.map((val) => val.fk).join(".");
270
+ for (const inboundRelTblKey of relTblRefs) {
271
+ const newSuffix = `.${srcTable.name}.${inboundRelTblKey.name}.${targetTbl.name}$${fkToRelTbl.name}${levels ? `.${levels}` : ""}`;
272
+ if (result.indexOf(newSuffix) === -1) {
273
+ result.push(newSuffix);
274
+ }
275
+ }
276
+ }
277
+ else {
278
+ // check if there are refs to 'srcTable'
279
+ const srcRefs = inboundTable
280
+ .getForeignKeys()
281
+ .filter((f) => f.reftable_name === srcTable.name);
282
+ for (const srcTblRef of srcRefs) {
283
+ for (const relTblRef of relTblRefs) {
284
+ if (levelPath.length > 0) {
285
+ let levels = `${levelPath[0].tbl}$${fkToRelTbl.name}`;
286
+ for (let i = 0; i < levelPath.length; i++) {
287
+ levels = `${levels}.${levelPath[i].fk}`;
288
+ }
289
+ const newSuffix = `.${srcTable.name}.${inboundTable.name}$${srcTblRef.name}.${relTblRef.name}.` +
290
+ `${levels}`;
291
+ if (result.indexOf(newSuffix) === -1) {
292
+ result.push(newSuffix);
293
+ }
294
+ }
295
+ else {
296
+ const newSuffix = `.${srcTable.name}.${inboundTable.name}$${srcTblRef.name}.${relTblRef.name}.${targetTbl.name}$${fkToRelTbl.name}`;
297
+ if (result.indexOf(newSuffix) === -1) {
298
+ result.push(newSuffix);
299
+ }
300
+ }
301
+ }
302
+ }
303
+ }
304
+ }
305
+ }
306
+ }
307
+ return result;
308
+ };
309
+ /**
310
+ * search for relations where an in select to source is possible
311
+ * @param {Table} source
312
+ * @param {string} viewname
313
+ * @returns
314
+ */
315
+ const get_inbound_relation_opts = async (source, viewname) => {
316
+ const tableCache = {};
317
+ for (const table of await Table.find()) {
318
+ tableCache[table.id] = table;
319
+ }
320
+ const fieldCache = {};
321
+ for (const field of await Field.find()) {
322
+ if (field.reftable_name) {
323
+ if (!fieldCache[field.reftable_name])
324
+ fieldCache[field.reftable_name] = [];
325
+ fieldCache[field.reftable_name].push(field);
326
+ }
327
+ }
328
+ const result = [];
329
+ const search = async (table, path, rootTable, visited) => {
330
+ const visitedCopy = new Set(visited);
331
+ const suffixes = await get_inbound_path_suffixes(table, source, path, tableCache, fieldCache);
332
+ if (suffixes.length > 0) {
333
+ const views = await View.find_table_views_where(rootTable.id, ({ state_fields, viewrow }) => viewrow.name !== viewname &&
334
+ !state_fields.some((sf) => sf.name === "id"));
335
+ for (const suffix of suffixes) {
336
+ result.push({ path: suffix, views });
337
+ }
338
+ }
339
+ if (!visitedCopy.has(table.name)) {
340
+ visitedCopy.add(table.name);
341
+ for (const inboundFk of fieldCache[table.name] || []) {
342
+ if (inboundFk.table_id === table.id)
343
+ continue;
344
+ const inboundTbl = tableCache[inboundFk.table_id];
345
+ await search(inboundTbl, [{ tbl: inboundTbl.name, fk: inboundFk.name }, ...path], rootTable, visitedCopy);
346
+ }
347
+ }
348
+ };
349
+ // search in reverse,
350
+ // start with the target (table of the subview) to the relation source
351
+ for (const table of await Table.find()) {
352
+ const visited = new Set();
353
+ await search(table, [], table, visited);
354
+ }
355
+ return result;
356
+ };
357
+ /**
358
+ * Get all relation options where source has a key to another table (refTable)
359
+ * and refTable has a key to source.
360
+ * Otherwise one could use a OneToOneShow from refTable.
361
+ * @param {Table} source
362
+ * @param {string} viewname name of the topview
363
+ * @returns viewnames mapped to arrays of Inbound options
364
+ */
365
+ const get_inbound_self_relation_opts = async (source, viewname) => {
366
+ const fields = await Field.find({
367
+ reftable_name: source.name,
368
+ is_unique: true,
369
+ });
370
+ const result = [];
371
+ const targetFields = source.getForeignKeys();
372
+ for (const field of fields) {
373
+ const refTable = Table.findOne({ id: field.table_id });
374
+ const fromTargetToRef = targetFields.filter((field) => field.reftable_name === refTable.name);
375
+ if (fromTargetToRef.length > 0) {
376
+ const views = await View.find_table_views_where(source, ({ state_fields, viewrow }) => viewrow.name !== viewname &&
377
+ state_fields.some((sf) => sf.name === "id"));
378
+ for (const toRef of fromTargetToRef) {
379
+ result.push({
380
+ path: `.${source.name}.${toRef.name}.${field.name}`,
381
+ views,
382
+ });
383
+ }
384
+ }
385
+ }
386
+ return result;
387
+ };
236
388
  /**
237
389
  * @function
238
390
  * @param {Table|object} table
@@ -250,6 +402,7 @@ const get_link_view_opts = async (table, viewname, accept = () => true) => {
250
402
  const view_name_opts = all_views.filter(accept).map((v) => ({
251
403
  label: `${v.name} [${v.viewtemplate} ${table_id_to_name[v.table_id] || ""}]`,
252
404
  name: v.name,
405
+ table: table_id_to_name[v.table_id] || "",
253
406
  }));
254
407
  const view_relation_opts = {};
255
408
  const link_view_opts = [];
@@ -267,15 +420,20 @@ const get_link_view_opts = async (table, viewname, accept = () => true) => {
267
420
  relation: table.name,
268
421
  });
269
422
  });
270
- const link_view_opts_push = (o) => {
423
+ const link_view_opts_push_legacy = (o) => {
271
424
  if (!link_view_opts.map((v) => v.name).includes(o.name))
272
425
  push_view_option(o);
273
426
  };
427
+ const link_view_opts_push = (o) => {
428
+ if (!view_relation_opts[o.view] ||
429
+ !view_relation_opts[o.view].find(({ value }) => value === o.name))
430
+ push_view_option(o);
431
+ };
274
432
  const child_views = await get_child_views(table, viewname);
275
433
  for (const { relation, related_table, through, throughTable, views, } of child_views) {
276
434
  for (const view of views) {
277
435
  if (through && throughTable) {
278
- link_view_opts_push({
436
+ link_view_opts_push_legacy({
279
437
  view: view.name,
280
438
  name: `ChildList:${view.name}.${throughTable.name}.${through.name}.${related_table.name}.${relation.name}`,
281
439
  label: `${view.name} [${view.viewtemplate} ${related_table.name}.${relation.name}.${through.name}]`,
@@ -283,7 +441,7 @@ const get_link_view_opts = async (table, viewname, accept = () => true) => {
283
441
  });
284
442
  }
285
443
  else {
286
- link_view_opts_push({
444
+ link_view_opts_push_legacy({
287
445
  view: view.name,
288
446
  name: `ChildList:${view.name}.${related_table.name}.${relation.name}`,
289
447
  label: `${view.name} [${view.viewtemplate} ${related_table.name}.${relation.name}]`,
@@ -295,7 +453,7 @@ const get_link_view_opts = async (table, viewname, accept = () => true) => {
295
453
  const parent_views = await get_parent_views(table, viewname);
296
454
  for (const { relation, related_table, views } of parent_views) {
297
455
  for (const view of views) {
298
- link_view_opts_push({
456
+ link_view_opts_push_legacy({
299
457
  view: view.name,
300
458
  name: `ParentShow:${view.name}.${related_table.name}.${relation.name}`,
301
459
  label: `${view.name} [${view.viewtemplate} ${relation.name}.${related_table.name}]`,
@@ -306,7 +464,7 @@ const get_link_view_opts = async (table, viewname, accept = () => true) => {
306
464
  const onetoone_views = await get_onetoone_views(table, viewname);
307
465
  for (const { relation, related_table, views } of onetoone_views) {
308
466
  for (const view of views) {
309
- link_view_opts_push({
467
+ link_view_opts_push_legacy({
310
468
  view: view.name,
311
469
  name: `OneToOneShow:${view.name}.${related_table.name}.${relation.name}`,
312
470
  label: `${view.name} [${view.viewtemplate} ${related_table.name}.${relation.label}]`,
@@ -316,13 +474,35 @@ const get_link_view_opts = async (table, viewname, accept = () => true) => {
316
474
  }
317
475
  const independent_views = await View.find_all_views_where(({ state_fields }) => !state_fields.some((sf) => sf.required));
318
476
  independent_views.forEach((view) => {
319
- link_view_opts_push({
477
+ link_view_opts_push_legacy({
320
478
  view: view.name,
321
479
  label: `${view.name} [${view.viewtemplate}]`,
322
480
  name: `Independent:${view.name}`,
323
481
  relation: "None",
324
482
  });
325
483
  });
484
+ const inbound_rel_opts = await get_inbound_relation_opts(table, viewname);
485
+ for (const { path, views } of inbound_rel_opts) {
486
+ for (const view of views) {
487
+ link_view_opts_push({
488
+ view: view.name,
489
+ label: `${view.name} [${view.viewtemplate} ${table.name}]`,
490
+ name: path,
491
+ relation: path,
492
+ });
493
+ }
494
+ }
495
+ const self_inbounds = await get_inbound_self_relation_opts(table, viewname);
496
+ for (const { path, views } of self_inbounds) {
497
+ for (const view of views) {
498
+ link_view_opts_push({
499
+ view: view.name,
500
+ label: `${view.name} [${view.viewtemplate} ${table.name}]`,
501
+ name: path,
502
+ relation: path,
503
+ });
504
+ }
505
+ }
326
506
  return { link_view_opts, view_name_opts, view_relation_opts };
327
507
  };
328
508
  /**
@@ -1168,16 +1348,36 @@ const stateFieldsToQuery = ({ state, stateHash, fields, prefix = "" }) => {
1168
1348
  */
1169
1349
  // todo potentially move to utils
1170
1350
  const addOrCreateList = (container, key, x) => {
1171
- if (container[key])
1172
- container[key].push(x);
1351
+ if (container[key]) {
1352
+ if (container[key].length)
1353
+ container[key].push(x);
1354
+ else
1355
+ container[key] = [container[key], x];
1356
+ }
1173
1357
  else
1174
1358
  container[key] = [x];
1175
1359
  };
1360
+ const stringToQuery = (s) => {
1361
+ const json = JSON.parse(s);
1362
+ const { path, sourcetable } = parseRelationPath(json.relation);
1363
+ return {
1364
+ ...json,
1365
+ path,
1366
+ sourcetable,
1367
+ };
1368
+ };
1369
+ const queryToString = (query) => {
1370
+ const relObj = {
1371
+ srcId: query.srcId,
1372
+ relation: buildRelationPath(query.sourcetable, query.path),
1373
+ };
1374
+ return JSON.stringify(relObj);
1375
+ };
1176
1376
  /**
1177
1377
  * @function
1178
1378
  * @param {object} opts
1179
1379
  * @param {Field[]} opts.fields
1180
- * @param {object} opts.state missing in contract
1380
+ * @param {object} opts.state
1181
1381
  * @param {boolean} [opts.approximate = true]
1182
1382
  * @param {Table} opts.table
1183
1383
  * @returns {object}
@@ -1185,7 +1385,7 @@ const addOrCreateList = (container, key, x) => {
1185
1385
  const stateFieldsToWhere = ({ fields, state, approximate = true, table }) => {
1186
1386
  let qstate = {};
1187
1387
  Object.entries(state || {}).forEach(([k, v]) => {
1188
- if (k === "_fts" || (table?.name && k === `_fts_${table.name}`)) {
1388
+ if (k === "_fts" || (table?.name && k === `_fts_${table.santized_name}`)) {
1189
1389
  qstate["_fts"] = {
1190
1390
  searchTerm: v.replace(/\0/g, ""),
1191
1391
  fields,
@@ -1194,7 +1394,35 @@ const stateFieldsToWhere = ({ fields, state, approximate = true, table }) => {
1194
1394
  return;
1195
1395
  }
1196
1396
  const field = fields.find((fld) => fld.name === k);
1197
- if (k.startsWith("_fromdate_")) {
1397
+ if (k === "_inbound_relation_path_") {
1398
+ const queryObj = typeof v === "string" ? stringToQuery(v) : v;
1399
+ const levels = [];
1400
+ let lastTableName = queryObj.sourcetable;
1401
+ let where = null;
1402
+ for (const level of queryObj.path) {
1403
+ if (level.inboundKey) {
1404
+ levels.push({ ...level });
1405
+ lastTableName = level.table;
1406
+ if (!where)
1407
+ where = { [db.sqlsanitize(level.inboundKey)]: queryObj.srcId };
1408
+ }
1409
+ else {
1410
+ const lastTable = Table.findOne({ name: lastTableName });
1411
+ const refField = lastTable.fields.find((field) => field.name === level.fkey);
1412
+ levels.push({ table: refField.reftable_name, fkey: level.fkey });
1413
+ lastTableName = refField.reftable_name;
1414
+ if (!where)
1415
+ where = { id: queryObj.srcId };
1416
+ }
1417
+ }
1418
+ addOrCreateList(qstate, "id", {
1419
+ inSelectWithLevels: {
1420
+ joinLevels: levels,
1421
+ where,
1422
+ },
1423
+ });
1424
+ }
1425
+ else if (k.startsWith("_fromdate_")) {
1198
1426
  const datefield = db.sqlsanitize(k.replace("_fromdate_", ""));
1199
1427
  const dfield = fields.find((fld) => fld.name === datefield);
1200
1428
  if (dfield)
@@ -1221,6 +1449,9 @@ const stateFieldsToWhere = ({ fields, state, approximate = true, table }) => {
1221
1449
  else if (field && field.type.name === "String" && v && v.slugify) {
1222
1450
  qstate[k] = v;
1223
1451
  }
1452
+ else if (Array.isArray(v) && field && field.type && field.type.read) {
1453
+ qstate[k] = { or: v.map(field.type.read) };
1454
+ }
1224
1455
  else if (field &&
1225
1456
  field.type.name === "String" &&
1226
1457
  !(field.attributes && field.attributes.options) &&
@@ -1456,7 +1687,7 @@ const initial_config_all_fields = (isEdit) => async ({ table_id, exttable_name }
1456
1687
  aboves.push({
1457
1688
  type: "action",
1458
1689
  block: false,
1459
- minRole: 10,
1690
+ minRole: 100,
1460
1691
  action_name: "Save",
1461
1692
  });
1462
1693
  cfg.layout = { above: aboves };
@@ -1603,6 +1834,9 @@ const json_list_to_external_table = (get_json_list, fields0) => {
1603
1834
  getFields() {
1604
1835
  return fields;
1605
1836
  },
1837
+ getForeignKeys() {
1838
+ return fields.filter((f) => f.is_fkey && f.type !== "File");
1839
+ },
1606
1840
  getField(fnm) {
1607
1841
  return fields.find((f) => f.name === fnm);
1608
1842
  },
@@ -1610,7 +1844,7 @@ const json_list_to_external_table = (get_json_list, fields0) => {
1610
1844
  getRows,
1611
1845
  get min_role_read() {
1612
1846
  const roles = getState().getConfig("exttables_min_role_read", {});
1613
- return roles[tbl.name] || 10;
1847
+ return roles[tbl.name] || 100;
1614
1848
  },
1615
1849
  getJoinedRows(opts = {}) {
1616
1850
  const { where, ...rest } = opts;
@@ -1677,6 +1911,20 @@ const run_action_column = async ({ col, req, ...rest }) => {
1677
1911
  ...rest,
1678
1912
  });
1679
1913
  };
1914
+ /**
1915
+ * for all tables collect the foreign keys with the targets
1916
+ * should only be used as options for the saltcorn-builder
1917
+ * @returns table names as key and the fks as value
1918
+ */
1919
+ const build_schema_fk_options = async () => {
1920
+ const result = {};
1921
+ for (const table of await Table.find()) {
1922
+ result[table.name] = table.getForeignKeys().map((field) => {
1923
+ return { name: field.name, reftable_name: field.reftable_name };
1924
+ });
1925
+ }
1926
+ return result;
1927
+ };
1680
1928
  module.exports = {
1681
1929
  field_picker_fields,
1682
1930
  picked_fields_to_query,
@@ -1698,5 +1946,8 @@ module.exports = {
1698
1946
  run_action_column,
1699
1947
  json_list_to_external_table,
1700
1948
  add_free_variables_to_joinfields,
1949
+ get_inbound_relation_opts,
1950
+ get_inbound_self_relation_opts,
1951
+ build_schema_fk_options,
1701
1952
  };
1702
1953
  //# sourceMappingURL=plugin-helper.js.map