tempest-express-sdk 0.27.0 → 0.28.0
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.
- package/README.md +1 -1
- package/dist/{chunk-ADF7OHRH.js → chunk-3NS5KVHT.js} +3 -3
- package/dist/{chunk-ADF7OHRH.js.map → chunk-3NS5KVHT.js.map} +1 -1
- package/dist/cli.cjs +1 -1
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +1 -1
- package/dist/index.cjs +324 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +126 -2
- package/dist/index.d.ts +126 -2
- package/dist/index.js +324 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { z, looseBoolean, toDict, PasswordUtils } from './chunk-
|
|
2
|
-
export { PasswordUtils, VERSION, baseAppSettingsSchema, baseAppSettingsShape, baseResponseSchema, centsField, corsSettingsShape, databaseSettingsShape, looseBoolean as envBoolean, hexColorField, latitudeField, loadSettings, longitudeField, looseBoolean, nonEmptyStrField, nonNegativeFloatField, nonNegativeIntField, percentField, portField, positiveFloatField, positiveIntField, priceField, ratingField, ratioField, serverSettingsShape, slugField, toDict, z } from './chunk-
|
|
1
|
+
import { z, looseBoolean, toDict, PasswordUtils } from './chunk-3NS5KVHT.js';
|
|
2
|
+
export { PasswordUtils, VERSION, baseAppSettingsSchema, baseAppSettingsShape, baseResponseSchema, centsField, corsSettingsShape, databaseSettingsShape, looseBoolean as envBoolean, hexColorField, latitudeField, loadSettings, longitudeField, looseBoolean, nonEmptyStrField, nonNegativeFloatField, nonNegativeIntField, percentField, portField, positiveFloatField, positiveIntField, priceField, ratingField, ratioField, serverSettingsShape, slugField, toDict, z } from './chunk-3NS5KVHT.js';
|
|
3
3
|
import { AsyncLocalStorage } from 'async_hooks';
|
|
4
4
|
import { Model, column, sql, BaseRepository, RecordNotFound, detectDialect, columnsOf, NodeSqliteDriver, AsyncEngine, or, and } from 'tempest-db-js';
|
|
5
5
|
export { AsyncEngine, AsyncResult, AsyncSession, BaseRepository, Column, DeleteBuilder, InsertBuilder, Model, NoResultError, NodeSqliteDriver, PostgresDialect, RecordNotFound, SelectBuilder, SqliteDialect, SyncEngine, SyncSession, UpdateBuilder, and, belongsTo, column, columnsOf, createEngine, createSyncEngine, del, detectDialect, getDialect, hasMany, insert, join, loadRelations, not, or, parseDatabaseUrl, select, sql, update } from 'tempest-db-js';
|
|
@@ -9334,6 +9334,23 @@ function partitionTotal(partition) {
|
|
|
9334
9334
|
return partition.segments.reduce((total, segment) => total + segment.value, 0);
|
|
9335
9335
|
}
|
|
9336
9336
|
|
|
9337
|
+
// src/admin/inlines.ts
|
|
9338
|
+
function adminInline(options) {
|
|
9339
|
+
const slug = options.model.tablename;
|
|
9340
|
+
if (typeof slug !== "string" || slug === "") {
|
|
9341
|
+
throw new Error("adminInline requires a concrete model with a tablename");
|
|
9342
|
+
}
|
|
9343
|
+
return {
|
|
9344
|
+
model: options.model,
|
|
9345
|
+
slug,
|
|
9346
|
+
fkField: options.fkField,
|
|
9347
|
+
listDisplay: options.listDisplay === void 0 ? null : [...options.listDisplay],
|
|
9348
|
+
label: options.label ?? null,
|
|
9349
|
+
editable: options.editable ?? false,
|
|
9350
|
+
canDelete: options.canDelete ?? false
|
|
9351
|
+
};
|
|
9352
|
+
}
|
|
9353
|
+
|
|
9337
9354
|
// src/admin/lenses.ts
|
|
9338
9355
|
function slugify(name) {
|
|
9339
9356
|
return name.normalize("NFD").replace(/\p{M}/gu, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "lens";
|
|
@@ -9589,6 +9606,8 @@ var AdminModel = class {
|
|
|
9589
9606
|
canImport;
|
|
9590
9607
|
/** Foreign-key columns rendered as a typed search box. */
|
|
9591
9608
|
autocompleteFields;
|
|
9609
|
+
/** Related child models listed on the detail view. */
|
|
9610
|
+
inlines;
|
|
9592
9611
|
actions = /* @__PURE__ */ new Map();
|
|
9593
9612
|
slugOverride;
|
|
9594
9613
|
listDisplayOverride;
|
|
@@ -9620,6 +9639,7 @@ var AdminModel = class {
|
|
|
9620
9639
|
this.uploadStorage = options.uploadStorage ?? null;
|
|
9621
9640
|
this.canImport = options.canImport ?? false;
|
|
9622
9641
|
this.autocompleteFields = [...options.autocompleteFields ?? []];
|
|
9642
|
+
this.inlines = [...options.inlines ?? []];
|
|
9623
9643
|
if (this.uploadFields.length > 0 && this.uploadStorage === null) {
|
|
9624
9644
|
throw new Error(
|
|
9625
9645
|
`AdminModel(${this.model.tablename}).uploadFields requires an uploadStorage (e.g. LocalUploadStorage / S3UploadStorage) \u2014 without one there is nowhere to write the file.`
|
|
@@ -9898,7 +9918,9 @@ function parseFormBody(admin, body, options = {}) {
|
|
|
9898
9918
|
const data = {};
|
|
9899
9919
|
const errors = {};
|
|
9900
9920
|
const uploads = options.uploadsAsText === true ? /* @__PURE__ */ new Set() : new Set(admin.uploadFields);
|
|
9921
|
+
const only = options.only === void 0 ? null : new Set(options.only);
|
|
9901
9922
|
for (const name of admin.editableFieldNames()) {
|
|
9923
|
+
if (only !== null && !only.has(name)) continue;
|
|
9902
9924
|
const column6 = columns[name];
|
|
9903
9925
|
if (column6 === void 0) continue;
|
|
9904
9926
|
if (uploads.has(name)) continue;
|
|
@@ -12232,10 +12254,97 @@ function renderDetailPage(context, view) {
|
|
|
12232
12254
|
</div>
|
|
12233
12255
|
</header>
|
|
12234
12256
|
<dl class="tempest-admin-detail__fields">${fields}</dl>
|
|
12257
|
+
${view.inlines.map((inline) => renderInline(inline, context.session?.csrfToken ?? "", view.inlineError)).join("")}
|
|
12235
12258
|
${auditPanel}
|
|
12236
12259
|
</section>`;
|
|
12237
12260
|
return renderLayout(context, `${view.title} \xB7 ${view.identity}`, body);
|
|
12238
12261
|
}
|
|
12262
|
+
function renderInlineCell(field) {
|
|
12263
|
+
const required = field.required ? " required" : "";
|
|
12264
|
+
const name = escapeHtml(field.name);
|
|
12265
|
+
const value = escapeHtml(field.value);
|
|
12266
|
+
let control;
|
|
12267
|
+
switch (field.widget) {
|
|
12268
|
+
case "checkbox":
|
|
12269
|
+
control = `<input type="checkbox" name="${name}" value="true"${field.checked ? " checked" : ""}>`;
|
|
12270
|
+
break;
|
|
12271
|
+
case "textarea":
|
|
12272
|
+
case "json":
|
|
12273
|
+
control = `<textarea name="${name}" rows="2"${required}>${value}</textarea>`;
|
|
12274
|
+
break;
|
|
12275
|
+
case "select": {
|
|
12276
|
+
const blank = field.required ? "" : '<option value="">\u2014 none \u2014</option>';
|
|
12277
|
+
const options = field.options.map(
|
|
12278
|
+
(option) => `<option value="${escapeHtml(option.value)}"${option.value === field.value ? " selected" : ""}>${escapeHtml(option.label)}</option>`
|
|
12279
|
+
).join("");
|
|
12280
|
+
control = `<select name="${name}"${required}>${blank}${options}</select>`;
|
|
12281
|
+
break;
|
|
12282
|
+
}
|
|
12283
|
+
case "number":
|
|
12284
|
+
control = `<input type="number" name="${name}" value="${value}"${field.step !== null ? ` step="${escapeHtml(field.step)}"` : ""}${required}>`;
|
|
12285
|
+
break;
|
|
12286
|
+
case "datetime":
|
|
12287
|
+
control = `<input type="datetime-local" name="${name}" value="${value}"${required}>`;
|
|
12288
|
+
break;
|
|
12289
|
+
case "date":
|
|
12290
|
+
control = `<input type="date" name="${name}" value="${value}"${required}>`;
|
|
12291
|
+
break;
|
|
12292
|
+
case "time":
|
|
12293
|
+
control = `<input type="time" name="${name}" value="${value}"${required}>`;
|
|
12294
|
+
break;
|
|
12295
|
+
default:
|
|
12296
|
+
control = `<input type="text" name="${name}" value="${value}"${required}>`;
|
|
12297
|
+
}
|
|
12298
|
+
const error = field.error !== null ? `<small class="tempest-admin-form__field-error">${escapeHtml(field.error)}</small>` : "";
|
|
12299
|
+
return `${control}${error}`;
|
|
12300
|
+
}
|
|
12301
|
+
function renderInline(inline, csrfToken, error) {
|
|
12302
|
+
const heading = `<header class="tempest-admin-inline__header">
|
|
12303
|
+
<h2>${escapeHtml(inline.label)}${inline.total > 0 ? ` <span class="tempest-admin-inline__count">(${escapeHtml(inline.total)})</span>` : ""}</h2>
|
|
12304
|
+
${inline.addUrl !== null ? `<a class="tempest-admin-btn" href="${escapeHtml(inline.addUrl)}">Add</a>` : ""}
|
|
12305
|
+
</header>`;
|
|
12306
|
+
const more = inline.truncated ? `<p class="tempest-admin-inline__more"><em>Showing the first ${escapeHtml(inline.rows.length)} of ${escapeHtml(inline.total)}.</em></p>` : "";
|
|
12307
|
+
if (!inline.editable) {
|
|
12308
|
+
if (inline.rows.length === 0) {
|
|
12309
|
+
return `<section class="tempest-admin-inline">${heading}<p><em>No related records.</em></p></section>`;
|
|
12310
|
+
}
|
|
12311
|
+
const head2 = `<tr>${inline.columns.map((column6) => `<th>${escapeHtml(column6)}</th>`).join("")}<th></th></tr>`;
|
|
12312
|
+
const body = inline.rows.map(
|
|
12313
|
+
(row) => `<tr>${row.cells.map((cell) => `<td>${escapeHtml(cell)}</td>`).join("")}<td>${row.url === null ? "" : `<a href="${escapeHtml(row.url)}">View</a>`}</td></tr>`
|
|
12314
|
+
).join("");
|
|
12315
|
+
return `<section class="tempest-admin-inline">
|
|
12316
|
+
${heading}
|
|
12317
|
+
<div class="tempest-admin-inline__scroll">
|
|
12318
|
+
<table class="tempest-admin-inline__table">
|
|
12319
|
+
<thead>${head2}</thead>
|
|
12320
|
+
<tbody>${body}</tbody>
|
|
12321
|
+
</table>
|
|
12322
|
+
</div>
|
|
12323
|
+
${more}
|
|
12324
|
+
</section>`;
|
|
12325
|
+
}
|
|
12326
|
+
const head = `<tr>${inline.columns.map((column6) => `<th>${escapeHtml(column6)}</th>`).join("")}${inline.canDelete ? "<th>Delete</th>" : ""}</tr>`;
|
|
12327
|
+
const renderRow = (row, isNew) => `<tr${isNew ? ' class="tempest-admin-inline__new"' : ""}>${row.fields.map((field) => `<td>${renderInlineCell(field)}</td>`).join("")}${inline.canDelete ? `<td class="tempest-admin-inline__del">${isNew ? "" : `<input type="checkbox" name="row.${escapeHtml(row.key)}.__delete" value="true">`}</td>` : ""}</tr>`;
|
|
12328
|
+
const rows = inline.rows.map((row) => renderRow(row, false)).join("");
|
|
12329
|
+
const blank = inline.newRow === null ? "" : renderRow(inline.newRow, true);
|
|
12330
|
+
return `<section class="tempest-admin-inline">
|
|
12331
|
+
${heading}
|
|
12332
|
+
${error !== null ? `<p class="tempest-admin-form__error">${escapeHtml(error)}</p>` : ""}
|
|
12333
|
+
<form method="post" action="${escapeHtml(inline.formAction)}" class="tempest-admin-inline__form">
|
|
12334
|
+
<input type="hidden" name="csrf_token" value="${escapeHtml(csrfToken)}">
|
|
12335
|
+
<div class="tempest-admin-inline__scroll">
|
|
12336
|
+
<table class="tempest-admin-inline__table">
|
|
12337
|
+
<thead>${head}</thead>
|
|
12338
|
+
<tbody>${rows}${blank}</tbody>
|
|
12339
|
+
</table>
|
|
12340
|
+
</div>
|
|
12341
|
+
<div class="tempest-admin-form__actions">
|
|
12342
|
+
<button type="submit">Save ${escapeHtml(inline.label)}</button>
|
|
12343
|
+
</div>
|
|
12344
|
+
</form>
|
|
12345
|
+
${more}
|
|
12346
|
+
</section>`;
|
|
12347
|
+
}
|
|
12239
12348
|
function renderAuditPanel(audit) {
|
|
12240
12349
|
const rows = audit.fields.map(
|
|
12241
12350
|
(field) => `<dt>${escapeHtml(field.label)}</dt><dd>${field.value === "" ? "<em>\u2014</em>" : escapeHtml(field.value)}</dd>`
|
|
@@ -12424,6 +12533,7 @@ var AUTOCOMPLETE_SCRIPT = `<script>
|
|
|
12424
12533
|
})();
|
|
12425
12534
|
</script>`;
|
|
12426
12535
|
var logger2 = new JSONLogger("tempest_express_sdk.admin.router");
|
|
12536
|
+
var INLINE_ROW_LIMIT = 50;
|
|
12427
12537
|
var AUTOCOMPLETE_LIMIT = 20;
|
|
12428
12538
|
var AUDIT_HISTORY_LIMIT = 50;
|
|
12429
12539
|
var FK_OPTION_CAP = 1e3;
|
|
@@ -13040,6 +13150,8 @@ function makeAdminRouter(site, options) {
|
|
|
13040
13150
|
title: admin.verboseName(),
|
|
13041
13151
|
identity,
|
|
13042
13152
|
audit: await buildAuditView(admin, row, state.dbSession),
|
|
13153
|
+
inlines: await buildInlines(admin, row, state, identity),
|
|
13154
|
+
inlineError: null,
|
|
13043
13155
|
fields: admin.detailFieldNames().map((name) => ({ label: name, value: formatCellValue(row[name]) })),
|
|
13044
13156
|
backUrl: `${prefix}/m/${admin.slug()}`,
|
|
13045
13157
|
editUrl: await allows(state.principal, admin, AdminPermission.EDIT) ? `${prefix}/m/${admin.slug()}/${identity}/edit` : null,
|
|
@@ -13160,6 +13272,103 @@ function makeAdminRouter(site, options) {
|
|
|
13160
13272
|
res.redirect(`${prefix}/m/${admin.slug()}/${identity}?ok=updated`);
|
|
13161
13273
|
})
|
|
13162
13274
|
);
|
|
13275
|
+
router.post(
|
|
13276
|
+
`${prefix}/m/:slug/:identity/inlines/:child`,
|
|
13277
|
+
guarded(async (req, res) => {
|
|
13278
|
+
const state = await authenticate(req, res);
|
|
13279
|
+
if (state === null) return;
|
|
13280
|
+
const admin = await resolveAdmin(req, res, state);
|
|
13281
|
+
if (admin === null) return;
|
|
13282
|
+
if (!checkCsrf(req, res, state)) return;
|
|
13283
|
+
const childSlug = String(req.params.child);
|
|
13284
|
+
const inline = admin.inlines.find(
|
|
13285
|
+
(entry) => entry.slug === childSlug && entry.editable
|
|
13286
|
+
);
|
|
13287
|
+
const childAdmin = inline === void 0 ? null : site.get(childSlug);
|
|
13288
|
+
if (inline === void 0 || childAdmin === null || !await allows(state.principal, childAdmin, AdminPermission.EDIT)) {
|
|
13289
|
+
html(res, renderNotFound(context(req, state.session, state.visible)), 404);
|
|
13290
|
+
return;
|
|
13291
|
+
}
|
|
13292
|
+
const identity = String(req.params.identity);
|
|
13293
|
+
const parent = await findRow(admin, state.dbSession, identity);
|
|
13294
|
+
if (parent === null) {
|
|
13295
|
+
html(res, renderNotFound(context(req, state.session, state.visible)), 404);
|
|
13296
|
+
return;
|
|
13297
|
+
}
|
|
13298
|
+
const parentId = parent[admin.identityField];
|
|
13299
|
+
const { rows: grouped, deletions } = groupInlineSubmission(
|
|
13300
|
+
req.body
|
|
13301
|
+
);
|
|
13302
|
+
const names = inlineFieldNames(childAdmin, inline);
|
|
13303
|
+
const childRepo = childAdmin.repository(state.dbSession);
|
|
13304
|
+
const actorId = backend.principalId(state.principal);
|
|
13305
|
+
const canDelete = inline.canDelete && await allows(state.principal, childAdmin, AdminPermission.DELETE);
|
|
13306
|
+
const failed = [];
|
|
13307
|
+
let formError = null;
|
|
13308
|
+
const owned = async (key) => await childRepo.first({
|
|
13309
|
+
[childAdmin.identityField]: key,
|
|
13310
|
+
[inline.fkField]: parentId
|
|
13311
|
+
});
|
|
13312
|
+
for (const [key, values] of Object.entries(grouped)) {
|
|
13313
|
+
const isNew = key.startsWith("new");
|
|
13314
|
+
if (!isNew && canDelete && deletions.has(key)) {
|
|
13315
|
+
if (await owned(key) !== null) {
|
|
13316
|
+
await childRepo.delete({ [childAdmin.identityField]: key });
|
|
13317
|
+
}
|
|
13318
|
+
continue;
|
|
13319
|
+
}
|
|
13320
|
+
if (isNew && Object.values(values).every((value) => value.trim() === "")) {
|
|
13321
|
+
continue;
|
|
13322
|
+
}
|
|
13323
|
+
const parsed = parseFormBody(childAdmin, values, { only: names });
|
|
13324
|
+
if (Object.keys(parsed.errors).length > 0) {
|
|
13325
|
+
failed.push({ key, values, errors: parsed.errors });
|
|
13326
|
+
continue;
|
|
13327
|
+
}
|
|
13328
|
+
try {
|
|
13329
|
+
if (isNew) {
|
|
13330
|
+
stampActor(childAdmin, parsed.data, actorId, true);
|
|
13331
|
+
await childRepo.create({
|
|
13332
|
+
...parsed.data,
|
|
13333
|
+
[inline.fkField]: parentId
|
|
13334
|
+
});
|
|
13335
|
+
} else {
|
|
13336
|
+
if (await owned(key) === null) continue;
|
|
13337
|
+
stampActor(childAdmin, parsed.data, actorId, false);
|
|
13338
|
+
await childRepo.update(
|
|
13339
|
+
{ [childAdmin.identityField]: key },
|
|
13340
|
+
parsed.data
|
|
13341
|
+
);
|
|
13342
|
+
}
|
|
13343
|
+
} catch (error) {
|
|
13344
|
+
formError = describeWriteFailure(childAdmin, error);
|
|
13345
|
+
failed.push({ key, values, errors: {} });
|
|
13346
|
+
}
|
|
13347
|
+
}
|
|
13348
|
+
if (failed.length > 0) {
|
|
13349
|
+
const fresh = await findRow(admin, state.dbSession, identity) ?? parent;
|
|
13350
|
+
html(
|
|
13351
|
+
res,
|
|
13352
|
+
renderDetailPage(context(req, state.session, state.visible), {
|
|
13353
|
+
title: admin.verboseName(),
|
|
13354
|
+
identity,
|
|
13355
|
+
audit: await buildAuditView(admin, fresh, state.dbSession),
|
|
13356
|
+
inlines: await buildInlines(admin, fresh, state, identity, {
|
|
13357
|
+
[childSlug]: failed
|
|
13358
|
+
}),
|
|
13359
|
+
inlineError: formError ?? "Some inline rows could not be saved.",
|
|
13360
|
+
fields: admin.detailFieldNames().map((name) => ({ label: name, value: formatCellValue(fresh[name]) })),
|
|
13361
|
+
backUrl: `${prefix}/m/${admin.slug()}`,
|
|
13362
|
+
editUrl: await allows(state.principal, admin, AdminPermission.EDIT) ? `${prefix}/m/${admin.slug()}/${identity}/edit` : null,
|
|
13363
|
+
deleteUrl: await allows(state.principal, admin, AdminPermission.DELETE) ? `${prefix}/m/${admin.slug()}/${identity}/delete` : null
|
|
13364
|
+
}),
|
|
13365
|
+
400
|
|
13366
|
+
);
|
|
13367
|
+
return;
|
|
13368
|
+
}
|
|
13369
|
+
res.redirect(`${prefix}/m/${admin.slug()}/${identity}?ok=updated`);
|
|
13370
|
+
})
|
|
13371
|
+
);
|
|
13163
13372
|
router.post(
|
|
13164
13373
|
`${prefix}/m/:slug/:identity/delete`,
|
|
13165
13374
|
guarded(async (req, res) => {
|
|
@@ -13181,6 +13390,89 @@ function makeAdminRouter(site, options) {
|
|
|
13181
13390
|
const principal = await backend.loadPrincipal(dbSession, String(actor));
|
|
13182
13391
|
return principal === null ? String(actor) : backend.displayName(principal);
|
|
13183
13392
|
}
|
|
13393
|
+
async function buildInlines(admin, parent, state, identity, overrides = {}) {
|
|
13394
|
+
const parentId = parent[admin.identityField];
|
|
13395
|
+
const blocks = [];
|
|
13396
|
+
for (const inline of admin.inlines) {
|
|
13397
|
+
const childAdmin = site.get(inline.slug);
|
|
13398
|
+
const repository = childAdmin === null ? new BaseRepository(inline.model, state.dbSession) : childAdmin.repository(state.dbSession);
|
|
13399
|
+
const children = await repository.list({
|
|
13400
|
+
[inline.fkField]: parentId
|
|
13401
|
+
});
|
|
13402
|
+
const columns = inline.listDisplay ?? childAdmin?.listDisplayNames() ?? Object.keys(adminColumns(inline.model));
|
|
13403
|
+
const label = inline.label ?? childAdmin?.verboseNamePlural() ?? humanizeField(inline.slug);
|
|
13404
|
+
const visible = children.slice(0, INLINE_ROW_LIMIT);
|
|
13405
|
+
const editable = inline.editable && childAdmin !== null && await allows(state.principal, childAdmin, AdminPermission.EDIT);
|
|
13406
|
+
const addUrl = childAdmin !== null && await allows(state.principal, childAdmin, AdminPermission.CREATE) ? `${prefix}/m/${inline.slug}/new` : null;
|
|
13407
|
+
if (!editable || childAdmin === null) {
|
|
13408
|
+
blocks.push({
|
|
13409
|
+
label,
|
|
13410
|
+
total: children.length,
|
|
13411
|
+
columns,
|
|
13412
|
+
editable: false,
|
|
13413
|
+
canDelete: false,
|
|
13414
|
+
addUrl,
|
|
13415
|
+
formAction: "",
|
|
13416
|
+
rows: visible.map((child) => ({
|
|
13417
|
+
key: String(child[childAdmin?.identityField ?? "id"]),
|
|
13418
|
+
cells: columns.map((column6) => formatCellValue(child[column6])),
|
|
13419
|
+
fields: [],
|
|
13420
|
+
url: childAdmin === null ? null : `${prefix}/m/${inline.slug}/${String(child[childAdmin.identityField])}`
|
|
13421
|
+
})),
|
|
13422
|
+
newRow: null,
|
|
13423
|
+
truncated: children.length > visible.length
|
|
13424
|
+
});
|
|
13425
|
+
continue;
|
|
13426
|
+
}
|
|
13427
|
+
const names = inlineFieldNames(childAdmin, inline);
|
|
13428
|
+
const submitted = overrides[inline.slug];
|
|
13429
|
+
const rows = [];
|
|
13430
|
+
if (submitted !== void 0) {
|
|
13431
|
+
for (const entry of submitted) {
|
|
13432
|
+
rows.push({
|
|
13433
|
+
key: entry.key,
|
|
13434
|
+
cells: [],
|
|
13435
|
+
fields: inlineFields(
|
|
13436
|
+
childAdmin,
|
|
13437
|
+
names,
|
|
13438
|
+
entry.key,
|
|
13439
|
+
entry.values,
|
|
13440
|
+
entry.errors
|
|
13441
|
+
),
|
|
13442
|
+
url: null
|
|
13443
|
+
});
|
|
13444
|
+
}
|
|
13445
|
+
} else {
|
|
13446
|
+
for (const child of visible) {
|
|
13447
|
+
const key = String(child[childAdmin.identityField]);
|
|
13448
|
+
rows.push({
|
|
13449
|
+
key,
|
|
13450
|
+
cells: [],
|
|
13451
|
+
fields: inlineFields(childAdmin, names, key, child, {}),
|
|
13452
|
+
url: `${prefix}/m/${inline.slug}/${key}`
|
|
13453
|
+
});
|
|
13454
|
+
}
|
|
13455
|
+
}
|
|
13456
|
+
blocks.push({
|
|
13457
|
+
label,
|
|
13458
|
+
total: children.length,
|
|
13459
|
+
columns: names.map(humanizeField),
|
|
13460
|
+
editable: true,
|
|
13461
|
+
canDelete: inline.canDelete && childAdmin.canDelete,
|
|
13462
|
+
addUrl,
|
|
13463
|
+
formAction: `${prefix}/m/${admin.slug()}/${identity}/inlines/${inline.slug}`,
|
|
13464
|
+
rows,
|
|
13465
|
+
newRow: {
|
|
13466
|
+
key: "new1",
|
|
13467
|
+
cells: [],
|
|
13468
|
+
fields: inlineFields(childAdmin, names, "new1", {}, {}),
|
|
13469
|
+
url: null
|
|
13470
|
+
},
|
|
13471
|
+
truncated: children.length > visible.length
|
|
13472
|
+
});
|
|
13473
|
+
}
|
|
13474
|
+
return blocks;
|
|
13475
|
+
}
|
|
13184
13476
|
async function buildAuditView(admin, row, dbSession) {
|
|
13185
13477
|
const fields = [];
|
|
13186
13478
|
for (const name of admin.auditFieldNames()) {
|
|
@@ -13479,6 +13771,35 @@ function makeAdminRouter(site, options) {
|
|
|
13479
13771
|
}
|
|
13480
13772
|
return router;
|
|
13481
13773
|
}
|
|
13774
|
+
function groupInlineSubmission(body) {
|
|
13775
|
+
const rows = {};
|
|
13776
|
+
const deletions = /* @__PURE__ */ new Set();
|
|
13777
|
+
for (const [key, raw] of Object.entries(body)) {
|
|
13778
|
+
if (!key.startsWith("row.")) continue;
|
|
13779
|
+
const parts = key.split(".");
|
|
13780
|
+
if (parts.length !== 3) continue;
|
|
13781
|
+
const [, rowKey, field] = parts;
|
|
13782
|
+
const value = typeof raw === "string" ? raw : "";
|
|
13783
|
+
if (field === "__delete") {
|
|
13784
|
+
if (!["", "false", "off", "0", "no"].includes(value.trim().toLowerCase())) {
|
|
13785
|
+
deletions.add(rowKey);
|
|
13786
|
+
}
|
|
13787
|
+
continue;
|
|
13788
|
+
}
|
|
13789
|
+
const row = rows[rowKey] ?? {};
|
|
13790
|
+
row[field] = value;
|
|
13791
|
+
rows[rowKey] = row;
|
|
13792
|
+
}
|
|
13793
|
+
return { rows, deletions };
|
|
13794
|
+
}
|
|
13795
|
+
function inlineFieldNames(childAdmin, inline) {
|
|
13796
|
+
return childAdmin.editableFieldNames().filter(
|
|
13797
|
+
(name) => name !== inline.fkField && !childAdmin.uploadFields.includes(name) && !childAdmin.autocompleteFields.includes(name)
|
|
13798
|
+
);
|
|
13799
|
+
}
|
|
13800
|
+
function inlineFields(childAdmin, names, key, values, errors) {
|
|
13801
|
+
return buildFormFields(childAdmin, { values, errors }).filter((field) => names.includes(field.name)).map((field) => ({ ...field, name: `row.${key}.${field.name}` }));
|
|
13802
|
+
}
|
|
13482
13803
|
function flagAllows(admin, action) {
|
|
13483
13804
|
if (action === AdminPermission.CREATE) return admin.canCreate;
|
|
13484
13805
|
if (action === AdminPermission.EDIT) return admin.canEdit;
|
|
@@ -15649,6 +15970,6 @@ async function withTestDatabase(models, fn) {
|
|
|
15649
15970
|
}
|
|
15650
15971
|
}
|
|
15651
15972
|
|
|
15652
|
-
export { ADMIN_CSS, ActivationService, AdminJsonSite, AdminModel, AdminPermission, AdminSessionStore, AdminSite, AppException, AttemptThrottle, AuditAction, BaseAuditLogModel, BaseController, BaseModel, BaseOAuthClient, BaseOutboxModel, BaseService, BaseUserModel, BaseUserRefreshTokenModel, BaseUserTokenModel, CEP_PATTERN, CNPJ_PATTERN, CPF_PATTERN, CSRF_COOKIE_NAME, CSRF_HEADER_NAME, CircuitOpenError, CompositeFeatureFlagBackend, ConflictException, DEFAULT_DOCS_FAVICON, DEFAULT_LOCALE, EmailProvider, EmailUtils, EnvFeatureFlagBackend, EventStream, ExpiredTokenException, FeatureFlags, ForbiddenException, GitHubOAuthClient, GoogleOAuthClient, GracefulShutdown, HTTPClient, HTTP_500_LOG_FILE, HTTP_500_MARKER, HttpMetrics, IDEMPOTENCY_HEADER, InvalidTokenException, JSONLogger, JWTUtils, LEVEL_LOG_FILES, LocalUploadStorage, MemoryBroker, MemoryCacheManager, MemoryFeatureFlagBackend, MemoryIdempotencyStore, MemoryRateLimitStore, MemorySessionStore, MemoryThrottleBackend, MessageCatalog, MessagingHub, MetricsUtils, MfaService, MultipartLimitError, NotFoundException, OAuthError, OIDCProvider, OutboxRelay, OutboxStatus, PHONE_BR_PATTERN, PasswordResetService, REDOC_CDN_URL, REQUEST_ID_HEADER, RabbitBroker, RedisCacheManager, RedisIdempotencyStore, RedisRateLimitStore, RedisSSEBroker, RedisSessionStore, Region, RetryPolicy, S3UploadStorage, SSEBroker, ServerSentEvent, SessionService, TOTPHelper, TaskManager, TelegramProvider, TenantScopedRepository, TooManyRequestsException, TwilioSmsProvider, UF, UnauthorizedException, UserAuthService, UserModelAuthBackend, UserTokenPurpose, ValidationException, WebPushDispatcher, WebPushError, WebPushGoneError, WebSocketHub, WebhookSignatureVerifier, WhatsAppProvider, activationSchema, addLogSink, adminAction, adminColumns, adminLens, adminThemeCss, attachWebSocketHub, authResponseSchema, authSettingsShape, backupDatabase, bearerToken, bodySizeLimitMiddleware, broadcastText, buildContentDisposition, buildFormFields, buildPaginationLinkHeader, cached2 as cached, cepField, citiesByUf, cnpjField, coerceFlag, configureFileLogging, configureLogging, cpfField, cpfOrCnpjField, createApp, createOpenApiRegistry, createTestDatabase, createdByColumn, csrfMiddleware, csrfTokenMatches, cursorPaginationFilterSchema, cursorPaginationSchema, decodeCursor, defaultMessageCatalog, defineEnum, deletedAtColumn, diffSnapshots, emailSettingsShape, encodeCursor, envList, escapeHtml, filterForColumn, foreignKeyFields, foreignKeyLabel, foreignKeyTable, formatCellValue, formatFieldValue, generateCsrfToken, generateOAuthState, generateOpaqueToken, generateOpenApiDocument, getAuth, getClientIp, getConditions, getPaginationConditions, getRequestId, getState, hashOpaqueToken, humanizeField, idempotencyMiddleware, inboundMessageSchema, isColumnOptional, isMultipart, isSearchableColumn, isValidCep, isValidCity, isValidCnpj, isValidCpf, isValidCpfCnpj, isValidPhoneBr, isValidUf, jwtSettingsShape, keyByHeader, keyByIp, keyByJwtClaim, keyByJwtSubject, listStates, logEntrySchema, logSettingsShape, loginSchema, makeAdminJsonRouter, makeAdminRouter, makeAppExceptionHandler, makeAuthRouter, makeFlagGuard, makeHealthRouter, makeJwtAuthMiddleware, makeLogsRouter, makeMetricsRouter, makeSessionMiddleware, makeToolSpecRouter, makeTwilioWebhookRouter, makeUnhandledExceptionHandler, makeWhatsAppWebhookRouter, metricCard, mfaChallengeSchema, mfaCodeSchema, mfaEnrollResponseSchema, minioSettingsShape, modifyDict, mountOpenApiJson, mountRedoc, mountSwaggerUi, normalizeCep, normalizeCnpj, normalizeCpf, normalizeCpfCnpj, normalizePhoneBr, normalizeUf, notFoundHandler, onlyDigits, paginationFilterSchema, paginationSchema, parseAcceptLanguage, parseCookies, parseCsv, parseFormBody, parseMultipart, partitionTotal, passwordResetConfirmSchema, passwordResetRequestSchema, phoneBrField, prometheusMiddleware, rabbitmqSettingsShape, rateLimitMiddleware, redisSettingsShape, refreshSchema, registerExceptionHandlers, renderAuthResultPage, renderDashboardPage, renderDetailPage, renderFormPage, renderImportPage, renderLayout, renderListPage, renderLoginPage, renderMfaPage, renderPasswordResetFormPage, requestIdMiddleware, requestTracingMiddleware, requireRoles, resolveAdminTheme, resolveDownloadPath, resolveRedocBundle, runServer, runWithRequestContext, sendBytesDownload, sendFileDownload, sessionCookie, sessionSettingsShape, setRequestId, signupSchema, snapshot, sseResponse, statesByRegion, syncFilterSchema, syncPaginationSchema, tableNameFor, toUtc, tokenFromUrl, tokenPairSchema, tokenSettingsShape, trendDirection, trendPercent, ufField, updatedByColumn, uploadSettingsShape, userPublicSchema, utcnow, validateTwilioSignature, verifyOpaqueToken, webPushKeysSchema, webPushPayloadSchema, webPushSettingsShape, webPushSubscriptionSchema, webSocketSettingsShape, widgetForColumn, withTestDatabase, wrapWithSlowQueryLog, wsEnvelopeSchema };
|
|
15973
|
+
export { ADMIN_CSS, ActivationService, AdminJsonSite, AdminModel, AdminPermission, AdminSessionStore, AdminSite, AppException, AttemptThrottle, AuditAction, BaseAuditLogModel, BaseController, BaseModel, BaseOAuthClient, BaseOutboxModel, BaseService, BaseUserModel, BaseUserRefreshTokenModel, BaseUserTokenModel, CEP_PATTERN, CNPJ_PATTERN, CPF_PATTERN, CSRF_COOKIE_NAME, CSRF_HEADER_NAME, CircuitOpenError, CompositeFeatureFlagBackend, ConflictException, DEFAULT_DOCS_FAVICON, DEFAULT_LOCALE, EmailProvider, EmailUtils, EnvFeatureFlagBackend, EventStream, ExpiredTokenException, FeatureFlags, ForbiddenException, GitHubOAuthClient, GoogleOAuthClient, GracefulShutdown, HTTPClient, HTTP_500_LOG_FILE, HTTP_500_MARKER, HttpMetrics, IDEMPOTENCY_HEADER, InvalidTokenException, JSONLogger, JWTUtils, LEVEL_LOG_FILES, LocalUploadStorage, MemoryBroker, MemoryCacheManager, MemoryFeatureFlagBackend, MemoryIdempotencyStore, MemoryRateLimitStore, MemorySessionStore, MemoryThrottleBackend, MessageCatalog, MessagingHub, MetricsUtils, MfaService, MultipartLimitError, NotFoundException, OAuthError, OIDCProvider, OutboxRelay, OutboxStatus, PHONE_BR_PATTERN, PasswordResetService, REDOC_CDN_URL, REQUEST_ID_HEADER, RabbitBroker, RedisCacheManager, RedisIdempotencyStore, RedisRateLimitStore, RedisSSEBroker, RedisSessionStore, Region, RetryPolicy, S3UploadStorage, SSEBroker, ServerSentEvent, SessionService, TOTPHelper, TaskManager, TelegramProvider, TenantScopedRepository, TooManyRequestsException, TwilioSmsProvider, UF, UnauthorizedException, UserAuthService, UserModelAuthBackend, UserTokenPurpose, ValidationException, WebPushDispatcher, WebPushError, WebPushGoneError, WebSocketHub, WebhookSignatureVerifier, WhatsAppProvider, activationSchema, addLogSink, adminAction, adminColumns, adminInline, adminLens, adminThemeCss, attachWebSocketHub, authResponseSchema, authSettingsShape, backupDatabase, bearerToken, bodySizeLimitMiddleware, broadcastText, buildContentDisposition, buildFormFields, buildPaginationLinkHeader, cached2 as cached, cepField, citiesByUf, cnpjField, coerceFlag, configureFileLogging, configureLogging, cpfField, cpfOrCnpjField, createApp, createOpenApiRegistry, createTestDatabase, createdByColumn, csrfMiddleware, csrfTokenMatches, cursorPaginationFilterSchema, cursorPaginationSchema, decodeCursor, defaultMessageCatalog, defineEnum, deletedAtColumn, diffSnapshots, emailSettingsShape, encodeCursor, envList, escapeHtml, filterForColumn, foreignKeyFields, foreignKeyLabel, foreignKeyTable, formatCellValue, formatFieldValue, generateCsrfToken, generateOAuthState, generateOpaqueToken, generateOpenApiDocument, getAuth, getClientIp, getConditions, getPaginationConditions, getRequestId, getState, groupInlineSubmission, hashOpaqueToken, humanizeField, idempotencyMiddleware, inboundMessageSchema, isColumnOptional, isMultipart, isSearchableColumn, isValidCep, isValidCity, isValidCnpj, isValidCpf, isValidCpfCnpj, isValidPhoneBr, isValidUf, jwtSettingsShape, keyByHeader, keyByIp, keyByJwtClaim, keyByJwtSubject, listStates, logEntrySchema, logSettingsShape, loginSchema, makeAdminJsonRouter, makeAdminRouter, makeAppExceptionHandler, makeAuthRouter, makeFlagGuard, makeHealthRouter, makeJwtAuthMiddleware, makeLogsRouter, makeMetricsRouter, makeSessionMiddleware, makeToolSpecRouter, makeTwilioWebhookRouter, makeUnhandledExceptionHandler, makeWhatsAppWebhookRouter, metricCard, mfaChallengeSchema, mfaCodeSchema, mfaEnrollResponseSchema, minioSettingsShape, modifyDict, mountOpenApiJson, mountRedoc, mountSwaggerUi, normalizeCep, normalizeCnpj, normalizeCpf, normalizeCpfCnpj, normalizePhoneBr, normalizeUf, notFoundHandler, onlyDigits, paginationFilterSchema, paginationSchema, parseAcceptLanguage, parseCookies, parseCsv, parseFormBody, parseMultipart, partitionTotal, passwordResetConfirmSchema, passwordResetRequestSchema, phoneBrField, prometheusMiddleware, rabbitmqSettingsShape, rateLimitMiddleware, redisSettingsShape, refreshSchema, registerExceptionHandlers, renderAuthResultPage, renderDashboardPage, renderDetailPage, renderFormPage, renderImportPage, renderLayout, renderListPage, renderLoginPage, renderMfaPage, renderPasswordResetFormPage, requestIdMiddleware, requestTracingMiddleware, requireRoles, resolveAdminTheme, resolveDownloadPath, resolveRedocBundle, runServer, runWithRequestContext, sendBytesDownload, sendFileDownload, sessionCookie, sessionSettingsShape, setRequestId, signupSchema, snapshot, sseResponse, statesByRegion, syncFilterSchema, syncPaginationSchema, tableNameFor, toUtc, tokenFromUrl, tokenPairSchema, tokenSettingsShape, trendDirection, trendPercent, ufField, updatedByColumn, uploadSettingsShape, userPublicSchema, utcnow, validateTwilioSignature, verifyOpaqueToken, webPushKeysSchema, webPushPayloadSchema, webPushSettingsShape, webPushSubscriptionSchema, webSocketSettingsShape, widgetForColumn, withTestDatabase, wrapWithSlowQueryLog, wsEnvelopeSchema };
|
|
15653
15974
|
//# sourceMappingURL=index.js.map
|
|
15654
15975
|
//# sourceMappingURL=index.js.map
|