betterstart-cli 0.0.28 → 0.0.30
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/dist/assets/adapters/next/integrations/mailchimp/actions/mailchimp.ts +0 -1
- package/dist/assets/adapters/next/plugins/blog/schemas/menus.json +1 -1
- package/dist/assets/adapters/next/plugins/blog/schemas/posts.json +1 -1
- package/dist/assets/adapters/next/templates/init/admin-globals.css +1 -1
- package/dist/assets/adapters/next/templates/init/components/layouts/admin-nav-link.tsx +12 -2
- package/dist/assets/adapters/next/templates/init/components/layouts/admin-settings-sidebar.tsx +75 -0
- package/dist/assets/adapters/next/templates/init/components/layouts/admin-sidebar-nav-link.tsx +12 -2
- package/dist/assets/adapters/next/templates/init/components/layouts/admin-sidebar.tsx +2 -8
- package/dist/assets/adapters/next/templates/init/components/shared/data-table/data-grid.tsx +14 -5
- package/dist/assets/adapters/next/templates/init/components/shared/data-table/data-table.tsx +111 -112
- package/dist/assets/adapters/next/templates/init/components/shared/dev-mode/dev-mode-types.ts +4 -0
- package/dist/assets/adapters/next/templates/init/components/shared/dev-mode-integrate.tsx +1 -1
- package/dist/assets/adapters/next/templates/init/components/shared/entity-versions/entity-versions-drawer.tsx +1 -1
- package/dist/assets/adapters/next/templates/init/components/shared/media/media-url-importer.tsx +45 -47
- package/dist/assets/adapters/next/templates/init/components/shared/page-header.tsx +1 -1
- package/dist/assets/adapters/next/templates/init/data/webhook-events.ts +5 -0
- package/dist/assets/adapters/next/templates/init/hooks/use-table-utils.ts +27 -7
- package/dist/assets/adapters/next/templates/init/hooks/use-webhooks.ts +211 -0
- package/dist/assets/adapters/next/templates/init/lib/actions/audit/types.ts +2 -0
- package/dist/assets/adapters/next/templates/init/lib/actions/forms/index.ts +0 -1
- package/dist/assets/adapters/next/templates/init/lib/actions/forms/types.ts +0 -4
- package/dist/assets/adapters/next/templates/init/lib/actions/forms/upsert-form-settings.ts +0 -2
- package/dist/assets/adapters/next/templates/init/lib/actions/webhooks/create-webhook.ts +55 -0
- package/dist/assets/adapters/next/templates/init/lib/actions/webhooks/delete-webhook.ts +26 -0
- package/dist/assets/adapters/next/templates/init/lib/actions/webhooks/dispatch.ts +135 -0
- package/dist/assets/adapters/next/templates/init/lib/actions/webhooks/get-webhook-deliveries.ts +124 -0
- package/dist/assets/adapters/next/templates/init/lib/actions/webhooks/get-webhook-secret.ts +28 -0
- package/dist/assets/adapters/next/templates/init/lib/actions/webhooks/get-webhook-subscriptions.ts +32 -0
- package/dist/assets/adapters/next/templates/init/lib/actions/webhooks/get-webhooks.ts +154 -0
- package/dist/assets/adapters/next/templates/init/lib/actions/webhooks/index.ts +30 -0
- package/dist/assets/adapters/next/templates/init/lib/actions/webhooks/internal-get-active-endpoints.ts +20 -0
- package/dist/assets/adapters/next/templates/init/lib/actions/webhooks/regenerate-webhook-secret.ts +35 -0
- package/dist/assets/adapters/next/templates/init/lib/actions/webhooks/register.ts +70 -0
- package/dist/assets/adapters/next/templates/init/lib/actions/webhooks/send-test-webhook.ts +81 -0
- package/dist/assets/adapters/next/templates/init/lib/actions/webhooks/types.ts +104 -0
- package/dist/assets/adapters/next/templates/init/lib/actions/webhooks/update-webhook.ts +72 -0
- package/dist/assets/adapters/next/templates/init/lib/db/core/schema.ts +71 -2
- package/dist/assets/adapters/next/templates/init/lib/lifecycle-hooks/register.ts +2 -0
- package/dist/assets/adapters/next/templates/init/lib/lifecycle-hooks/runner.ts +3 -1
- package/dist/assets/adapters/next/templates/init/lib/lifecycle-hooks/types.ts +6 -1
- package/dist/assets/adapters/next/templates/init/pages/auth-gate-rsc.tsx +1 -1
- package/dist/assets/adapters/next/templates/init/pages/media/media-page-content.tsx +1 -1
- package/dist/assets/adapters/next/templates/init/pages/media/media-page-skeleton.tsx +1 -1
- package/dist/assets/adapters/next/templates/init/pages/settings/audit-log/audit-log-columns.tsx +150 -0
- package/dist/assets/adapters/next/templates/init/pages/settings/audit-log/audit-log-page-content.tsx +137 -0
- package/dist/assets/adapters/next/templates/init/pages/{audit-log → settings/audit-log}/audit-log-page-skeleton.tsx +1 -1
- package/dist/assets/adapters/next/templates/init/pages/settings/audit-log/audit-log-table.tsx +295 -0
- package/dist/assets/adapters/next/templates/init/pages/settings/forms/edit-form-notifications-dialog.tsx +128 -0
- package/dist/assets/adapters/next/templates/init/pages/settings/forms/forms-settings-page-content.tsx +111 -0
- package/dist/assets/adapters/next/templates/init/pages/settings/forms/forms-settings-page-skeleton.tsx +7 -0
- package/dist/assets/adapters/next/templates/init/pages/settings/forms/forms-settings-page.tsx +14 -0
- package/dist/assets/adapters/next/templates/init/pages/settings/settings-layout.tsx +10 -0
- package/dist/assets/adapters/next/templates/init/pages/settings/webhooks/delete-webhook-dialog.tsx +82 -0
- package/dist/assets/adapters/next/templates/init/pages/settings/webhooks/webhook-actions.tsx +53 -0
- package/dist/assets/adapters/next/templates/init/pages/settings/webhooks/webhook-enabled-switch.tsx +18 -0
- package/dist/assets/adapters/next/templates/init/pages/settings/webhooks/webhook-endpoint-dialog.tsx +370 -0
- package/dist/assets/adapters/next/templates/init/pages/settings/webhooks/webhooks-columns.tsx +258 -0
- package/dist/assets/adapters/next/templates/init/pages/settings/webhooks/webhooks-logs-columns.tsx +200 -0
- package/dist/assets/adapters/next/templates/init/pages/settings/webhooks/webhooks-logs-page-content.tsx +117 -0
- package/dist/assets/adapters/next/templates/init/pages/settings/webhooks/webhooks-logs-page.tsx +14 -0
- package/dist/assets/adapters/next/templates/init/pages/settings/webhooks/webhooks-logs-table.tsx +253 -0
- package/dist/assets/adapters/next/templates/init/pages/settings/webhooks/webhooks-page-content.tsx +161 -0
- package/dist/assets/adapters/next/templates/init/pages/settings/webhooks/webhooks-page-skeleton.tsx +7 -0
- package/dist/assets/adapters/next/templates/init/pages/settings/webhooks/webhooks-page.tsx +14 -0
- package/dist/assets/adapters/next/templates/init/pages/settings/webhooks/webhooks-table.tsx +264 -0
- package/dist/assets/adapters/next/templates/init/pages/users/users-page-skeleton.tsx +1 -1
- package/dist/assets/adapters/next/templates/init/pages/users/users-table.tsx +103 -109
- package/dist/assets/adapters/next/templates/init/types/webhooks.ts +7 -0
- package/dist/assets/adapters/next/templates/init/utils/webhook/signature.ts +13 -0
- package/dist/assets/shared-assets/react-admin/ui/card.tsx +1 -1
- package/dist/assets/shared-assets/react-admin/ui/drawer.tsx +2 -2
- package/dist/assets/shared-assets/react-admin/ui/input-group.tsx +3 -3
- package/dist/assets/shared-assets/react-admin/ui/sidebar.tsx +1 -1
- package/dist/cli.js +947 -620
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
- package/dist/assets/adapters/next/templates/init/lib/actions/forms/test-form-webhook.ts +0 -40
- package/dist/assets/adapters/next/templates/init/pages/audit-log/audit-log-page-content.tsx +0 -550
- package/dist/assets/adapters/next/templates/init/utils/webhook/webhook.ts +0 -28
- /package/dist/assets/adapters/next/templates/init/pages/{audit-log → settings/audit-log}/audit-log-detail-drawer.tsx +0 -0
- /package/dist/assets/adapters/next/templates/init/pages/{audit-log → settings/audit-log}/audit-log-detail-row.tsx +0 -0
- /package/dist/assets/adapters/next/templates/init/pages/{audit-log → settings/audit-log}/audit-log-page.tsx +0 -0
package/dist/cli.js
CHANGED
|
@@ -1410,16 +1410,29 @@ import path9 from "path";
|
|
|
1410
1410
|
var PG_SSL_WARNING_START = "Warning: SECURITY WARNING: The SSL modes 'prefer', 'require', and 'verify-ca' are treated as aliases for 'verify-full'.";
|
|
1411
1411
|
var PG_SSL_WARNING_END = "See https://www.postgresql.org/docs/current/libpq-ssl.html for libpq SSL mode definitions.";
|
|
1412
1412
|
var NODE_TRACE_WARNING_HINT = "(Use `node --trace-warnings";
|
|
1413
|
-
var
|
|
1413
|
+
var DRIZZLE_NOISE_PATTERNS = [
|
|
1414
1414
|
/^No config path provided, using default 'drizzle\.config\.ts'$/,
|
|
1415
1415
|
/^Reading config file '.+drizzle\.config\.ts'$/,
|
|
1416
|
-
/^Using 'pg' driver for database querying
|
|
1416
|
+
/^Using 'pg' driver for database querying$/,
|
|
1417
|
+
/^\[.\] Pulling schema from database\.\.\.$/u,
|
|
1418
|
+
/^\[.\] Changes applied$/u
|
|
1417
1419
|
];
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
+
var SUPPRESSIBLE_LINE_STARTS = [
|
|
1421
|
+
"No config path provided",
|
|
1422
|
+
"Reading config file '",
|
|
1423
|
+
"Using 'pg' driver",
|
|
1424
|
+
"(node:",
|
|
1425
|
+
"["
|
|
1426
|
+
];
|
|
1427
|
+
var ANSI_ESCAPE_PATTERN = /\u001B\[[0-9;]*[A-Za-z]/g;
|
|
1428
|
+
function resolveDrizzlePushStdio(interactive) {
|
|
1429
|
+
return interactive ? ["inherit", "pipe", "pipe"] : "pipe";
|
|
1430
|
+
}
|
|
1431
|
+
function stripAnsi(text7) {
|
|
1432
|
+
return text7.replace(ANSI_ESCAPE_PATTERN, "").replaceAll("\r", "");
|
|
1420
1433
|
}
|
|
1421
|
-
function
|
|
1422
|
-
const text7 = line.
|
|
1434
|
+
function shouldSuppressOutputLine(line, state) {
|
|
1435
|
+
const text7 = stripAnsi(line).trim();
|
|
1423
1436
|
if (state.suppressNextTraceHint) {
|
|
1424
1437
|
state.suppressNextTraceHint = false;
|
|
1425
1438
|
if (text7.startsWith(NODE_TRACE_WARNING_HINT)) {
|
|
@@ -1437,20 +1450,20 @@ function shouldSuppressWarningLine(line, state) {
|
|
|
1437
1450
|
}
|
|
1438
1451
|
return true;
|
|
1439
1452
|
}
|
|
1440
|
-
return
|
|
1441
|
-
}
|
|
1442
|
-
function shouldSuppressDrizzleConfigBannerLine(line) {
|
|
1443
|
-
const text7 = line.trim();
|
|
1444
|
-
return DRIZZLE_CONFIG_BANNER_PATTERNS.some((pattern) => pattern.test(text7));
|
|
1445
|
-
}
|
|
1446
|
-
function shouldSuppressOutputLine(line, state) {
|
|
1447
|
-
return shouldSuppressWarningLine(line, state) || shouldSuppressDrizzleConfigBannerLine(line);
|
|
1453
|
+
return DRIZZLE_NOISE_PATTERNS.some((pattern) => pattern.test(text7));
|
|
1448
1454
|
}
|
|
1449
|
-
function
|
|
1455
|
+
function filterNoiseLines(output, state) {
|
|
1450
1456
|
const lines = output.match(/[^\n]*\n|[^\n]+/g) ?? [];
|
|
1451
1457
|
return lines.filter((line) => !shouldSuppressOutputLine(line, state)).join("");
|
|
1452
1458
|
}
|
|
1453
|
-
function
|
|
1459
|
+
function couldBecomeSuppressible(partial, state) {
|
|
1460
|
+
if (state.suppressingPgSslWarning || state.suppressNextTraceHint) {
|
|
1461
|
+
return true;
|
|
1462
|
+
}
|
|
1463
|
+
const text7 = stripAnsi(partial);
|
|
1464
|
+
return SUPPRESSIBLE_LINE_STARTS.some((start) => text7.startsWith(start) || start.startsWith(text7));
|
|
1465
|
+
}
|
|
1466
|
+
function createDrizzleNoiseFilter(forward) {
|
|
1454
1467
|
const state = {
|
|
1455
1468
|
suppressingPgSslWarning: false,
|
|
1456
1469
|
suppressNextTraceHint: false
|
|
@@ -1460,24 +1473,27 @@ function createPgConnectionStringSslWarningFilter(write) {
|
|
|
1460
1473
|
write(chunk) {
|
|
1461
1474
|
buffer += chunk;
|
|
1462
1475
|
const lastNewlineIndex = buffer.lastIndexOf("\n");
|
|
1463
|
-
if (lastNewlineIndex
|
|
1464
|
-
|
|
1476
|
+
if (lastNewlineIndex !== -1) {
|
|
1477
|
+
const complete = buffer.slice(0, lastNewlineIndex + 1);
|
|
1478
|
+
buffer = buffer.slice(lastNewlineIndex + 1);
|
|
1479
|
+
const filtered = filterNoiseLines(complete, state);
|
|
1480
|
+
if (filtered) {
|
|
1481
|
+
forward(filtered);
|
|
1482
|
+
}
|
|
1465
1483
|
}
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
if (filtered) {
|
|
1470
|
-
write(filtered);
|
|
1484
|
+
if (buffer && !couldBecomeSuppressible(buffer, state)) {
|
|
1485
|
+
forward(buffer);
|
|
1486
|
+
buffer = "";
|
|
1471
1487
|
}
|
|
1472
1488
|
},
|
|
1473
1489
|
end() {
|
|
1474
1490
|
if (!buffer) {
|
|
1475
1491
|
return;
|
|
1476
1492
|
}
|
|
1477
|
-
const filtered =
|
|
1493
|
+
const filtered = filterNoiseLines(buffer, state);
|
|
1478
1494
|
buffer = "";
|
|
1479
1495
|
if (filtered) {
|
|
1480
|
-
|
|
1496
|
+
forward(filtered);
|
|
1481
1497
|
}
|
|
1482
1498
|
}
|
|
1483
1499
|
};
|
|
@@ -1487,20 +1503,20 @@ function runDrizzlePush(cwd, options = {}) {
|
|
|
1487
1503
|
const drizzleBin = path9.join(cwd, "node_modules", ".bin", "drizzle-kit");
|
|
1488
1504
|
const child = spawn2(drizzleBin, ["push", "--force"], {
|
|
1489
1505
|
cwd,
|
|
1490
|
-
stdio: resolveDrizzlePushStdio(options.
|
|
1506
|
+
stdio: resolveDrizzlePushStdio(options.interactive),
|
|
1491
1507
|
env: { ...process.env }
|
|
1492
1508
|
});
|
|
1493
1509
|
let stdout = "";
|
|
1494
1510
|
let stderr = "";
|
|
1495
|
-
const stderrFilter =
|
|
1496
|
-
if (options.
|
|
1511
|
+
const stderrFilter = createDrizzleNoiseFilter((chunk) => {
|
|
1512
|
+
if (options.interactive) {
|
|
1497
1513
|
process.stderr.write(chunk);
|
|
1498
1514
|
return;
|
|
1499
1515
|
}
|
|
1500
1516
|
stderr += chunk;
|
|
1501
1517
|
});
|
|
1502
|
-
const stdoutFilter =
|
|
1503
|
-
if (options.
|
|
1518
|
+
const stdoutFilter = createDrizzleNoiseFilter((chunk) => {
|
|
1519
|
+
if (options.interactive) {
|
|
1504
1520
|
process.stdout.write(chunk);
|
|
1505
1521
|
return;
|
|
1506
1522
|
}
|
|
@@ -1515,7 +1531,7 @@ function runDrizzlePush(cwd, options = {}) {
|
|
|
1515
1531
|
child.on("close", (code, signal) => {
|
|
1516
1532
|
stdoutFilter.end();
|
|
1517
1533
|
stderrFilter.end();
|
|
1518
|
-
if (options.
|
|
1534
|
+
if (options.interactive) {
|
|
1519
1535
|
if (code === 0) {
|
|
1520
1536
|
resolve({ success: true, error: null });
|
|
1521
1537
|
return;
|
|
@@ -1733,7 +1749,7 @@ async function runPostGenerate(cwd, schemaName, options = {}) {
|
|
|
1733
1749
|
} else {
|
|
1734
1750
|
console.log("\n Running drizzle-kit push...");
|
|
1735
1751
|
try {
|
|
1736
|
-
const pushResult = await runDrizzlePush(cwd, {
|
|
1752
|
+
const pushResult = await runDrizzlePush(cwd, { interactive: true });
|
|
1737
1753
|
if (!pushResult.success) {
|
|
1738
1754
|
throw new Error(pushResult.error ?? "drizzle-kit push failed");
|
|
1739
1755
|
}
|
|
@@ -2856,6 +2872,8 @@ function resolveProjectPaths(config) {
|
|
|
2856
2872
|
const adminTypesDir = path14.posix.join(adminDir, "types");
|
|
2857
2873
|
const adminNavigationFile = path14.posix.join(adminDir, "data", "navigation.ts");
|
|
2858
2874
|
const adminNavigationDir = path14.posix.join(adminDir, "data", "navigation");
|
|
2875
|
+
const adminWebhookEventsFile = path14.posix.join(adminDir, "data", "webhook-events.ts");
|
|
2876
|
+
const adminWebhookEventsDir = path14.posix.join(adminDir, "data", "webhook-events");
|
|
2859
2877
|
const adminActionsDir = path14.posix.join(adminDir, "lib", "actions");
|
|
2860
2878
|
return {
|
|
2861
2879
|
adminDir,
|
|
@@ -2872,6 +2890,8 @@ function resolveProjectPaths(config) {
|
|
|
2872
2890
|
adminTypesNavigationFile: path14.posix.join(adminTypesDir, "navigation.ts"),
|
|
2873
2891
|
adminNavigationFile,
|
|
2874
2892
|
adminNavigationDir,
|
|
2893
|
+
adminWebhookEventsFile,
|
|
2894
|
+
adminWebhookEventsDir,
|
|
2875
2895
|
adminActionsDir,
|
|
2876
2896
|
adminEmailTemplatesDir: path14.posix.join(adminDir, "components", "email-templates"),
|
|
2877
2897
|
adminHooksDir: path14.posix.join(adminDir, "hooks")
|
|
@@ -6322,6 +6342,22 @@ function lifecycleHookContextExample(event, schemaName, input, data, schemaType
|
|
|
6322
6342
|
if (schemaType === "form") {
|
|
6323
6343
|
context.schemaType = "form";
|
|
6324
6344
|
}
|
|
6345
|
+
if (event === "beforeRestore" || event === "afterRestore") {
|
|
6346
|
+
context.entityId = SAMPLE_UUID;
|
|
6347
|
+
context.changedFields = [];
|
|
6348
|
+
context.metadata = { restoredFromVersion: 2 };
|
|
6349
|
+
if (phase === "after") {
|
|
6350
|
+
context.data = data;
|
|
6351
|
+
}
|
|
6352
|
+
return createExample("Context", context);
|
|
6353
|
+
}
|
|
6354
|
+
if (event === "beforeReorder" || event === "afterReorder") {
|
|
6355
|
+
context.changedFields = ["sortOrder"];
|
|
6356
|
+
if (phase === "after") {
|
|
6357
|
+
context.data = { order: [{ id: SAMPLE_UUID, sortOrder: 0 }] };
|
|
6358
|
+
}
|
|
6359
|
+
return createExample("Context", context);
|
|
6360
|
+
}
|
|
6325
6361
|
if (event !== "beforeCreate" && event !== "afterCreate") {
|
|
6326
6362
|
context.entityId = SAMPLE_UUID;
|
|
6327
6363
|
}
|
|
@@ -6348,7 +6384,11 @@ function buildEntityDevModeLifecycleHooks(schema, adminImportAlias) {
|
|
|
6348
6384
|
"beforeUpdate",
|
|
6349
6385
|
"afterUpdate",
|
|
6350
6386
|
"beforeDelete",
|
|
6351
|
-
"afterDelete"
|
|
6387
|
+
"afterDelete",
|
|
6388
|
+
"beforeRestore",
|
|
6389
|
+
"afterRestore",
|
|
6390
|
+
"beforeReorder",
|
|
6391
|
+
"afterReorder"
|
|
6352
6392
|
];
|
|
6353
6393
|
if (schema.actions?.draft === true) {
|
|
6354
6394
|
events.push("beforePublish", "afterPublish", "beforeUnpublish", "afterUnpublish");
|
|
@@ -6896,7 +6936,7 @@ function generatePageSkeleton(pascal, label) {
|
|
|
6896
6936
|
return `export function ${pascal}SubmissionsPageSkeleton() {
|
|
6897
6937
|
return (
|
|
6898
6938
|
<div className="flex items-center justify-center h-48">
|
|
6899
|
-
<div className="text-muted-foreground">Loading ${label}
|
|
6939
|
+
<div className="text-muted-foreground">Loading ${label}\u2026</div>
|
|
6900
6940
|
</div>
|
|
6901
6941
|
)
|
|
6902
6942
|
}
|
|
@@ -7059,7 +7099,7 @@ ${deleteTransition}${bulkDeleteHandler}
|
|
|
7059
7099
|
<div className="flex items-center gap-1">
|
|
7060
7100
|
<${devModeIntegrateButtonExportName} initialSettings={initialSettings} />${exportButton}
|
|
7061
7101
|
<Button variant="outline" asChild>
|
|
7062
|
-
<Link href="${adminRoutePath}/forms
|
|
7102
|
+
<Link href="${adminRoutePath}/settings/forms">
|
|
7063
7103
|
<Settings className="size-3.5" />
|
|
7064
7104
|
Settings
|
|
7065
7105
|
</Link>
|
|
@@ -7105,199 +7145,6 @@ ${bulkDeleteActions}
|
|
|
7105
7145
|
`;
|
|
7106
7146
|
}
|
|
7107
7147
|
|
|
7108
|
-
// adapters/next/generators/form-admin/admin-settings-page.ts
|
|
7109
|
-
function generateSettingsPage(pascal, kebab) {
|
|
7110
|
-
return `import { getFormSettings } from '@admin/actions/forms'
|
|
7111
|
-
import { ${pascal}SettingsPageContent } from './settings-page-content'
|
|
7112
|
-
|
|
7113
|
-
export default async function ${pascal}SettingsPage() {
|
|
7114
|
-
const settings = await getFormSettings('${kebab}')
|
|
7115
|
-
|
|
7116
|
-
return <${pascal}SettingsPageContent initialSettings={settings} />
|
|
7117
|
-
}
|
|
7118
|
-
`;
|
|
7119
|
-
}
|
|
7120
|
-
function generateSettingsPageContent(pascal, kebab, label) {
|
|
7121
|
-
return `'use client'
|
|
7122
|
-
|
|
7123
|
-
import {
|
|
7124
|
-
testFormWebhook,
|
|
7125
|
-
type FormSettingsData,
|
|
7126
|
-
upsertFormSettings,
|
|
7127
|
-
} from '@admin/actions/forms'
|
|
7128
|
-
import { PageHeader } from '@admin/components/shared/page-header'
|
|
7129
|
-
import { Button } from '@admin/components/ui/button'
|
|
7130
|
-
import {
|
|
7131
|
-
Form,
|
|
7132
|
-
FormControl,
|
|
7133
|
-
FormDescription,
|
|
7134
|
-
FormField,
|
|
7135
|
-
FormItem,
|
|
7136
|
-
FormLabel,
|
|
7137
|
-
} from '@admin/components/ui/form'
|
|
7138
|
-
import { Input } from '@admin/components/ui/input'
|
|
7139
|
-
import { Switch } from '@admin/components/ui/switch'
|
|
7140
|
-
import { Textarea } from '@admin/components/ui/textarea'
|
|
7141
|
-
import { LoaderCircle } from 'lucide-react'
|
|
7142
|
-
import * as React from 'react'
|
|
7143
|
-
import { useForm } from 'react-hook-form'
|
|
7144
|
-
import { toast } from 'sonner'
|
|
7145
|
-
|
|
7146
|
-
interface ${pascal}SettingsPageContentProps {
|
|
7147
|
-
initialSettings: FormSettingsData | null
|
|
7148
|
-
}
|
|
7149
|
-
|
|
7150
|
-
interface ${pascal}SettingsFormValues {
|
|
7151
|
-
notificationEmails: string
|
|
7152
|
-
webhookUrl: string
|
|
7153
|
-
webhookEnabled: boolean
|
|
7154
|
-
}
|
|
7155
|
-
|
|
7156
|
-
export function ${pascal}SettingsPageContent({
|
|
7157
|
-
initialSettings,
|
|
7158
|
-
}: ${pascal}SettingsPageContentProps) {
|
|
7159
|
-
const form = useForm<${pascal}SettingsFormValues>({
|
|
7160
|
-
defaultValues: {
|
|
7161
|
-
notificationEmails: initialSettings?.notificationEmails ?? '',
|
|
7162
|
-
webhookUrl: initialSettings?.webhookUrl ?? '',
|
|
7163
|
-
webhookEnabled: initialSettings?.webhookEnabled ?? false,
|
|
7164
|
-
},
|
|
7165
|
-
})
|
|
7166
|
-
const [isSaving, startSaveTransition] = React.useTransition()
|
|
7167
|
-
const [isTesting, startTestTransition] = React.useTransition()
|
|
7168
|
-
const webhookUrl = form.watch('webhookUrl')
|
|
7169
|
-
const webhookEnabled = form.watch('webhookEnabled')
|
|
7170
|
-
|
|
7171
|
-
const handleSave = (values: ${pascal}SettingsFormValues) => {
|
|
7172
|
-
startSaveTransition(async () => {
|
|
7173
|
-
const result = await upsertFormSettings('${kebab}', {
|
|
7174
|
-
notificationEmails: values.notificationEmails || null,
|
|
7175
|
-
webhookUrl: values.webhookUrl || null,
|
|
7176
|
-
webhookEnabled: values.webhookEnabled,
|
|
7177
|
-
})
|
|
7178
|
-
if (result.success) {
|
|
7179
|
-
toast.success('Settings saved successfully')
|
|
7180
|
-
} else {
|
|
7181
|
-
toast.error(result.error || 'Failed to save settings')
|
|
7182
|
-
}
|
|
7183
|
-
})
|
|
7184
|
-
}
|
|
7185
|
-
|
|
7186
|
-
const handleTestWebhook = () => {
|
|
7187
|
-
startTestTransition(async () => {
|
|
7188
|
-
const result = await testFormWebhook('${kebab}')
|
|
7189
|
-
if (result.success) {
|
|
7190
|
-
toast.success('Test webhook sent successfully')
|
|
7191
|
-
} else {
|
|
7192
|
-
toast.error(result.error || 'Failed to send test webhook')
|
|
7193
|
-
}
|
|
7194
|
-
})
|
|
7195
|
-
}
|
|
7196
|
-
|
|
7197
|
-
return (
|
|
7198
|
-
<>
|
|
7199
|
-
<PageHeader title="${label} Settings" />
|
|
7200
|
-
<Form {...form}>
|
|
7201
|
-
<form
|
|
7202
|
-
onSubmit={form.handleSubmit(handleSave)}
|
|
7203
|
-
className="space-y-6 rounded-sm border p-6 mx-6 mt-6"
|
|
7204
|
-
>
|
|
7205
|
-
<FormField
|
|
7206
|
-
control={form.control}
|
|
7207
|
-
name="notificationEmails"
|
|
7208
|
-
render={({ field }) => (
|
|
7209
|
-
<FormItem>
|
|
7210
|
-
<FormLabel>Notification Emails</FormLabel>
|
|
7211
|
-
<FormControl>
|
|
7212
|
-
<Textarea
|
|
7213
|
-
placeholder="email@example.com, another@example.com"
|
|
7214
|
-
rows={3}
|
|
7215
|
-
{...field}
|
|
7216
|
-
/>
|
|
7217
|
-
</FormControl>
|
|
7218
|
-
<FormDescription>
|
|
7219
|
-
Comma-separated list of email addresses to notify on new submissions.
|
|
7220
|
-
</FormDescription>
|
|
7221
|
-
</FormItem>
|
|
7222
|
-
)}
|
|
7223
|
-
/>
|
|
7224
|
-
|
|
7225
|
-
<div className="space-y-4 border-t pt-6">
|
|
7226
|
-
<FormField
|
|
7227
|
-
control={form.control}
|
|
7228
|
-
name="webhookUrl"
|
|
7229
|
-
render={({ field }) => (
|
|
7230
|
-
<FormItem>
|
|
7231
|
-
<FormLabel>Webhook URL</FormLabel>
|
|
7232
|
-
<FormControl>
|
|
7233
|
-
<Input
|
|
7234
|
-
type="url"
|
|
7235
|
-
placeholder="https://hooks.example.com/endpoint"
|
|
7236
|
-
{...field}
|
|
7237
|
-
/>
|
|
7238
|
-
</FormControl>
|
|
7239
|
-
<FormDescription>
|
|
7240
|
-
Receive a POST request with form data on each submission.
|
|
7241
|
-
</FormDescription>
|
|
7242
|
-
</FormItem>
|
|
7243
|
-
)}
|
|
7244
|
-
/>
|
|
7245
|
-
|
|
7246
|
-
<FormField
|
|
7247
|
-
control={form.control}
|
|
7248
|
-
name="webhookEnabled"
|
|
7249
|
-
render={({ field }) => (
|
|
7250
|
-
<FormItem className="flex flex-row items-center space-x-2 space-y-0">
|
|
7251
|
-
<FormControl>
|
|
7252
|
-
<Switch
|
|
7253
|
-
checked={field.value}
|
|
7254
|
-
onCheckedChange={field.onChange}
|
|
7255
|
-
/>
|
|
7256
|
-
</FormControl>
|
|
7257
|
-
<FormLabel>Enable Webhook</FormLabel>
|
|
7258
|
-
</FormItem>
|
|
7259
|
-
)}
|
|
7260
|
-
/>
|
|
7261
|
-
|
|
7262
|
-
{webhookUrl && webhookEnabled && (
|
|
7263
|
-
<Button
|
|
7264
|
-
type="button"
|
|
7265
|
-
variant="outline"
|
|
7266
|
-
onClick={handleTestWebhook}
|
|
7267
|
-
disabled={isTesting}
|
|
7268
|
-
>
|
|
7269
|
-
{isTesting ? (
|
|
7270
|
-
<>
|
|
7271
|
-
<LoaderCircle className="animate-spin" />
|
|
7272
|
-
Sending...
|
|
7273
|
-
</>
|
|
7274
|
-
) : (
|
|
7275
|
-
'Test Webhook'
|
|
7276
|
-
)}
|
|
7277
|
-
</Button>
|
|
7278
|
-
)}
|
|
7279
|
-
</div>
|
|
7280
|
-
|
|
7281
|
-
<div className="border-t pt-6">
|
|
7282
|
-
<Button type="submit" disabled={isSaving}>
|
|
7283
|
-
{isSaving ? (
|
|
7284
|
-
<>
|
|
7285
|
-
<LoaderCircle className="animate-spin" />
|
|
7286
|
-
Saving...
|
|
7287
|
-
</>
|
|
7288
|
-
) : (
|
|
7289
|
-
'Save Settings'
|
|
7290
|
-
)}
|
|
7291
|
-
</Button>
|
|
7292
|
-
</div>
|
|
7293
|
-
</form>
|
|
7294
|
-
</Form>
|
|
7295
|
-
</>
|
|
7296
|
-
)
|
|
7297
|
-
}
|
|
7298
|
-
`;
|
|
7299
|
-
}
|
|
7300
|
-
|
|
7301
7148
|
// adapters/next/generators/form-admin/admin-submission-drawer.ts
|
|
7302
7149
|
function generateSubmissionDrawer(pascal, kebab, fields, label, includeDynamic, _actionImportPath) {
|
|
7303
7150
|
const fieldItems = fields.filter((f) => f.name).map((f) => {
|
|
@@ -7428,7 +7275,7 @@ export function ${pascal}SubmissionDrawer({
|
|
|
7428
7275
|
</DrawerHeader>
|
|
7429
7276
|
<ScrollArea className="min-h-0 flex-1">
|
|
7430
7277
|
{isPending ? (
|
|
7431
|
-
<div className="p-4 text-sm text-muted-foreground">Loading submission
|
|
7278
|
+
<div className="p-4 text-sm text-muted-foreground">Loading submission\u2026</div>
|
|
7432
7279
|
) : error ? (
|
|
7433
7280
|
<div className="p-4 text-sm text-destructive">
|
|
7434
7281
|
Error loading submission: {error.message}
|
|
@@ -7468,7 +7315,6 @@ import {
|
|
|
7468
7315
|
DataGridRow
|
|
7469
7316
|
} from '@admin/components/shared/data-table/data-grid'
|
|
7470
7317
|
import { DataTablePagination } from '@admin/components/shared/data-table/data-table-pagination'
|
|
7471
|
-
import { Card, CardContent } from '@admin/components/ui/card'
|
|
7472
7318
|
import { use${pascal}Submissions } from '@admin/hooks/use-${kebab}-form'
|
|
7473
7319
|
import { useTableUtils } from '@admin/hooks/use-table-utils'
|
|
7474
7320
|
import {
|
|
@@ -7602,108 +7448,104 @@ export function ${pascal}SubmissionsTable<TValue>({
|
|
|
7602
7448
|
|
|
7603
7449
|
return (
|
|
7604
7450
|
<div className={cn("flex flex-col gap-6 pt-px pb-2 h-full", className)}>
|
|
7605
|
-
<
|
|
7606
|
-
|
|
7607
|
-
|
|
7608
|
-
<
|
|
7609
|
-
{
|
|
7610
|
-
|
|
7611
|
-
|
|
7612
|
-
|
|
7613
|
-
|
|
7614
|
-
|
|
7615
|
-
|
|
7616
|
-
|
|
7617
|
-
|
|
7618
|
-
|
|
7619
|
-
|
|
7620
|
-
'text-center': meta?.align === 'center',
|
|
7621
|
-
'text-right': meta?.align === 'right'
|
|
7622
|
-
})}
|
|
7623
|
-
data-column-id={header.column.id}
|
|
7624
|
-
onMouseEnter={() => setHoveredColumnId(header.column.id)}
|
|
7625
|
-
onMouseLeave={() => setHoveredColumnId((current) => (current === header.column.id ? null : current))}
|
|
7626
|
-
>
|
|
7627
|
-
{header.isPlaceholder
|
|
7628
|
-
? null
|
|
7629
|
-
: flexRender(header.column.columnDef.header, header.getContext())}
|
|
7630
|
-
{canResizeColumn ? (
|
|
7631
|
-
<button
|
|
7632
|
-
type="button"
|
|
7633
|
-
aria-label={\`Resize \${resizeLabel} column\`}
|
|
7634
|
-
className="group/resize-handle absolute right-0 top-0 z-10 flex h-full w-5 cursor-col-resize touch-none select-none items-center justify-center text-muted-foreground opacity-0 transition-opacity hover:text-foreground focus-visible:text-foreground focus-visible:opacity-100 focus-visible:outline-none group-focus-within/resize-header:opacity-100 data-[column-hovered=true]:opacity-100 data-[resizing=true]:opacity-100"
|
|
7635
|
-
data-resize-handle
|
|
7636
|
-
data-column-hovered={hoveredColumnId === header.column.id ? 'true' : 'false'}
|
|
7637
|
-
data-resizing={header.column.getIsResizing() ? 'true' : 'false'}
|
|
7638
|
-
onDoubleClick={resetColumnSizingToContainer}
|
|
7639
|
-
onMouseDown={header.getResizeHandler()}
|
|
7640
|
-
onTouchStart={header.getResizeHandler()}
|
|
7641
|
-
>
|
|
7642
|
-
<GripVertical aria-hidden="true" className={cn('size-3.5', { 'text-ring': header.column.getIsResizing() })} />
|
|
7643
|
-
</button>
|
|
7644
|
-
) : null}
|
|
7645
|
-
</DataGridHead>
|
|
7646
|
-
)
|
|
7647
|
-
})}
|
|
7648
|
-
</DataGridRow>
|
|
7649
|
-
))}
|
|
7650
|
-
</DataGridHeader>
|
|
7651
|
-
<DataGridBody>
|
|
7652
|
-
{isPending ? (
|
|
7653
|
-
<DataGridRow>
|
|
7654
|
-
<DataGridCell className="flex h-24 items-center justify-center text-center" style={{ gridColumn: '1 / -1' }}>
|
|
7655
|
-
<div className="text-muted-foreground">Loading ${label} submissions...</div>
|
|
7656
|
-
</DataGridCell>
|
|
7657
|
-
</DataGridRow>
|
|
7658
|
-
) : error ? (
|
|
7659
|
-
<DataGridRow>
|
|
7660
|
-
<DataGridCell className="flex h-24 items-center justify-center text-center" style={{ gridColumn: '1 / -1' }}>
|
|
7661
|
-
<div className="text-destructive">Error loading ${label} submissions: {error.message}</div>
|
|
7662
|
-
</DataGridCell>
|
|
7663
|
-
</DataGridRow>
|
|
7664
|
-
) : table.getRowModel().rows?.length ? (
|
|
7665
|
-
table.getRowModel().rows.map((row) => (
|
|
7666
|
-
<DataGridRow
|
|
7667
|
-
key={row.id}
|
|
7668
|
-
data-state={row.getIsSelected() ? 'selected' : undefined}
|
|
7669
|
-
className="cursor-pointer hover:bg-muted/50"
|
|
7670
|
-
onClick={(e) => {
|
|
7671
|
-
const target = e.target as HTMLElement
|
|
7672
|
-
if (!e.currentTarget.contains(target)) return
|
|
7673
|
-
if (target.closest('button, a, input, [role="checkbox"]')) return
|
|
7674
|
-
onViewSubmission(row.original.id)
|
|
7675
|
-
}}
|
|
7676
|
-
>
|
|
7677
|
-
{row.getVisibleCells().map((cell) => {
|
|
7678
|
-
const meta = cell.column.columnDef.meta as Record<string, unknown> | undefined
|
|
7679
|
-
return (
|
|
7680
|
-
<DataGridCell
|
|
7681
|
-
key={cell.id}
|
|
7682
|
-
className={cn({
|
|
7683
|
-
'text-center': meta?.align === 'center',
|
|
7684
|
-
'text-right': meta?.align === 'right'
|
|
7685
|
-
})}
|
|
7686
|
-
data-column-id={cell.column.id}
|
|
7687
|
-
onMouseEnter={() => setHoveredColumnId(cell.column.id)}
|
|
7688
|
-
onMouseLeave={() => setHoveredColumnId((current) => (current === cell.column.id ? null : current))}
|
|
7689
|
-
>
|
|
7690
|
-
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
|
7691
|
-
</DataGridCell>
|
|
7692
|
-
)
|
|
7451
|
+
<DataGrid containerClassName="min-h-0 flex-1" containerRef={tableContainerRef} gridTemplateColumns={gridTemplateColumns} style={{ width: table.getTotalSize() }}>
|
|
7452
|
+
<DataGridHeader>
|
|
7453
|
+
{table.getHeaderGroups().map((headerGroup) => (
|
|
7454
|
+
<DataGridRow key={headerGroup.id}>
|
|
7455
|
+
{headerGroup.headers.map((header, headerIndex) => {
|
|
7456
|
+
const meta = header.column.columnDef.meta as Record<string, unknown> | undefined
|
|
7457
|
+
const resizeLabel = typeof header.column.columnDef.header === 'string' ? header.column.columnDef.header : header.column.id
|
|
7458
|
+
const nextHeader = headerGroup.headers[headerIndex + 1]
|
|
7459
|
+
const canResizeColumn = header.column.getCanResize() && nextHeader?.column.getCanResize() === true
|
|
7460
|
+
return (
|
|
7461
|
+
<DataGridHead
|
|
7462
|
+
key={header.id}
|
|
7463
|
+
className={cn('group/resize-header relative overflow-hidden', {
|
|
7464
|
+
'text-center': meta?.align === 'center',
|
|
7465
|
+
'text-right': meta?.align === 'right'
|
|
7693
7466
|
})}
|
|
7694
|
-
|
|
7695
|
-
|
|
7696
|
-
|
|
7697
|
-
|
|
7698
|
-
|
|
7699
|
-
|
|
7700
|
-
|
|
7701
|
-
|
|
7702
|
-
|
|
7703
|
-
|
|
7704
|
-
|
|
7705
|
-
|
|
7706
|
-
|
|
7467
|
+
data-column-id={header.column.id}
|
|
7468
|
+
onMouseEnter={() => setHoveredColumnId(header.column.id)}
|
|
7469
|
+
onMouseLeave={() => setHoveredColumnId((current) => (current === header.column.id ? null : current))}
|
|
7470
|
+
>
|
|
7471
|
+
{header.isPlaceholder
|
|
7472
|
+
? null
|
|
7473
|
+
: flexRender(header.column.columnDef.header, header.getContext())}
|
|
7474
|
+
{canResizeColumn ? (
|
|
7475
|
+
<button
|
|
7476
|
+
type="button"
|
|
7477
|
+
aria-label={\`Resize \${resizeLabel} column\`}
|
|
7478
|
+
className="group/resize-handle absolute right-0 top-0 z-10 flex h-full w-5 cursor-col-resize touch-none select-none items-center justify-center text-muted-foreground opacity-0 transition-opacity hover:text-foreground focus-visible:text-foreground focus-visible:opacity-100 focus-visible:outline-none group-focus-within/resize-header:opacity-100 data-[column-hovered=true]:opacity-100 data-[resizing=true]:opacity-100"
|
|
7479
|
+
data-resize-handle
|
|
7480
|
+
data-column-hovered={hoveredColumnId === header.column.id ? 'true' : 'false'}
|
|
7481
|
+
data-resizing={header.column.getIsResizing() ? 'true' : 'false'}
|
|
7482
|
+
onDoubleClick={resetColumnSizingToContainer}
|
|
7483
|
+
onMouseDown={header.getResizeHandler()}
|
|
7484
|
+
onTouchStart={header.getResizeHandler()}
|
|
7485
|
+
>
|
|
7486
|
+
<GripVertical aria-hidden="true" className={cn('size-3.5', { 'text-ring': header.column.getIsResizing() })} />
|
|
7487
|
+
</button>
|
|
7488
|
+
) : null}
|
|
7489
|
+
</DataGridHead>
|
|
7490
|
+
)
|
|
7491
|
+
})}
|
|
7492
|
+
</DataGridRow>
|
|
7493
|
+
))}
|
|
7494
|
+
</DataGridHeader>
|
|
7495
|
+
<DataGridBody>
|
|
7496
|
+
{isPending ? (
|
|
7497
|
+
<DataGridRow>
|
|
7498
|
+
<DataGridCell className="flex h-24 items-center justify-center text-center" style={{ gridColumn: '1 / -1' }}>
|
|
7499
|
+
<div className="text-muted-foreground">Loading ${label} submissions\u2026</div>
|
|
7500
|
+
</DataGridCell>
|
|
7501
|
+
</DataGridRow>
|
|
7502
|
+
) : error ? (
|
|
7503
|
+
<DataGridRow>
|
|
7504
|
+
<DataGridCell className="flex h-24 items-center justify-center text-center" style={{ gridColumn: '1 / -1' }}>
|
|
7505
|
+
<div className="text-destructive">Error loading ${label} submissions: {error.message}</div>
|
|
7506
|
+
</DataGridCell>
|
|
7507
|
+
</DataGridRow>
|
|
7508
|
+
) : table.getRowModel().rows?.length ? (
|
|
7509
|
+
table.getRowModel().rows.map((row) => (
|
|
7510
|
+
<DataGridRow
|
|
7511
|
+
key={row.id}
|
|
7512
|
+
data-state={row.getIsSelected() ? 'selected' : undefined}
|
|
7513
|
+
className="cursor-pointer hover:bg-muted/50"
|
|
7514
|
+
onClick={(e) => {
|
|
7515
|
+
const target = e.target as HTMLElement
|
|
7516
|
+
if (!e.currentTarget.contains(target)) return
|
|
7517
|
+
if (target.closest('button, a, input, [role="checkbox"]')) return
|
|
7518
|
+
onViewSubmission(row.original.id)
|
|
7519
|
+
}}
|
|
7520
|
+
>
|
|
7521
|
+
{row.getVisibleCells().map((cell) => {
|
|
7522
|
+
const meta = cell.column.columnDef.meta as Record<string, unknown> | undefined
|
|
7523
|
+
return (
|
|
7524
|
+
<DataGridCell
|
|
7525
|
+
key={cell.id}
|
|
7526
|
+
className={cn({
|
|
7527
|
+
'text-center': meta?.align === 'center',
|
|
7528
|
+
'text-right': meta?.align === 'right'
|
|
7529
|
+
})}
|
|
7530
|
+
data-column-id={cell.column.id}
|
|
7531
|
+
onMouseEnter={() => setHoveredColumnId(cell.column.id)}
|
|
7532
|
+
onMouseLeave={() => setHoveredColumnId((current) => (current === cell.column.id ? null : current))}
|
|
7533
|
+
>
|
|
7534
|
+
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
|
7535
|
+
</DataGridCell>
|
|
7536
|
+
)
|
|
7537
|
+
})}
|
|
7538
|
+
</DataGridRow>
|
|
7539
|
+
))
|
|
7540
|
+
) : (
|
|
7541
|
+
<DataGridRow>
|
|
7542
|
+
<DataGridCell className="flex h-24 items-center justify-center text-center" style={{ gridColumn: '1 / -1' }}>
|
|
7543
|
+
No ${label} submissions found.
|
|
7544
|
+
</DataGridCell>
|
|
7545
|
+
</DataGridRow>
|
|
7546
|
+
)}
|
|
7547
|
+
</DataGridBody>
|
|
7548
|
+
</DataGrid>
|
|
7707
7549
|
|
|
7708
7550
|
{shouldShowPagination ? (
|
|
7709
7551
|
<DataTablePagination
|
|
@@ -7812,14 +7654,6 @@ function generateFormAdminPages(schema, pagesDir, options) {
|
|
|
7812
7654
|
hasDynamicFields(schema),
|
|
7813
7655
|
actionImportPath
|
|
7814
7656
|
)
|
|
7815
|
-
),
|
|
7816
|
-
createGeneratedFile(
|
|
7817
|
-
`${pagesDir}/forms/${kebab}/settings/page.tsx`,
|
|
7818
|
-
generateSettingsPage(pascal, kebab)
|
|
7819
|
-
),
|
|
7820
|
-
createGeneratedFile(
|
|
7821
|
-
`${pagesDir}/forms/${kebab}/settings/settings-page-content.tsx`,
|
|
7822
|
-
generateSettingsPageContent(pascal, kebab, schema.label)
|
|
7823
7657
|
)
|
|
7824
7658
|
]
|
|
7825
7659
|
};
|
|
@@ -8227,7 +8061,6 @@ import { ${tableName} } from '@admin/db/schema'
|
|
|
8227
8061
|
import { getFormSettings } from '@admin/actions/forms'
|
|
8228
8062
|
import { sendFormEmails } from '@admin/actions/email/form-delivery'
|
|
8229
8063
|
import { getTouchedFieldNames } from '@admin/utils/audit/audit'
|
|
8230
|
-
import { sendWebhook } from '@admin/utils/webhook/webhook'
|
|
8231
8064
|
import { ${cacheInvalidationFn} } from 'next/cache'
|
|
8232
8065
|
${mailchimpImport}
|
|
8233
8066
|
import { CACHE_TAG, CACHE_TAG_BY_ID } from './types'
|
|
@@ -8268,16 +8101,7 @@ export async function create${pascal}Submission(
|
|
|
8268
8101
|
submitterEmail: ${submitterEmailField ? `data.${submitterEmailField}` : "null"},
|
|
8269
8102
|
submissionData: { ...data },
|
|
8270
8103
|
submittedAt: created${pascal}Submission.submittedAt,
|
|
8271
|
-
})
|
|
8272
|
-
|
|
8273
|
-
if (settings?.webhookEnabled && settings?.webhookUrl) {
|
|
8274
|
-
sendWebhook(settings.webhookUrl, {
|
|
8275
|
-
form_name: '${formName}',
|
|
8276
|
-
submission_id: created${pascal}Submission.id,
|
|
8277
|
-
...data,
|
|
8278
|
-
submitted_at: created${pascal}Submission.submittedAt,
|
|
8279
|
-
})
|
|
8280
|
-
}${mailchimpCall}
|
|
8104
|
+
})${mailchimpCall}
|
|
8281
8105
|
|
|
8282
8106
|
${cacheInvalidationFn}(CACHE_TAG)
|
|
8283
8107
|
${cacheInvalidationFn}(CACHE_TAG_BY_ID(created${pascal}Submission.id))
|
|
@@ -8792,6 +8616,58 @@ function namespaceGeneratedFiles(files, namespace) {
|
|
|
8792
8616
|
}));
|
|
8793
8617
|
}
|
|
8794
8618
|
|
|
8619
|
+
// adapters/next/generators/webhook-events.ts
|
|
8620
|
+
var NO_WEBHOOK_SCHEMAS = /* @__PURE__ */ new Set(["settings"]);
|
|
8621
|
+
function renderExtract(schemaName, kind, label, events, settingsKey) {
|
|
8622
|
+
const lines = [
|
|
8623
|
+
` schema: '${schemaName}'`,
|
|
8624
|
+
` kind: '${kind}'`,
|
|
8625
|
+
` label: ${JSON.stringify(label)}`,
|
|
8626
|
+
` events: [${events.map((event) => `'${event}'`).join(", ")}]`
|
|
8627
|
+
];
|
|
8628
|
+
if (settingsKey) {
|
|
8629
|
+
lines.push(` settingsKey: '${settingsKey}'`);
|
|
8630
|
+
}
|
|
8631
|
+
return `import type { WebhookEventSource } from '@admin/types/webhooks'
|
|
8632
|
+
|
|
8633
|
+
export const ${toCamelCase(schemaName)}WebhookEvents: WebhookEventSource = {
|
|
8634
|
+
${lines.join(",\n")}
|
|
8635
|
+
}
|
|
8636
|
+
`;
|
|
8637
|
+
}
|
|
8638
|
+
function updateWebhookEvents(schema, webhookEventsDir, kind) {
|
|
8639
|
+
if (NO_WEBHOOK_SCHEMAS.has(schema.name)) {
|
|
8640
|
+
return { files: [] };
|
|
8641
|
+
}
|
|
8642
|
+
const events = kind === "single" ? [`${schema.name}.updated`] : [
|
|
8643
|
+
`${schema.name}.created`,
|
|
8644
|
+
`${schema.name}.updated`,
|
|
8645
|
+
`${schema.name}.deleted`,
|
|
8646
|
+
...schema.actions?.draft === true ? [`${schema.name}.published`, `${schema.name}.unpublished`] : [],
|
|
8647
|
+
`${schema.name}.restored`,
|
|
8648
|
+
`${schema.name}.reordered`
|
|
8649
|
+
];
|
|
8650
|
+
return {
|
|
8651
|
+
files: [
|
|
8652
|
+
createGeneratedFile(
|
|
8653
|
+
`${webhookEventsDir}/${schema.name}.ts`,
|
|
8654
|
+
renderExtract(schema.name, kind, schema.label, events)
|
|
8655
|
+
)
|
|
8656
|
+
]
|
|
8657
|
+
};
|
|
8658
|
+
}
|
|
8659
|
+
function updateFormWebhookEvents(schema, webhookEventsDir) {
|
|
8660
|
+
const kebabName = toKebabCase(schema.name);
|
|
8661
|
+
return {
|
|
8662
|
+
files: [
|
|
8663
|
+
createGeneratedFile(
|
|
8664
|
+
`${webhookEventsDir}/${schema.name}.ts`,
|
|
8665
|
+
renderExtract(schema.name, "form", schema.label, [`form.${kebabName}.submitted`], kebabName)
|
|
8666
|
+
)
|
|
8667
|
+
]
|
|
8668
|
+
};
|
|
8669
|
+
}
|
|
8670
|
+
|
|
8795
8671
|
// adapters/next/generators/form-pipeline/pipeline.ts
|
|
8796
8672
|
function runFormPipeline(schema, cwd, config, options = {}) {
|
|
8797
8673
|
const paths = resolveProjectPaths(config);
|
|
@@ -8831,6 +8707,10 @@ function runFormPipeline(schema, cwd, config, options = {}) {
|
|
|
8831
8707
|
{
|
|
8832
8708
|
name: "Navigation",
|
|
8833
8709
|
run: () => updateFormNavigation(schema, paths.adminNavigationDir, namespacedOptions).files
|
|
8710
|
+
},
|
|
8711
|
+
{
|
|
8712
|
+
name: "Webhook events",
|
|
8713
|
+
run: () => updateFormWebhookEvents(schema, paths.adminWebhookEventsDir).files
|
|
8834
8714
|
}
|
|
8835
8715
|
];
|
|
8836
8716
|
for (let i = 0; i < steps.length; i++) {
|
|
@@ -9839,6 +9719,13 @@ function buildRestoreManyToManyStatements(ctx) {
|
|
|
9839
9719
|
}
|
|
9840
9720
|
function genRestoreContent(ctx) {
|
|
9841
9721
|
const kebabSingular = toKebabCase(ctx.singular);
|
|
9722
|
+
const restoreContext = lifecycleContext(
|
|
9723
|
+
ctx.plural,
|
|
9724
|
+
`,
|
|
9725
|
+
entityId: versionRow.entityId,
|
|
9726
|
+
changedFields: [],
|
|
9727
|
+
metadata: { restoredFromVersion: versionRow.version }`
|
|
9728
|
+
);
|
|
9842
9729
|
const snapshotImport = ctx.hasM2M ? `build${ctx.Singular}VersionSnapshotWithRelationships` : `build${ctx.Singular}VersionSnapshot`;
|
|
9843
9730
|
const currentSnapshot = ctx.hasM2M ? `await build${ctx.Singular}VersionSnapshotWithRelationships(currentRow as unknown as ${ctx.Singular}, tx)` : `build${ctx.Singular}VersionSnapshot(currentRow as unknown as ${ctx.Singular})`;
|
|
9844
9731
|
const dbImports = [
|
|
@@ -9864,6 +9751,7 @@ import {
|
|
|
9864
9751
|
build${ctx.Singular}RestoreData,
|
|
9865
9752
|
${snapshotImport}
|
|
9866
9753
|
} from './helpers'
|
|
9754
|
+
${lifecycleHookImport()}
|
|
9867
9755
|
import type { ${ctx.Singular}UpdateResult, ${ctx.Singular} } from './types'
|
|
9868
9756
|
|
|
9869
9757
|
export async function restore${ctx.Singular}Version(
|
|
@@ -9885,6 +9773,9 @@ export async function restore${ctx.Singular}Version(
|
|
|
9885
9773
|
|
|
9886
9774
|
const versionData = versionRow.data as Record<string, unknown>
|
|
9887
9775
|
const restoreData = build${ctx.Singular}RestoreData(versionData)
|
|
9776
|
+
const auditRequestMetadata = await getAuditRequestMetadata()
|
|
9777
|
+
const lifecycleContext = ${restoreContext}
|
|
9778
|
+
${beforeHook("beforeRestore", "lifecycleContext")}
|
|
9888
9779
|
|
|
9889
9780
|
const result = await db.transaction(async (tx) => {
|
|
9890
9781
|
const [currentRow] = await tx
|
|
@@ -9916,6 +9807,13 @@ ${restoreM2M}
|
|
|
9916
9807
|
${ctx.cacheInvalidationFn}(${ctx.camelPlural}CacheTags.byId(versionRow.entityId))
|
|
9917
9808
|
${ctx.cacheInvalidationFn}(entityVersionsCacheTags.for('${ctx.plural}', versionRow.entityId))
|
|
9918
9809
|
const restored${ctx.Singular} = await get${ctx.Singular}ById(versionRow.entityId)
|
|
9810
|
+
${afterHook(
|
|
9811
|
+
"afterRestore",
|
|
9812
|
+
`{
|
|
9813
|
+
...lifecycleContext,
|
|
9814
|
+
data: (restored${ctx.Singular} ?? result[0]) as unknown as Record<string, unknown>
|
|
9815
|
+
}`
|
|
9816
|
+
)}
|
|
9919
9817
|
|
|
9920
9818
|
return {
|
|
9921
9819
|
success: true,
|
|
@@ -10128,14 +10026,20 @@ export async function delete${ctx.Singular}(id: string): Promise<${ctx.Singular}
|
|
|
10128
10026
|
${beforeHook("beforeDelete", "lifecycleContext")}
|
|
10129
10027
|
|
|
10130
10028
|
try {
|
|
10131
|
-
await db.transaction(async (tx) => {
|
|
10029
|
+
const [deletedRow] = await db.transaction(async (tx) => {
|
|
10132
10030
|
await deleteEntityVersions(tx, '${ctx.plural}', [id])
|
|
10133
|
-
|
|
10031
|
+
return tx.delete(${ctx.tableVar}).where(eq(${ctx.tableVar}.id, id)).returning()
|
|
10134
10032
|
})
|
|
10135
10033
|
${ctx.cacheInvalidationFn}(${ctx.camelPlural}CacheTags.all)
|
|
10136
10034
|
${ctx.cacheInvalidationFn}(${ctx.camelPlural}CacheTags.byId(id))
|
|
10137
10035
|
${ctx.cacheInvalidationFn}(entityVersionsCacheTags.for('${ctx.plural}', id))
|
|
10138
|
-
${afterHook(
|
|
10036
|
+
${afterHook(
|
|
10037
|
+
"afterDelete",
|
|
10038
|
+
`{
|
|
10039
|
+
...lifecycleContext,
|
|
10040
|
+
data: deletedRow as unknown as Record<string, unknown> | undefined
|
|
10041
|
+
}`
|
|
10042
|
+
)}
|
|
10139
10043
|
return { success: true }
|
|
10140
10044
|
} catch (error) {
|
|
10141
10045
|
console.error('Error deleting ${ctx.singular}:', error)
|
|
@@ -10179,17 +10083,26 @@ export async function deleteBulk${ctx.Plural}(ids: string[]): Promise<${ctx.Sing
|
|
|
10179
10083
|
}
|
|
10180
10084
|
|
|
10181
10085
|
try {
|
|
10182
|
-
await db.transaction(async (tx) => {
|
|
10086
|
+
const deletedRows = await db.transaction(async (tx) => {
|
|
10183
10087
|
await deleteEntityVersions(tx, '${ctx.plural}', ids)
|
|
10184
|
-
|
|
10088
|
+
return tx.delete(${ctx.tableVar}).where(inArray(${ctx.tableVar}.id, ids)).returning()
|
|
10185
10089
|
})
|
|
10090
|
+
const deletedRowsById = new Map(
|
|
10091
|
+
deletedRows.map((row) => [row.id, row as unknown as Record<string, unknown>])
|
|
10092
|
+
)
|
|
10186
10093
|
${ctx.cacheInvalidationFn}(${ctx.camelPlural}CacheTags.all)
|
|
10187
10094
|
for (const id of ids) {
|
|
10188
10095
|
${ctx.cacheInvalidationFn}(${ctx.camelPlural}CacheTags.byId(id))
|
|
10189
10096
|
${ctx.cacheInvalidationFn}(entityVersionsCacheTags.for('${ctx.plural}', id))
|
|
10190
10097
|
}
|
|
10191
10098
|
for (const lifecycleContext of lifecycleContexts) {
|
|
10192
|
-
${afterHook(
|
|
10099
|
+
${afterHook(
|
|
10100
|
+
"afterDelete",
|
|
10101
|
+
`{
|
|
10102
|
+
...lifecycleContext,
|
|
10103
|
+
data: deletedRowsById.get(lifecycleContext.entityId)
|
|
10104
|
+
}`
|
|
10105
|
+
)}
|
|
10193
10106
|
}
|
|
10194
10107
|
return { success: true }
|
|
10195
10108
|
} catch (error) {
|
|
@@ -10200,6 +10113,8 @@ export async function deleteBulk${ctx.Plural}(ids: string[]): Promise<${ctx.Sing
|
|
|
10200
10113
|
`;
|
|
10201
10114
|
}
|
|
10202
10115
|
function genBulkSortOrderContent(ctx) {
|
|
10116
|
+
const reorderContext = lifecycleContext(ctx.plural, `,
|
|
10117
|
+
changedFields: ['sortOrder']`);
|
|
10203
10118
|
return `'use server'
|
|
10204
10119
|
|
|
10205
10120
|
import db from '@admin/db'
|
|
@@ -10208,15 +10123,20 @@ import { ${ctx.tableVar} } from '@admin/db/schema'
|
|
|
10208
10123
|
import { asc, eq, notInArray } from 'drizzle-orm'
|
|
10209
10124
|
import { ${ctx.cacheInvalidationFn} } from 'next/cache'
|
|
10210
10125
|
import { ${ctx.camelPlural}CacheTags } from './types'
|
|
10126
|
+
${lifecycleHookImport()}
|
|
10211
10127
|
|
|
10212
10128
|
export async function bulkUpdate${ctx.Plural}SortOrder(
|
|
10213
10129
|
updates: Array<{ id: string; sortOrder: number }>
|
|
10214
10130
|
): Promise<{ success: boolean; error?: string }> {
|
|
10215
|
-
await requireRole([UserRole.ADMIN, UserRole.EDITOR])
|
|
10131
|
+
const actor = await requireRole([UserRole.ADMIN, UserRole.EDITOR])
|
|
10132
|
+
if (updates.length === 0) return { success: true }
|
|
10216
10133
|
|
|
10217
|
-
|
|
10218
|
-
|
|
10134
|
+
const now = new Date().toISOString()
|
|
10135
|
+
const auditRequestMetadata = await getAuditRequestMetadata()
|
|
10136
|
+
const lifecycleContext = ${reorderContext}
|
|
10137
|
+
${beforeHook("beforeReorder", "lifecycleContext")}
|
|
10219
10138
|
|
|
10139
|
+
try {
|
|
10220
10140
|
// Sort the provided items by their new position
|
|
10221
10141
|
const sorted = [...updates].sort((a, b) => a.sortOrder - b.sortOrder)
|
|
10222
10142
|
const updatedIds = sorted.map((u) => u.id)
|
|
@@ -10260,13 +10180,18 @@ export async function bulkUpdate${ctx.Plural}SortOrder(
|
|
|
10260
10180
|
}
|
|
10261
10181
|
|
|
10262
10182
|
// Renumber all items gap-free
|
|
10183
|
+
const appliedOrder = allIds
|
|
10184
|
+
.filter(Boolean)
|
|
10185
|
+
.map((id, index) => ({ id, sortOrder: index }))
|
|
10186
|
+
|
|
10263
10187
|
await Promise.all(
|
|
10264
|
-
|
|
10265
|
-
db.update(${ctx.tableVar}).set({ sortOrder
|
|
10188
|
+
appliedOrder.map(({ id, sortOrder }) =>
|
|
10189
|
+
db.update(${ctx.tableVar}).set({ sortOrder }).where(eq(${ctx.tableVar}.id, id))
|
|
10266
10190
|
)
|
|
10267
10191
|
)
|
|
10268
10192
|
|
|
10269
10193
|
${ctx.cacheInvalidationFn}(${ctx.camelPlural}CacheTags.all)
|
|
10194
|
+
${afterHook("afterReorder", "{ ...lifecycleContext, data: { order: appliedOrder } }")}
|
|
10270
10195
|
return { success: true }
|
|
10271
10196
|
} catch (error) {
|
|
10272
10197
|
console.error('Error bulk updating sort order:', error)
|
|
@@ -11628,7 +11553,7 @@ import { getAuditRequestMetadata } from '@admin/actions/audit/request-metadata'
|
|
|
11628
11553
|
import db from '@admin/db'
|
|
11629
11554
|
import { ${upsertDbImports.join(", ")} } from '@admin/db/schema'
|
|
11630
11555
|
import { eq } from 'drizzle-orm'
|
|
11631
|
-
import {
|
|
11556
|
+
import { runAfterHooks, runBeforeHooks } from '@admin/lib/lifecycle-hooks'
|
|
11632
11557
|
import { getChangedFieldNames, getTouchedFieldNames } from '@admin/utils/audit/audit'
|
|
11633
11558
|
import { ${cacheInvalidationFn} } from 'next/cache'
|
|
11634
11559
|
import { get${Singular} } from './get-${kebabSingular}'
|
|
@@ -11680,6 +11605,22 @@ ${htmlUpsertBlock}
|
|
|
11680
11605
|
? getChangedFieldNames(previousRow as unknown as Record<string, unknown>, processedData)
|
|
11681
11606
|
: getTouchedFieldNames(processedData)
|
|
11682
11607
|
|
|
11608
|
+
const lifecycleContext = {
|
|
11609
|
+
user: actor,
|
|
11610
|
+
entityType: '${schema.name}',
|
|
11611
|
+
schemaType: 'single' as const,
|
|
11612
|
+
auditCategory: '${auditCategory}' as const,
|
|
11613
|
+
timestamp: now,
|
|
11614
|
+
sourceType: 'admin_ui' as const,
|
|
11615
|
+
ipAddress: auditRequestMetadata.ipAddress,
|
|
11616
|
+
userAgent: auditRequestMetadata.userAgent,
|
|
11617
|
+
entityId: SINGLETON_ID,
|
|
11618
|
+
input: processedData,
|
|
11619
|
+
changedFields,
|
|
11620
|
+
targetLabel: ${JSON.stringify(schema.label)}
|
|
11621
|
+
}
|
|
11622
|
+
await runBeforeHooks(previousRow ? 'beforeUpdate' : 'beforeCreate', lifecycleContext)
|
|
11623
|
+
|
|
11683
11624
|
const result = await db.transaction(async (tx) => {
|
|
11684
11625
|
const rows = await tx
|
|
11685
11626
|
.insert(${tableVar})
|
|
@@ -11704,18 +11645,9 @@ ${m2mWriteStatements}
|
|
|
11704
11645
|
|
|
11705
11646
|
${cacheInvalidationFn}(${cacheTagsVar}.all)
|
|
11706
11647
|
const saved${Singular} = await get${Singular}()
|
|
11707
|
-
|
|
11708
|
-
|
|
11709
|
-
|
|
11710
|
-
targetType: '${schema.name}',
|
|
11711
|
-
targetId: SINGLETON_ID,
|
|
11712
|
-
targetLabel: ${JSON.stringify(schema.label)},
|
|
11713
|
-
user: actor,
|
|
11714
|
-
timestamp: now,
|
|
11715
|
-
sourceType: 'admin_ui' as const,
|
|
11716
|
-
changedFields,
|
|
11717
|
-
metadata: { schemaType: 'single' },
|
|
11718
|
-
...auditRequestMetadata
|
|
11648
|
+
runAfterHooks(previousRow ? 'afterUpdate' : 'afterCreate', {
|
|
11649
|
+
...lifecycleContext,
|
|
11650
|
+
data: (saved${Singular} ?? result[0]) as unknown as Record<string, unknown>
|
|
11719
11651
|
})
|
|
11720
11652
|
|
|
11721
11653
|
return {
|
|
@@ -16574,7 +16506,7 @@ export default async function ${Plural}Page() {
|
|
|
16574
16506
|
const skeletonContent = `export function ${Plural}PageSkeleton() {
|
|
16575
16507
|
return (
|
|
16576
16508
|
<div className="flex items-center justify-center h-48">
|
|
16577
|
-
<div className="text-muted-foreground">Loading ${schema.label}
|
|
16509
|
+
<div className="text-muted-foreground">Loading ${schema.label}\u2026</div>
|
|
16578
16510
|
</div>
|
|
16579
16511
|
)
|
|
16580
16512
|
}
|
|
@@ -16906,7 +16838,6 @@ function generateSinglePage(schema, pagesDir, options = {}) {
|
|
|
16906
16838
|
const Singular = toPascalCase(singular);
|
|
16907
16839
|
const PageName = toPascalCase(schema.name);
|
|
16908
16840
|
const actionImportPath = resolveSchemaActionImportPath(schema.name, options.outputNamespace);
|
|
16909
|
-
const adminRoutePath = options.adminRoutePath ?? "/admin";
|
|
16910
16841
|
const devModeIntegration = buildSingleDevModeIntegration(
|
|
16911
16842
|
schema,
|
|
16912
16843
|
options.adminDir ?? "admin",
|
|
@@ -16914,7 +16845,6 @@ function generateSinglePage(schema, pagesDir, options = {}) {
|
|
|
16914
16845
|
options.adminImportAlias
|
|
16915
16846
|
);
|
|
16916
16847
|
const settingsImport = schema.name === "settings" ? "" : "import { getSetting } from '@admin/actions/settings'\n";
|
|
16917
|
-
const settingsAuditImports = schema.name === "settings" ? "import { Button } from '@admin/components/ui/button'\nimport { ScrollText } from 'lucide-react'\nimport Link from 'next/link'\n" : "";
|
|
16918
16848
|
const dataLoad = schema.name === "settings" ? ` const data = await get${Singular}()
|
|
16919
16849
|
` : ` const [data, initialSettings] = await Promise.all([
|
|
16920
16850
|
get${Singular}(),
|
|
@@ -16922,16 +16852,7 @@ function generateSinglePage(schema, pagesDir, options = {}) {
|
|
|
16922
16852
|
])
|
|
16923
16853
|
`;
|
|
16924
16854
|
const initialSettingsProp = schema.name === "settings" ? "initialSettings={data}" : "initialSettings={initialSettings}";
|
|
16925
|
-
const
|
|
16926
|
-
<Button asChild variant="outline" size="sm">
|
|
16927
|
-
<Link href="${adminRoutePath}/system/audit-log">
|
|
16928
|
-
<ScrollText />
|
|
16929
|
-
Audit Log
|
|
16930
|
-
</Link>
|
|
16931
|
-
</Button>
|
|
16932
|
-
<${devModeIntegration.buttonExportName} ${initialSettingsProp} />
|
|
16933
|
-
</div>` : `<${devModeIntegration.buttonExportName} ${initialSettingsProp} />`;
|
|
16934
|
-
const content = `${settingsImport}${settingsAuditImports}import { get${Singular} } from '@admin/actions/${actionImportPath}'
|
|
16855
|
+
const content = `${settingsImport}import { get${Singular} } from '@admin/actions/${actionImportPath}'
|
|
16935
16856
|
import { PageHeader } from '@admin/components/shared/page-header'
|
|
16936
16857
|
import { ${devModeIntegration.buttonExportName} } from '${devModeIntegration.buttonImportPath}'
|
|
16937
16858
|
import { ${Singular}Form } from './${schema.name}-form'
|
|
@@ -16944,9 +16865,9 @@ ${dataLoad}
|
|
|
16944
16865
|
<React.Fragment>
|
|
16945
16866
|
<PageHeader
|
|
16946
16867
|
title="${schema.label}"
|
|
16947
|
-
actions={${
|
|
16868
|
+
actions={<${devModeIntegration.buttonExportName} ${initialSettingsProp} />}
|
|
16948
16869
|
/>
|
|
16949
|
-
<main className="
|
|
16870
|
+
<main className="mx-auto max-w-5xl w-full p-4">
|
|
16950
16871
|
<${Singular}Form initialData={data} />
|
|
16951
16872
|
</main>
|
|
16952
16873
|
</React.Fragment>
|
|
@@ -17007,7 +16928,6 @@ import { GripVertical } from 'lucide-react'
|
|
|
17007
16928
|
import { parseAsInteger, parseAsString, useQueryStates } from 'nuqs'
|
|
17008
16929
|
${hasEdit ? "import { useRouter } from 'next/navigation'\n" : ""}import { use${Plural} } from '@admin/hooks/use-${schema.name}'
|
|
17009
16930
|
import type { ${Singular} } from '@admin/actions/${actionImportPath}'
|
|
17010
|
-
import { Card, CardContent } from '@admin/components/ui/card'
|
|
17011
16931
|
import { useTableUtils } from '@admin/hooks/use-table-utils'
|
|
17012
16932
|
import { cn } from '@admin/utils/shared/cn'
|
|
17013
16933
|
|
|
@@ -17113,110 +17033,106 @@ ${hasEdit ? " const router = useRouter()\n" : ""} const [{
|
|
|
17113
17033
|
<div
|
|
17114
17034
|
className={cn("flex flex-col gap-6 pt-px pb-2 h-full", className)}
|
|
17115
17035
|
>
|
|
17116
|
-
<
|
|
17117
|
-
<
|
|
17118
|
-
|
|
17119
|
-
<
|
|
17120
|
-
{
|
|
17121
|
-
|
|
17122
|
-
|
|
17123
|
-
|
|
17124
|
-
|
|
17125
|
-
|
|
17126
|
-
|
|
17127
|
-
|
|
17128
|
-
|
|
17129
|
-
|
|
17130
|
-
|
|
17131
|
-
'text-center': meta?.align === 'center',
|
|
17132
|
-
'text-right': meta?.align === 'right'
|
|
17133
|
-
})}
|
|
17134
|
-
data-column-id={header.column.id}
|
|
17135
|
-
onMouseEnter={() => setHoveredColumnId(header.column.id)}
|
|
17136
|
-
onMouseLeave={() => setHoveredColumnId((current) => (current === header.column.id ? null : current))}
|
|
17137
|
-
>
|
|
17138
|
-
{header.isPlaceholder
|
|
17139
|
-
? null
|
|
17140
|
-
: flexRender(header.column.columnDef.header, header.getContext())}
|
|
17141
|
-
{canResizeColumn ? (
|
|
17142
|
-
<button
|
|
17143
|
-
type="button"
|
|
17144
|
-
aria-label={\`Resize \${resizeLabel} column\`}
|
|
17145
|
-
className="group/resize-handle absolute right-0 top-0 z-10 flex h-full w-5 cursor-col-resize touch-none select-none items-center justify-center text-muted-foreground opacity-0 transition-opacity hover:text-foreground focus-visible:text-foreground focus-visible:opacity-100 focus-visible:outline-none group-focus-within/resize-header:opacity-100 data-[column-hovered=true]:opacity-100 data-[resizing=true]:opacity-100"
|
|
17146
|
-
data-resize-handle
|
|
17147
|
-
data-column-hovered={hoveredColumnId === header.column.id ? 'true' : 'false'}
|
|
17148
|
-
data-resizing={header.column.getIsResizing() ? 'true' : 'false'}
|
|
17149
|
-
onDoubleClick={resetColumnSizingToContainer}
|
|
17150
|
-
onMouseDown={header.getResizeHandler()}
|
|
17151
|
-
onTouchStart={header.getResizeHandler()}
|
|
17152
|
-
>
|
|
17153
|
-
<GripVertical aria-hidden="true" className={cn('size-3.5', { 'text-ring': header.column.getIsResizing() })} />
|
|
17154
|
-
</button>
|
|
17155
|
-
) : null}
|
|
17156
|
-
</DataGridHead>
|
|
17157
|
-
)
|
|
17158
|
-
})}
|
|
17159
|
-
</DataGridRow>
|
|
17160
|
-
))}
|
|
17161
|
-
</DataGridHeader>
|
|
17162
|
-
<DataGridBody>
|
|
17163
|
-
{isPending ? (
|
|
17164
|
-
<DataGridRow>
|
|
17165
|
-
<DataGridCell className="flex h-24 items-center justify-center text-center" style={{ gridColumn: '1 / -1' }}>
|
|
17166
|
-
<div className="text-muted-foreground">Loading ${schema.label}...</div>
|
|
17167
|
-
</DataGridCell>
|
|
17168
|
-
</DataGridRow>
|
|
17169
|
-
) : error ? (
|
|
17170
|
-
<DataGridRow>
|
|
17171
|
-
<DataGridCell className="flex h-24 items-center justify-center text-center" style={{ gridColumn: '1 / -1' }}>
|
|
17172
|
-
<div className="text-destructive">Error loading ${schema.label}: {error.message}</div>
|
|
17173
|
-
</DataGridCell>
|
|
17174
|
-
</DataGridRow>
|
|
17175
|
-
) : table.getRowModel().rows?.length ? (
|
|
17176
|
-
table.getRowModel().rows.map((row) => (
|
|
17177
|
-
<DataGridRow
|
|
17178
|
-
key={row.id}
|
|
17179
|
-
className={cn('hover:bg-muted/50', {
|
|
17180
|
-
'cursor-pointer': ${hasEdit ? "true" : "false"}
|
|
17036
|
+
<DataGrid containerClassName="min-h-0 flex-1" containerRef={tableContainerRef} gridTemplateColumns={gridTemplateColumns} style={{ width: table.getTotalSize() }}>
|
|
17037
|
+
<DataGridHeader>
|
|
17038
|
+
{table.getHeaderGroups().map((headerGroup) => (
|
|
17039
|
+
<DataGridRow key={headerGroup.id}>
|
|
17040
|
+
{headerGroup.headers.map((header, headerIndex) => {
|
|
17041
|
+
const meta = header.column.columnDef.meta as Record<string, unknown> | undefined
|
|
17042
|
+
const resizeLabel = typeof header.column.columnDef.header === 'string' ? header.column.columnDef.header : header.column.id
|
|
17043
|
+
const nextHeader = headerGroup.headers[headerIndex + 1]
|
|
17044
|
+
const canResizeColumn = header.column.getCanResize() && nextHeader?.column.getCanResize() === true
|
|
17045
|
+
return (
|
|
17046
|
+
<DataGridHead
|
|
17047
|
+
key={header.id}
|
|
17048
|
+
className={cn('group/resize-header relative overflow-hidden', {
|
|
17049
|
+
'text-center': meta?.align === 'center',
|
|
17050
|
+
'text-right': meta?.align === 'right'
|
|
17181
17051
|
})}
|
|
17182
|
-
data-
|
|
17183
|
-
|
|
17184
|
-
|
|
17185
|
-
if (!e.currentTarget.contains(target)) return
|
|
17186
|
-
if (target.closest('button, a, input, [role="checkbox"]')) return
|
|
17187
|
-
router.push(\`${adminRoutePath}/${schema.name}/\${row.original.id}/edit\`)
|
|
17188
|
-
}}` : ""}
|
|
17052
|
+
data-column-id={header.column.id}
|
|
17053
|
+
onMouseEnter={() => setHoveredColumnId(header.column.id)}
|
|
17054
|
+
onMouseLeave={() => setHoveredColumnId((current) => (current === header.column.id ? null : current))}
|
|
17189
17055
|
>
|
|
17190
|
-
{
|
|
17191
|
-
|
|
17192
|
-
|
|
17193
|
-
|
|
17194
|
-
|
|
17195
|
-
|
|
17196
|
-
|
|
17197
|
-
|
|
17198
|
-
|
|
17199
|
-
|
|
17200
|
-
|
|
17201
|
-
|
|
17202
|
-
|
|
17203
|
-
|
|
17204
|
-
|
|
17205
|
-
|
|
17206
|
-
|
|
17207
|
-
|
|
17208
|
-
|
|
17209
|
-
|
|
17210
|
-
|
|
17211
|
-
|
|
17212
|
-
|
|
17213
|
-
|
|
17214
|
-
|
|
17215
|
-
|
|
17216
|
-
|
|
17217
|
-
|
|
17218
|
-
|
|
17219
|
-
|
|
17056
|
+
{header.isPlaceholder
|
|
17057
|
+
? null
|
|
17058
|
+
: flexRender(header.column.columnDef.header, header.getContext())}
|
|
17059
|
+
{canResizeColumn ? (
|
|
17060
|
+
<button
|
|
17061
|
+
type="button"
|
|
17062
|
+
aria-label={\`Resize \${resizeLabel} column\`}
|
|
17063
|
+
className="group/resize-handle absolute right-0 top-0 z-10 flex h-full w-5 cursor-col-resize touch-none select-none items-center justify-center text-muted-foreground opacity-0 transition-opacity hover:text-foreground focus-visible:text-foreground focus-visible:opacity-100 focus-visible:outline-none group-focus-within/resize-header:opacity-100 data-[column-hovered=true]:opacity-100 data-[resizing=true]:opacity-100"
|
|
17064
|
+
data-resize-handle
|
|
17065
|
+
data-column-hovered={hoveredColumnId === header.column.id ? 'true' : 'false'}
|
|
17066
|
+
data-resizing={header.column.getIsResizing() ? 'true' : 'false'}
|
|
17067
|
+
onDoubleClick={resetColumnSizingToContainer}
|
|
17068
|
+
onMouseDown={header.getResizeHandler()}
|
|
17069
|
+
onTouchStart={header.getResizeHandler()}
|
|
17070
|
+
>
|
|
17071
|
+
<GripVertical aria-hidden="true" className={cn('size-3.5', { 'text-ring': header.column.getIsResizing() })} />
|
|
17072
|
+
</button>
|
|
17073
|
+
) : null}
|
|
17074
|
+
</DataGridHead>
|
|
17075
|
+
)
|
|
17076
|
+
})}
|
|
17077
|
+
</DataGridRow>
|
|
17078
|
+
))}
|
|
17079
|
+
</DataGridHeader>
|
|
17080
|
+
<DataGridBody>
|
|
17081
|
+
{isPending ? (
|
|
17082
|
+
<DataGridRow>
|
|
17083
|
+
<DataGridCell className="flex h-24 items-center justify-center text-center" style={{ gridColumn: '1 / -1' }}>
|
|
17084
|
+
<div className="text-muted-foreground">Loading ${schema.label}\u2026</div>
|
|
17085
|
+
</DataGridCell>
|
|
17086
|
+
</DataGridRow>
|
|
17087
|
+
) : error ? (
|
|
17088
|
+
<DataGridRow>
|
|
17089
|
+
<DataGridCell className="flex h-24 items-center justify-center text-center" style={{ gridColumn: '1 / -1' }}>
|
|
17090
|
+
<div className="text-destructive">Error loading ${schema.label}: {error.message}</div>
|
|
17091
|
+
</DataGridCell>
|
|
17092
|
+
</DataGridRow>
|
|
17093
|
+
) : table.getRowModel().rows?.length ? (
|
|
17094
|
+
table.getRowModel().rows.map((row) => (
|
|
17095
|
+
<DataGridRow
|
|
17096
|
+
key={row.id}
|
|
17097
|
+
className={cn('hover:bg-muted/50', {
|
|
17098
|
+
'cursor-pointer': ${hasEdit ? "true" : "false"}
|
|
17099
|
+
})}
|
|
17100
|
+
data-state={row.getIsSelected() ? 'selected' : undefined}${hasEdit ? `
|
|
17101
|
+
onClick={(e) => {
|
|
17102
|
+
const target = e.target as HTMLElement
|
|
17103
|
+
if (!e.currentTarget.contains(target)) return
|
|
17104
|
+
if (target.closest('button, a, input, [role="checkbox"]')) return
|
|
17105
|
+
router.push(\`${adminRoutePath}/${schema.name}/\${row.original.id}/edit\`)
|
|
17106
|
+
}}` : ""}
|
|
17107
|
+
>
|
|
17108
|
+
{row.getVisibleCells().map((cell) => {
|
|
17109
|
+
const meta = cell.column.columnDef.meta as Record<string, unknown> | undefined
|
|
17110
|
+
return (
|
|
17111
|
+
<DataGridCell
|
|
17112
|
+
key={cell.id}
|
|
17113
|
+
className={cn({
|
|
17114
|
+
'text-center': meta?.align === 'center',
|
|
17115
|
+
'text-right': meta?.align === 'right'
|
|
17116
|
+
})}
|
|
17117
|
+
data-column-id={cell.column.id}
|
|
17118
|
+
onMouseEnter={() => setHoveredColumnId(cell.column.id)}
|
|
17119
|
+
onMouseLeave={() => setHoveredColumnId((current) => (current === cell.column.id ? null : current))}
|
|
17120
|
+
>
|
|
17121
|
+
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
|
17122
|
+
</DataGridCell>
|
|
17123
|
+
)
|
|
17124
|
+
})}
|
|
17125
|
+
</DataGridRow>
|
|
17126
|
+
))
|
|
17127
|
+
) : (
|
|
17128
|
+
<DataGridRow>
|
|
17129
|
+
<DataGridCell className="flex h-24 items-center justify-center text-center" style={{ gridColumn: '1 / -1' }}>
|
|
17130
|
+
No ${schema.label} found.
|
|
17131
|
+
</DataGridCell>
|
|
17132
|
+
</DataGridRow>
|
|
17133
|
+
)}
|
|
17134
|
+
</DataGridBody>
|
|
17135
|
+
</DataGrid>
|
|
17220
17136
|
|
|
17221
17137
|
{shouldShowPagination ? (
|
|
17222
17138
|
<DataTablePagination
|
|
@@ -17331,6 +17247,10 @@ function runEntityPipeline(schema, cwd, config, options = {}) {
|
|
|
17331
17247
|
name: "Navigation",
|
|
17332
17248
|
run: () => updateNavigation(normalizedSchema, paths.adminNavigationDir, namespacedOptions).files
|
|
17333
17249
|
});
|
|
17250
|
+
steps.push({
|
|
17251
|
+
name: "Webhook events",
|
|
17252
|
+
run: () => updateWebhookEvents(normalizedSchema, paths.adminWebhookEventsDir, "entity").files
|
|
17253
|
+
});
|
|
17334
17254
|
for (let i = 0; i < steps.length; i++) {
|
|
17335
17255
|
const step = steps[i];
|
|
17336
17256
|
const stepNum = i + 1;
|
|
@@ -17393,6 +17313,10 @@ function runSinglePipeline(schema, cwd, config, options = {}) {
|
|
|
17393
17313
|
{
|
|
17394
17314
|
name: "Navigation",
|
|
17395
17315
|
run: () => updateNavigation(normalizedSchema, paths.adminNavigationDir, namespacedOptions).files
|
|
17316
|
+
},
|
|
17317
|
+
{
|
|
17318
|
+
name: "Webhook events",
|
|
17319
|
+
run: () => updateWebhookEvents(normalizedSchema, paths.adminWebhookEventsDir, "single").files
|
|
17396
17320
|
}
|
|
17397
17321
|
];
|
|
17398
17322
|
for (let i = 0; i < steps.length; i++) {
|
|
@@ -17968,18 +17892,41 @@ others.sort((a, b) => {
|
|
|
17968
17892
|
export const ${namespace.camel}Navigation = [...(dashboard ? [dashboard] : []), ...others]
|
|
17969
17893
|
`;
|
|
17970
17894
|
}
|
|
17895
|
+
function renderWebhookEventsBarrel(extractNames, namespaceValue) {
|
|
17896
|
+
const namespace = resolveAdminNamespace(namespaceValue);
|
|
17897
|
+
const importLines = extractNames.map(
|
|
17898
|
+
(name) => `import { ${toCamelCase(name)}WebhookEvents } from './webhook-events/${name}'`
|
|
17899
|
+
);
|
|
17900
|
+
const entryLines = extractNames.map((name) => ` ${toCamelCase(name)}WebhookEvents`);
|
|
17901
|
+
const extractImports = importLines.length > 0 ? `
|
|
17902
|
+
${importLines.join("\n")}` : "";
|
|
17903
|
+
const entries = entryLines.length > 0 ? `[
|
|
17904
|
+
${entryLines.join(",\n")}
|
|
17905
|
+
]` : "[]";
|
|
17906
|
+
return `import type { WebhookEventSource } from '${namespace.alias}/types/webhooks'${extractImports}
|
|
17907
|
+
|
|
17908
|
+
export type { WebhookEventSource } from '${namespace.alias}/types/webhooks'
|
|
17909
|
+
|
|
17910
|
+
export const webhookEventSources: WebhookEventSource[] = ${entries}
|
|
17911
|
+
`;
|
|
17912
|
+
}
|
|
17971
17913
|
function renderBarrelFiles(cwd, config) {
|
|
17972
17914
|
const paths = resolveProjectPaths(config);
|
|
17973
17915
|
const dbExtracts = listNamespacedExtracts(cwd, paths.adminDbDir).filter(
|
|
17974
17916
|
(extract) => !(extract.namespace === "core" && extract.name === "schema")
|
|
17975
17917
|
);
|
|
17976
17918
|
const navExtractNames = listExtractNames(cwd, paths.adminNavigationDir, /* @__PURE__ */ new Set(["core"]));
|
|
17919
|
+
const webhookEventExtractNames = listExtractNames(cwd, paths.adminWebhookEventsDir);
|
|
17977
17920
|
return namespaceGeneratedFiles(
|
|
17978
17921
|
[
|
|
17979
17922
|
createGeneratedFile(paths.adminDbSchemaFile, renderDbBarrel(dbExtracts)),
|
|
17980
17923
|
createGeneratedFile(
|
|
17981
17924
|
paths.adminNavigationFile,
|
|
17982
17925
|
renderNavigationBarrel(navExtractNames, config.frameworkConfig.next.namespace)
|
|
17926
|
+
),
|
|
17927
|
+
createGeneratedFile(
|
|
17928
|
+
paths.adminWebhookEventsFile,
|
|
17929
|
+
renderWebhookEventsBarrel(webhookEventExtractNames, config.frameworkConfig.next.namespace)
|
|
17983
17930
|
)
|
|
17984
17931
|
],
|
|
17985
17932
|
config.frameworkConfig.next.namespace
|
|
@@ -21905,6 +21852,16 @@ function openBrowserVercelNeon() {
|
|
|
21905
21852
|
`Opening Vercel... Create a Neon Postgres database, then copy the ${pc.cyan("DATABASE_URL")} from the dashboard.`
|
|
21906
21853
|
);
|
|
21907
21854
|
}
|
|
21855
|
+
function openBrowserVercelNeonResource(url) {
|
|
21856
|
+
if (!url) {
|
|
21857
|
+
openBrowserVercelNeon();
|
|
21858
|
+
return;
|
|
21859
|
+
}
|
|
21860
|
+
openBrowser(url);
|
|
21861
|
+
p10.log.info(
|
|
21862
|
+
`Opening Vercel... Copy the Neon ${pc.cyan("DATABASE_URL")} from the database dashboard, then paste it below.`
|
|
21863
|
+
);
|
|
21864
|
+
}
|
|
21908
21865
|
async function promptConnectionString() {
|
|
21909
21866
|
const input = await p10.text({
|
|
21910
21867
|
message: "Paste your PostgreSQL connection string",
|
|
@@ -22337,6 +22294,10 @@ function scaffoldComponents({ cwd, config }) {
|
|
|
22337
22294
|
"components/layouts/admin-sidebar-nav-link-skeleton.tsx",
|
|
22338
22295
|
readTemplate("components/layouts/admin-sidebar-nav-link-skeleton.tsx")
|
|
22339
22296
|
);
|
|
22297
|
+
write(
|
|
22298
|
+
"components/layouts/admin-settings-sidebar.tsx",
|
|
22299
|
+
readTemplate("components/layouts/admin-settings-sidebar.tsx")
|
|
22300
|
+
);
|
|
22340
22301
|
write(
|
|
22341
22302
|
"components/layouts/admin-sidebar-user-menu.tsx",
|
|
22342
22303
|
readTemplate("components/layouts/admin-sidebar-user-menu.tsx")
|
|
@@ -22501,6 +22462,7 @@ function scaffoldComponents({ cwd, config }) {
|
|
|
22501
22462
|
write("types/auth.ts", readTemplate("types/auth.ts"));
|
|
22502
22463
|
write("types/navigation.ts", readTemplate("types/navigation.ts"));
|
|
22503
22464
|
write("types/table-meta.ts", readTemplate("types/table-meta.ts"));
|
|
22465
|
+
write("types/webhooks.ts", readTemplate("types/webhooks.ts"));
|
|
22504
22466
|
for (const relPath of [
|
|
22505
22467
|
"utils/auth/roles.ts",
|
|
22506
22468
|
"utils/audit/audit.ts",
|
|
@@ -22536,7 +22498,7 @@ function scaffoldComponents({ cwd, config }) {
|
|
|
22536
22498
|
"utils/upload/upload.ts",
|
|
22537
22499
|
"utils/user/user.ts",
|
|
22538
22500
|
"utils/validation/validation.ts",
|
|
22539
|
-
"utils/webhook/
|
|
22501
|
+
"utils/webhook/signature.ts"
|
|
22540
22502
|
]) {
|
|
22541
22503
|
write(relPath, readTemplate(relPath));
|
|
22542
22504
|
}
|
|
@@ -22618,6 +22580,7 @@ function scaffoldComponents({ cwd, config }) {
|
|
|
22618
22580
|
write("hooks/use-admin-theme.tsx", readTemplate("hooks/use-admin-theme.tsx"));
|
|
22619
22581
|
write("hooks/use-audit-log.ts", readTemplate("hooks/use-audit-log.ts"));
|
|
22620
22582
|
write("hooks/use-users.ts", readTemplate("hooks/use-users.ts"));
|
|
22583
|
+
write("hooks/use-webhooks.ts", readTemplate("hooks/use-webhooks.ts"));
|
|
22621
22584
|
write("hooks/use-mobile.ts", readTemplate("hooks/use-mobile.ts"));
|
|
22622
22585
|
write("hooks/use-failed-image-url.ts", readTemplate("hooks/use-failed-image-url.ts"));
|
|
22623
22586
|
write("hooks/use-media.ts", readTemplate("hooks/use-media.ts"));
|
|
@@ -22632,14 +22595,28 @@ function scaffoldComponents({ cwd, config }) {
|
|
|
22632
22595
|
const adminNamespace = resolveAdminNamespace(namespace);
|
|
22633
22596
|
const projectName = detectProjectName(cwd);
|
|
22634
22597
|
write("data/navigation.ts", readTemplate("data/navigation.ts"));
|
|
22598
|
+
write("data/webhook-events.ts", readTemplate("data/webhook-events.ts"));
|
|
22635
22599
|
write(`utils/app/${adminNamespace.camel}.ts`, adminDataTemplate(projectName, namespace));
|
|
22636
22600
|
for (const relPath of [
|
|
22637
22601
|
"lib/actions/forms/types.ts",
|
|
22638
22602
|
"lib/actions/forms/get-form-settings.ts",
|
|
22639
22603
|
"lib/actions/forms/upsert-form-settings.ts",
|
|
22640
22604
|
"lib/actions/forms/get-all-form-settings.ts",
|
|
22641
|
-
"lib/actions/forms/test-form-webhook.ts",
|
|
22642
22605
|
"lib/actions/forms/index.ts",
|
|
22606
|
+
"lib/actions/webhooks/types.ts",
|
|
22607
|
+
"lib/actions/webhooks/internal-get-active-endpoints.ts",
|
|
22608
|
+
"lib/actions/webhooks/dispatch.ts",
|
|
22609
|
+
"lib/actions/webhooks/get-webhooks.ts",
|
|
22610
|
+
"lib/actions/webhooks/create-webhook.ts",
|
|
22611
|
+
"lib/actions/webhooks/update-webhook.ts",
|
|
22612
|
+
"lib/actions/webhooks/delete-webhook.ts",
|
|
22613
|
+
"lib/actions/webhooks/get-webhook-secret.ts",
|
|
22614
|
+
"lib/actions/webhooks/regenerate-webhook-secret.ts",
|
|
22615
|
+
"lib/actions/webhooks/get-webhook-subscriptions.ts",
|
|
22616
|
+
"lib/actions/webhooks/send-test-webhook.ts",
|
|
22617
|
+
"lib/actions/webhooks/get-webhook-deliveries.ts",
|
|
22618
|
+
"lib/actions/webhooks/register.ts",
|
|
22619
|
+
"lib/actions/webhooks/index.ts",
|
|
22643
22620
|
"lib/actions/entity-versions/types.ts",
|
|
22644
22621
|
"lib/actions/entity-versions/get-entity-versions.ts",
|
|
22645
22622
|
"lib/actions/entity-versions/internal-create-entity-version.ts",
|
|
@@ -22824,41 +22801,27 @@ function defaultSettingsSchema() {
|
|
|
22824
22801
|
type: "section",
|
|
22825
22802
|
name: "siteSettings",
|
|
22826
22803
|
label: "Dashboard Settings",
|
|
22827
|
-
description: "General settings for the dashboard",
|
|
22828
22804
|
fields: [
|
|
22829
22805
|
{
|
|
22830
22806
|
name: "title",
|
|
22831
22807
|
type: "string",
|
|
22832
|
-
label: "Name",
|
|
22808
|
+
label: "Application Name",
|
|
22833
22809
|
hint: "Displayed in the sidebar and throughout the dashboard",
|
|
22834
22810
|
default: "BetterStart"
|
|
22835
22811
|
},
|
|
22836
|
-
{
|
|
22837
|
-
name: "dashboardDescription",
|
|
22838
|
-
type: "text",
|
|
22839
|
-
label: "Description",
|
|
22840
|
-
hint: "A brief description of the application"
|
|
22841
|
-
}
|
|
22812
|
+
{ name: "dashboardLogo", type: "image", label: "Logo" }
|
|
22842
22813
|
]
|
|
22843
22814
|
},
|
|
22844
|
-
{
|
|
22845
|
-
type: "section",
|
|
22846
|
-
name: "branding",
|
|
22847
|
-
label: "Branding",
|
|
22848
|
-
description: "Logo and visual identity",
|
|
22849
|
-
fields: [{ name: "dashboardLogo", type: "image", label: "Logo" }]
|
|
22850
|
-
},
|
|
22851
22815
|
{
|
|
22852
22816
|
type: "section",
|
|
22853
22817
|
name: "developer",
|
|
22854
|
-
label: "
|
|
22855
|
-
description: "Developer tools for the dashboard",
|
|
22818
|
+
label: "Developers",
|
|
22856
22819
|
fields: [
|
|
22857
22820
|
{
|
|
22858
22821
|
name: "devMode",
|
|
22859
22822
|
type: "boolean",
|
|
22860
22823
|
label: "Dev Mode",
|
|
22861
|
-
hint: "Show generated integration snippets and schema details
|
|
22824
|
+
hint: "Show generated integration snippets and schema details for developers",
|
|
22862
22825
|
default: true
|
|
22863
22826
|
}
|
|
22864
22827
|
]
|
|
@@ -22867,7 +22830,6 @@ function defaultSettingsSchema() {
|
|
|
22867
22830
|
type: "section",
|
|
22868
22831
|
name: "auditLog",
|
|
22869
22832
|
label: "Audit Log",
|
|
22870
|
-
description: "Audit retention controls",
|
|
22871
22833
|
fields: [
|
|
22872
22834
|
{
|
|
22873
22835
|
name: "auditRetentionEnabled",
|
|
@@ -23188,6 +23150,78 @@ function scaffoldLayout({ cwd, config }) {
|
|
|
23188
23150
|
path41.join(usersDir, "change-password-dialog.tsx"),
|
|
23189
23151
|
readTemplate("pages/users/change-password-dialog.tsx")
|
|
23190
23152
|
);
|
|
23153
|
+
const settingsDir = path41.join(config.paths.pages, "settings");
|
|
23154
|
+
write(path41.join(settingsDir, "layout.tsx"), readTemplate("pages/settings/settings-layout.tsx"));
|
|
23155
|
+
const settingsFormsDir = path41.join(settingsDir, "forms");
|
|
23156
|
+
write(
|
|
23157
|
+
path41.join(settingsFormsDir, "page.tsx"),
|
|
23158
|
+
readTemplate("pages/settings/forms/forms-settings-page.tsx")
|
|
23159
|
+
);
|
|
23160
|
+
write(
|
|
23161
|
+
path41.join(settingsFormsDir, "forms-settings-page-skeleton.tsx"),
|
|
23162
|
+
readTemplate("pages/settings/forms/forms-settings-page-skeleton.tsx")
|
|
23163
|
+
);
|
|
23164
|
+
write(
|
|
23165
|
+
path41.join(settingsFormsDir, "forms-settings-page-content.tsx"),
|
|
23166
|
+
readTemplate("pages/settings/forms/forms-settings-page-content.tsx")
|
|
23167
|
+
);
|
|
23168
|
+
write(
|
|
23169
|
+
path41.join(settingsFormsDir, "edit-form-notifications-dialog.tsx"),
|
|
23170
|
+
readTemplate("pages/settings/forms/edit-form-notifications-dialog.tsx")
|
|
23171
|
+
);
|
|
23172
|
+
const settingsWebhooksDir = path41.join(settingsDir, "webhooks");
|
|
23173
|
+
write(
|
|
23174
|
+
path41.join(settingsWebhooksDir, "page.tsx"),
|
|
23175
|
+
readTemplate("pages/settings/webhooks/webhooks-page.tsx")
|
|
23176
|
+
);
|
|
23177
|
+
write(
|
|
23178
|
+
path41.join(settingsWebhooksDir, "webhooks-page-skeleton.tsx"),
|
|
23179
|
+
readTemplate("pages/settings/webhooks/webhooks-page-skeleton.tsx")
|
|
23180
|
+
);
|
|
23181
|
+
write(
|
|
23182
|
+
path41.join(settingsWebhooksDir, "webhooks-page-content.tsx"),
|
|
23183
|
+
readTemplate("pages/settings/webhooks/webhooks-page-content.tsx")
|
|
23184
|
+
);
|
|
23185
|
+
write(
|
|
23186
|
+
path41.join(settingsWebhooksDir, "webhooks-table.tsx"),
|
|
23187
|
+
readTemplate("pages/settings/webhooks/webhooks-table.tsx")
|
|
23188
|
+
);
|
|
23189
|
+
write(
|
|
23190
|
+
path41.join(settingsWebhooksDir, "webhooks-columns.tsx"),
|
|
23191
|
+
readTemplate("pages/settings/webhooks/webhooks-columns.tsx")
|
|
23192
|
+
);
|
|
23193
|
+
write(
|
|
23194
|
+
path41.join(settingsWebhooksDir, "webhook-actions.tsx"),
|
|
23195
|
+
readTemplate("pages/settings/webhooks/webhook-actions.tsx")
|
|
23196
|
+
);
|
|
23197
|
+
write(
|
|
23198
|
+
path41.join(settingsWebhooksDir, "webhook-enabled-switch.tsx"),
|
|
23199
|
+
readTemplate("pages/settings/webhooks/webhook-enabled-switch.tsx")
|
|
23200
|
+
);
|
|
23201
|
+
write(
|
|
23202
|
+
path41.join(settingsWebhooksDir, "webhook-endpoint-dialog.tsx"),
|
|
23203
|
+
readTemplate("pages/settings/webhooks/webhook-endpoint-dialog.tsx")
|
|
23204
|
+
);
|
|
23205
|
+
write(
|
|
23206
|
+
path41.join(settingsWebhooksDir, "delete-webhook-dialog.tsx"),
|
|
23207
|
+
readTemplate("pages/settings/webhooks/delete-webhook-dialog.tsx")
|
|
23208
|
+
);
|
|
23209
|
+
write(
|
|
23210
|
+
path41.join(settingsWebhooksDir, "webhooks-logs-page-content.tsx"),
|
|
23211
|
+
readTemplate("pages/settings/webhooks/webhooks-logs-page-content.tsx")
|
|
23212
|
+
);
|
|
23213
|
+
write(
|
|
23214
|
+
path41.join(settingsWebhooksDir, "webhooks-logs-table.tsx"),
|
|
23215
|
+
readTemplate("pages/settings/webhooks/webhooks-logs-table.tsx")
|
|
23216
|
+
);
|
|
23217
|
+
write(
|
|
23218
|
+
path41.join(settingsWebhooksDir, "webhooks-logs-columns.tsx"),
|
|
23219
|
+
readTemplate("pages/settings/webhooks/webhooks-logs-columns.tsx")
|
|
23220
|
+
);
|
|
23221
|
+
write(
|
|
23222
|
+
path41.join(settingsWebhooksDir, "logs", "page.tsx"),
|
|
23223
|
+
readTemplate("pages/settings/webhooks/webhooks-logs-page.tsx")
|
|
23224
|
+
);
|
|
23191
23225
|
const mediaDir = path41.join(config.paths.pages, "media");
|
|
23192
23226
|
write(path41.join(mediaDir, "page.tsx"), readTemplate("pages/media/media-page.tsx"));
|
|
23193
23227
|
write(
|
|
@@ -23198,23 +23232,34 @@ function scaffoldLayout({ cwd, config }) {
|
|
|
23198
23232
|
path41.join(mediaDir, "media-page-content.tsx"),
|
|
23199
23233
|
readTemplate("pages/media/media-page-content.tsx")
|
|
23200
23234
|
);
|
|
23201
|
-
const auditLogDir = path41.join(config.paths.pages, "
|
|
23202
|
-
write(
|
|
23235
|
+
const auditLogDir = path41.join(config.paths.pages, "settings", "audit-log");
|
|
23236
|
+
write(
|
|
23237
|
+
path41.join(auditLogDir, "page.tsx"),
|
|
23238
|
+
readTemplate("pages/settings/audit-log/audit-log-page.tsx")
|
|
23239
|
+
);
|
|
23203
23240
|
write(
|
|
23204
23241
|
path41.join(auditLogDir, "audit-log-page-skeleton.tsx"),
|
|
23205
|
-
readTemplate("pages/audit-log/audit-log-page-skeleton.tsx")
|
|
23242
|
+
readTemplate("pages/settings/audit-log/audit-log-page-skeleton.tsx")
|
|
23206
23243
|
);
|
|
23207
23244
|
write(
|
|
23208
23245
|
path41.join(auditLogDir, "audit-log-page-content.tsx"),
|
|
23209
|
-
readTemplate("pages/audit-log/audit-log-page-content.tsx")
|
|
23246
|
+
readTemplate("pages/settings/audit-log/audit-log-page-content.tsx")
|
|
23247
|
+
);
|
|
23248
|
+
write(
|
|
23249
|
+
path41.join(auditLogDir, "audit-log-table.tsx"),
|
|
23250
|
+
readTemplate("pages/settings/audit-log/audit-log-table.tsx")
|
|
23251
|
+
);
|
|
23252
|
+
write(
|
|
23253
|
+
path41.join(auditLogDir, "audit-log-columns.tsx"),
|
|
23254
|
+
readTemplate("pages/settings/audit-log/audit-log-columns.tsx")
|
|
23210
23255
|
);
|
|
23211
23256
|
write(
|
|
23212
23257
|
path41.join(auditLogDir, "audit-log-detail-drawer.tsx"),
|
|
23213
|
-
readTemplate("pages/audit-log/audit-log-detail-drawer.tsx")
|
|
23258
|
+
readTemplate("pages/settings/audit-log/audit-log-detail-drawer.tsx")
|
|
23214
23259
|
);
|
|
23215
23260
|
write(
|
|
23216
23261
|
path41.join(auditLogDir, "audit-log-detail-row.tsx"),
|
|
23217
|
-
readTemplate("pages/audit-log/audit-log-detail-row.tsx")
|
|
23262
|
+
readTemplate("pages/settings/audit-log/audit-log-detail-row.tsx")
|
|
23218
23263
|
);
|
|
23219
23264
|
const accountDir = path41.join(adminDir, "(account)");
|
|
23220
23265
|
write(path41.join(accountDir, "layout.tsx"), readTemplate("pages/account-layout.tsx"));
|
|
@@ -24620,25 +24665,17 @@ import pc5 from "picocolors";
|
|
|
24620
24665
|
var PROVISION_TIMEOUT_MS2 = 18e4;
|
|
24621
24666
|
var INTERACTIVE_PROVISION_TIMEOUT_MS2 = 6e5;
|
|
24622
24667
|
async function provisionNeonInteractive(runner, cwd, options) {
|
|
24623
|
-
const addArgs = ["integration", "add", "neon", "--no-env-pull"];
|
|
24624
|
-
if (options.plan) addArgs.push("--plan", options.plan);
|
|
24625
24668
|
const quietSpinner = spinner2();
|
|
24626
24669
|
quietSpinner.start("Creating your Neon database");
|
|
24627
|
-
const quiet = await runVercel(runner,
|
|
24670
|
+
const quiet = await runVercel(runner, neonAddArgs(options), {
|
|
24628
24671
|
cwd,
|
|
24629
24672
|
mode: "capture",
|
|
24630
24673
|
timeoutMs: PROVISION_TIMEOUT_MS2,
|
|
24631
24674
|
env: options.env
|
|
24632
24675
|
});
|
|
24633
24676
|
if (quiet.success) {
|
|
24634
|
-
quietSpinner.message("Retrieving the database connection string");
|
|
24635
|
-
const databaseUrl2 = await pullDatabaseUrl(runner, cwd, options.env);
|
|
24636
|
-
if (!databaseUrl2) {
|
|
24637
|
-
quietSpinner.stop("No DATABASE_URL came back from Vercel");
|
|
24638
|
-
return { failure: "env-pull-empty" };
|
|
24639
|
-
}
|
|
24640
24677
|
quietSpinner.clear();
|
|
24641
|
-
return
|
|
24678
|
+
return readNeonProvisionInfo(quiet.stdout);
|
|
24642
24679
|
}
|
|
24643
24680
|
quietSpinner.clear();
|
|
24644
24681
|
p15.log.info(
|
|
@@ -24646,7 +24683,7 @@ async function provisionNeonInteractive(runner, cwd, options) {
|
|
|
24646
24683
|
"(the Free plan is recommended)."
|
|
24647
24684
|
)}`
|
|
24648
24685
|
);
|
|
24649
|
-
const add = await runVercel(runner,
|
|
24686
|
+
const add = await runVercel(runner, connectedNeonAddArgs(options), {
|
|
24650
24687
|
cwd,
|
|
24651
24688
|
mode: "inherit",
|
|
24652
24689
|
timeoutMs: INTERACTIVE_PROVISION_TIMEOUT_MS2,
|
|
@@ -24656,21 +24693,19 @@ async function provisionNeonInteractive(runner, cwd, options) {
|
|
|
24656
24693
|
return { failure: add.timedOut ? "timeout" : "provision-failed" };
|
|
24657
24694
|
}
|
|
24658
24695
|
const pullSpinner = spinner2();
|
|
24659
|
-
pullSpinner.start("Retrieving
|
|
24660
|
-
const databaseUrl = await
|
|
24696
|
+
pullSpinner.start("Retrieving DATABASE_URL from Vercel");
|
|
24697
|
+
const databaseUrl = await pullVercelEnvValue(runner, cwd, readDbUrlFromDotenv, options.env);
|
|
24661
24698
|
if (!databaseUrl) {
|
|
24662
|
-
pullSpinner.stop("No DATABASE_URL came back from Vercel
|
|
24663
|
-
return {
|
|
24699
|
+
pullSpinner.stop(`${pc5.yellow("\u25B2")} No DATABASE_URL came back from Vercel`);
|
|
24700
|
+
return {};
|
|
24664
24701
|
}
|
|
24665
24702
|
pullSpinner.clear();
|
|
24666
24703
|
return { databaseUrl };
|
|
24667
24704
|
}
|
|
24668
24705
|
async function provisionNeon(runner, cwd, options) {
|
|
24669
|
-
const addArgs = ["integration", "add", "neon", "--no-env-pull", "--format", "json"];
|
|
24670
|
-
if (options.plan) addArgs.push("--plan", options.plan);
|
|
24671
24706
|
const provisionSpinner = spinner2();
|
|
24672
24707
|
provisionSpinner.start("Creating your Neon database");
|
|
24673
|
-
const add = await runVercel(runner,
|
|
24708
|
+
const add = await runVercel(runner, neonAddArgs(options), {
|
|
24674
24709
|
cwd,
|
|
24675
24710
|
mode: "capture",
|
|
24676
24711
|
timeoutMs: PROVISION_TIMEOUT_MS2,
|
|
@@ -24685,33 +24720,49 @@ ${add.stderr}`.trim();
|
|
|
24685
24720
|
if (/claim/i.test(combined)) return { failure: "claim-required", detail };
|
|
24686
24721
|
return { failure: add.timedOut ? "timeout" : "provision-failed", detail };
|
|
24687
24722
|
}
|
|
24688
|
-
const meta = parseVercelJson(add.stdout);
|
|
24689
|
-
const resourceName = meta?.resourceName ?? meta?.name;
|
|
24690
|
-
provisionSpinner.message("Retrieving the database connection string");
|
|
24691
|
-
const databaseUrl = await pullDatabaseUrl(runner, cwd, options.env);
|
|
24692
|
-
if (!databaseUrl) {
|
|
24693
|
-
provisionSpinner.stop("No DATABASE_URL came back from Vercel");
|
|
24694
|
-
return { resourceName, failure: "env-pull-empty" };
|
|
24695
|
-
}
|
|
24696
24723
|
provisionSpinner.clear();
|
|
24697
|
-
return
|
|
24724
|
+
return readNeonProvisionInfo(add.stdout);
|
|
24698
24725
|
}
|
|
24699
|
-
function
|
|
24700
|
-
|
|
24726
|
+
async function connectNeonResourceToProject(runner, cwd, resourceName, env) {
|
|
24727
|
+
const connect = await runVercel(
|
|
24728
|
+
runner,
|
|
24729
|
+
["integration", "resource", "connect", resourceName, "--yes", "--format", "json"],
|
|
24730
|
+
{ cwd, mode: "capture", timeoutMs: PROVISION_TIMEOUT_MS2, env }
|
|
24731
|
+
);
|
|
24732
|
+
if (connect.success) return { ok: true };
|
|
24733
|
+
const detail = `${connect.stdout}
|
|
24734
|
+
${connect.stderr}`.trim();
|
|
24735
|
+
if (/already connected/i.test(detail)) {
|
|
24736
|
+
return { ok: true, alreadyConnected: true, detail: detail || void 0 };
|
|
24737
|
+
}
|
|
24738
|
+
return { ok: false, detail: detail || void 0 };
|
|
24701
24739
|
}
|
|
24702
24740
|
function readDbUrlFromDotenv(filePath) {
|
|
24703
24741
|
const vars = parseDotenvFile(filePath);
|
|
24704
24742
|
const isPg = (v) => !!v && (v.startsWith("postgres://") || v.startsWith("postgresql://"));
|
|
24705
24743
|
if (isPg(vars.get("DATABASE_URL"))) return vars.get("DATABASE_URL");
|
|
24706
24744
|
if (isPg(vars.get("POSTGRES_URL"))) return vars.get("POSTGRES_URL");
|
|
24707
|
-
for (const [key, value] of vars) {
|
|
24708
|
-
if (/DATABASE_URL$/.test(key) && isPg(value)) return value;
|
|
24709
|
-
}
|
|
24710
|
-
for (const value of vars.values()) {
|
|
24711
|
-
if (isPg(value)) return value;
|
|
24712
|
-
}
|
|
24713
24745
|
return void 0;
|
|
24714
24746
|
}
|
|
24747
|
+
function readNeonProvisionInfo(stdout) {
|
|
24748
|
+
const meta = parseVercelJson(stdout);
|
|
24749
|
+
if (!meta) return {};
|
|
24750
|
+
return {
|
|
24751
|
+
resourceName: meta.resource?.name,
|
|
24752
|
+
dashboardUrl: meta.dashboardUrl,
|
|
24753
|
+
resourceUrl: meta.ssoUrl?.resource
|
|
24754
|
+
};
|
|
24755
|
+
}
|
|
24756
|
+
function neonAddArgs(options) {
|
|
24757
|
+
const addArgs = ["integration", "add", "neon", "--no-connect", "--format", "json"];
|
|
24758
|
+
if (options.plan) addArgs.push("--plan", options.plan);
|
|
24759
|
+
return addArgs;
|
|
24760
|
+
}
|
|
24761
|
+
function connectedNeonAddArgs(options) {
|
|
24762
|
+
const addArgs = ["integration", "add", "neon"];
|
|
24763
|
+
if (options.plan) addArgs.push("--plan", options.plan);
|
|
24764
|
+
return addArgs;
|
|
24765
|
+
}
|
|
24715
24766
|
|
|
24716
24767
|
// adapters/next/init/vercel/flow.ts
|
|
24717
24768
|
async function runVercelNeonFlow(options) {
|
|
@@ -24727,23 +24778,29 @@ async function runVercelNeonFlow(options) {
|
|
|
24727
24778
|
p16.log.warn(authFailureMessage(auth.reason));
|
|
24728
24779
|
return { ok: false };
|
|
24729
24780
|
}
|
|
24730
|
-
|
|
24731
|
-
projectSpinner.start(`Creating a Vercel project ${pc6.cyan(options.projectName)}`);
|
|
24732
|
-
const project2 = await createVercelProject(runner, options.cwd, options.projectName, env);
|
|
24733
|
-
projectSpinner.stop(
|
|
24734
|
-
project2.linked ? `Linked Vercel project ${pc6.cyan(project2.name)}` : `Using Vercel project ${pc6.cyan(project2.name)}`
|
|
24735
|
-
);
|
|
24781
|
+
await ensureLinkedProject(runner, options.cwd, options.projectName, env);
|
|
24736
24782
|
const neon = await provisionNeonForMode(runner, options);
|
|
24737
|
-
if (neon.failure
|
|
24783
|
+
if (neon.failure) {
|
|
24738
24784
|
p16.log.warn(neonFailureMessage(neon.failure));
|
|
24739
24785
|
if (neon.detail) p16.log.message(pc6.dim(neon.detail));
|
|
24740
24786
|
return { ok: false };
|
|
24741
24787
|
}
|
|
24788
|
+
let databaseUrl = neon.databaseUrl;
|
|
24789
|
+
if (neon.resourceName) {
|
|
24790
|
+
const pulledDatabaseUrl = await connectNeonAndPullDatabaseUrl(
|
|
24791
|
+
runner,
|
|
24792
|
+
options.cwd,
|
|
24793
|
+
neon.resourceName,
|
|
24794
|
+
env
|
|
24795
|
+
);
|
|
24796
|
+
databaseUrl = pulledDatabaseUrl ?? databaseUrl;
|
|
24797
|
+
}
|
|
24742
24798
|
return {
|
|
24743
24799
|
ok: true,
|
|
24744
|
-
databaseUrl
|
|
24745
|
-
|
|
24746
|
-
|
|
24800
|
+
databaseUrl,
|
|
24801
|
+
neonResourceName: neon.resourceName,
|
|
24802
|
+
dashboardUrl: neon.dashboardUrl,
|
|
24803
|
+
resourceUrl: neon.resourceUrl
|
|
24747
24804
|
};
|
|
24748
24805
|
} catch (error) {
|
|
24749
24806
|
p16.log.warn(
|
|
@@ -24767,16 +24824,7 @@ async function runVercelBlobFlow(options) {
|
|
|
24767
24824
|
p16.log.warn(authFailureMessage(auth.reason));
|
|
24768
24825
|
return { ok: false };
|
|
24769
24826
|
}
|
|
24770
|
-
|
|
24771
|
-
if (!projectId) {
|
|
24772
|
-
const projectSpinner = spinner2();
|
|
24773
|
-
projectSpinner.start(`Creating a Vercel project ${pc6.cyan(options.projectName)}`);
|
|
24774
|
-
const project2 = await createVercelProject(runner, options.cwd, options.projectName, env);
|
|
24775
|
-
projectSpinner.stop(
|
|
24776
|
-
project2.linked ? `Linked Vercel project ${pc6.cyan(project2.name)}` : `Using Vercel project ${pc6.cyan(project2.name)}`
|
|
24777
|
-
);
|
|
24778
|
-
projectId = project2.projectId;
|
|
24779
|
-
}
|
|
24827
|
+
await ensureLinkedProject(runner, options.cwd, options.projectName, env);
|
|
24780
24828
|
const blob = await provisionBlobForMode(runner, options);
|
|
24781
24829
|
if (blob.failure || !blob.token) {
|
|
24782
24830
|
p16.log.warn(blobFailureMessage(blob.failure));
|
|
@@ -24786,7 +24834,6 @@ async function runVercelBlobFlow(options) {
|
|
|
24786
24834
|
return {
|
|
24787
24835
|
ok: true,
|
|
24788
24836
|
token: blob.token,
|
|
24789
|
-
vercelProjectId: projectId,
|
|
24790
24837
|
blobStoreName: blob.storeName
|
|
24791
24838
|
};
|
|
24792
24839
|
} catch (error) {
|
|
@@ -24812,13 +24859,24 @@ async function runVercelDeployFlow(options) {
|
|
|
24812
24859
|
printManualDeployHint();
|
|
24813
24860
|
return { ok: false };
|
|
24814
24861
|
}
|
|
24815
|
-
|
|
24816
|
-
|
|
24817
|
-
|
|
24818
|
-
|
|
24819
|
-
|
|
24820
|
-
|
|
24862
|
+
await ensureLinkedProject(runner, options.cwd, options.projectName, env);
|
|
24863
|
+
if (options.neonResourceName) {
|
|
24864
|
+
const neonSpinner = spinner2();
|
|
24865
|
+
neonSpinner.start("Connecting Neon database to Vercel project");
|
|
24866
|
+
const connect = await connectNeonResourceToProject(
|
|
24867
|
+
runner,
|
|
24868
|
+
options.cwd,
|
|
24869
|
+
options.neonResourceName,
|
|
24870
|
+
env
|
|
24821
24871
|
);
|
|
24872
|
+
if (connect.ok) {
|
|
24873
|
+
neonSpinner.stop(
|
|
24874
|
+
connect.alreadyConnected ? "Neon database already connected to Vercel project" : "Connected Neon database to Vercel project"
|
|
24875
|
+
);
|
|
24876
|
+
} else {
|
|
24877
|
+
neonSpinner.stop(`${pc6.yellow("\u25B2")} Could not connect Neon database to Vercel project`);
|
|
24878
|
+
if (connect.detail) p16.log.message(pc6.dim(connect.detail));
|
|
24879
|
+
}
|
|
24822
24880
|
}
|
|
24823
24881
|
const envSpinner = spinner2();
|
|
24824
24882
|
envSpinner.start("Syncing environment variables to Vercel");
|
|
@@ -24873,6 +24931,33 @@ async function runVercelDeployFlow(options) {
|
|
|
24873
24931
|
function printManualDeployHint() {
|
|
24874
24932
|
p16.log.info(`You can deploy manually: ${pc6.cyan("vercel deploy --prod")}`);
|
|
24875
24933
|
}
|
|
24934
|
+
async function ensureLinkedProject(runner, cwd, projectName, env) {
|
|
24935
|
+
if (readLinkedProjectId(cwd)) return;
|
|
24936
|
+
const projectSpinner = spinner2();
|
|
24937
|
+
projectSpinner.start(`Creating a Vercel project ${pc6.cyan(projectName)}`);
|
|
24938
|
+
const project2 = await createVercelProject(runner, cwd, projectName, env);
|
|
24939
|
+
projectSpinner.stop(
|
|
24940
|
+
project2.linked ? `Linked Vercel project ${pc6.cyan(project2.name)}` : `Using Vercel project ${pc6.cyan(project2.name)}`
|
|
24941
|
+
);
|
|
24942
|
+
}
|
|
24943
|
+
async function connectNeonAndPullDatabaseUrl(runner, cwd, resourceName, env) {
|
|
24944
|
+
const neonSpinner = spinner2();
|
|
24945
|
+
neonSpinner.start("Connecting Neon database to Vercel project");
|
|
24946
|
+
const connect = await connectNeonResourceToProject(runner, cwd, resourceName, env);
|
|
24947
|
+
if (!connect.ok) {
|
|
24948
|
+
neonSpinner.stop(`${pc6.yellow("\u25B2")} Could not connect Neon database to Vercel project`);
|
|
24949
|
+
if (connect.detail) p16.log.message(pc6.dim(connect.detail));
|
|
24950
|
+
return void 0;
|
|
24951
|
+
}
|
|
24952
|
+
neonSpinner.message("Retrieving DATABASE_URL from Vercel");
|
|
24953
|
+
const databaseUrl = await pullVercelEnvValue(runner, cwd, readDbUrlFromDotenv, env);
|
|
24954
|
+
if (!databaseUrl) {
|
|
24955
|
+
neonSpinner.stop(`${pc6.yellow("\u25B2")} No DATABASE_URL came back from Vercel`);
|
|
24956
|
+
return void 0;
|
|
24957
|
+
}
|
|
24958
|
+
neonSpinner.clear();
|
|
24959
|
+
return databaseUrl;
|
|
24960
|
+
}
|
|
24876
24961
|
function provisionBlobForMode(runner, options) {
|
|
24877
24962
|
const opts = { name: blobStoreName(options.projectName), env: options.env };
|
|
24878
24963
|
return options.interactive ? provisionBlobStoreInteractive(runner, options.cwd, opts) : provisionBlobStore(runner, options.cwd, opts);
|
|
@@ -24919,8 +25004,6 @@ function neonFailureMessage(reason) {
|
|
|
24919
25004
|
return "Provisioning needs the Neon marketplace terms accepted \u2014 falling back to manual entry.";
|
|
24920
25005
|
case "claim-required":
|
|
24921
25006
|
return "The Neon resource needs to be claimed \u2014 falling back to manual entry.";
|
|
24922
|
-
case "env-pull-empty":
|
|
24923
|
-
return "Provisioned Neon, but no DATABASE_URL came back \u2014 falling back to manual entry.";
|
|
24924
25007
|
case "timeout":
|
|
24925
25008
|
return "Neon provisioning timed out \u2014 falling back to manual entry.";
|
|
24926
25009
|
default:
|
|
@@ -25038,10 +25121,15 @@ async function main() {
|
|
|
25038
25121
|
process.exit(0)
|
|
25039
25122
|
}
|
|
25040
25123
|
|
|
25041
|
-
const EMAIL = process.env.SEED_EMAIL
|
|
25042
|
-
const PASSWORD = process.env.SEED_PASSWORD
|
|
25124
|
+
const EMAIL = process.env.SEED_EMAIL
|
|
25125
|
+
const PASSWORD = process.env.SEED_PASSWORD
|
|
25043
25126
|
const NAME = process.env.SEED_NAME || 'Admin'
|
|
25044
25127
|
|
|
25128
|
+
if (!EMAIL || !PASSWORD) {
|
|
25129
|
+
console.error(' SEED_EMAIL and SEED_PASSWORD are required.')
|
|
25130
|
+
process.exit(1)
|
|
25131
|
+
}
|
|
25132
|
+
|
|
25045
25133
|
// Check if a user already exists with the requested email
|
|
25046
25134
|
const existingUser = await db
|
|
25047
25135
|
.select({ id: schema.user.id, name: schema.user.name })
|
|
@@ -25221,7 +25309,7 @@ async function runSeedCommand(options) {
|
|
|
25221
25309
|
}
|
|
25222
25310
|
|
|
25223
25311
|
// adapters/next/commands/init.ts
|
|
25224
|
-
var
|
|
25312
|
+
var ANSI_ESCAPE_PATTERN2 = /\u001B\[[0-?]*[ -/]*[@-~]/g;
|
|
25225
25313
|
var REMOVABLE_NAMESPACE_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
25226
25314
|
function normalizeNamespaceForRemoval(value) {
|
|
25227
25315
|
if (typeof value !== "string") {
|
|
@@ -25493,6 +25581,7 @@ async function runInitCommand(name, options) {
|
|
|
25493
25581
|
isFreshProject = true;
|
|
25494
25582
|
}
|
|
25495
25583
|
let databaseUrl;
|
|
25584
|
+
let neonResourceName;
|
|
25496
25585
|
const existingDbUrl = readExistingDbUrl(cwd);
|
|
25497
25586
|
if (options.yes) {
|
|
25498
25587
|
if (options.databaseUrl) {
|
|
@@ -25514,9 +25603,23 @@ async function runInitCommand(name, options) {
|
|
|
25514
25603
|
env: process.env
|
|
25515
25604
|
});
|
|
25516
25605
|
if (flow.ok && flow.databaseUrl) {
|
|
25606
|
+
neonResourceName = flow.neonResourceName;
|
|
25517
25607
|
databaseUrl = flow.databaseUrl;
|
|
25518
25608
|
persistDatabaseUrl(cwd, databaseUrl);
|
|
25519
25609
|
p17.log.success(`Saved DATABASE_URL to ${pc7.cyan(".env.local")}`);
|
|
25610
|
+
} else if (flow.ok) {
|
|
25611
|
+
neonResourceName = flow.neonResourceName;
|
|
25612
|
+
p17.log.warn("Created a Neon database, but DATABASE_URL could not be retrieved from Vercel.");
|
|
25613
|
+
const resourceUrl = flow.resourceUrl ?? flow.dashboardUrl;
|
|
25614
|
+
if (resourceUrl) {
|
|
25615
|
+
p17.log.info(
|
|
25616
|
+
`Open ${pc7.cyan(resourceUrl)} to copy DATABASE_URL, then rerun ${pc7.cyan("betterstart init --database-url <url> --yes")}.`
|
|
25617
|
+
);
|
|
25618
|
+
} else {
|
|
25619
|
+
p17.log.info(
|
|
25620
|
+
`Rerun ${pc7.cyan("betterstart init --database-url <url> --yes")} with a Postgres connection string.`
|
|
25621
|
+
);
|
|
25622
|
+
}
|
|
25520
25623
|
} else {
|
|
25521
25624
|
p17.log.warn("Vercel provisioning did not complete; continuing without a database URL.");
|
|
25522
25625
|
}
|
|
@@ -25536,9 +25639,16 @@ async function runInitCommand(name, options) {
|
|
|
25536
25639
|
env: process.env
|
|
25537
25640
|
});
|
|
25538
25641
|
if (flow.ok && flow.databaseUrl) {
|
|
25642
|
+
neonResourceName = flow.neonResourceName;
|
|
25539
25643
|
databaseUrl = flow.databaseUrl;
|
|
25540
25644
|
persistDatabaseUrl(cwd, databaseUrl);
|
|
25541
25645
|
p17.log.success(`Saved DATABASE_URL to ${pc7.cyan(".env.local")}`);
|
|
25646
|
+
} else if (flow.ok) {
|
|
25647
|
+
neonResourceName = flow.neonResourceName;
|
|
25648
|
+
openBrowserVercelNeonResource(flow.resourceUrl ?? flow.dashboardUrl);
|
|
25649
|
+
databaseUrl = await promptConnectionString();
|
|
25650
|
+
persistDatabaseUrl(cwd, databaseUrl);
|
|
25651
|
+
p17.log.success(`Saved DATABASE_URL to ${pc7.cyan(".env.local")}`);
|
|
25542
25652
|
} else {
|
|
25543
25653
|
p17.log.info("Falling back to a manual database connection string.");
|
|
25544
25654
|
openBrowserVercelNeon();
|
|
@@ -25868,7 +25978,7 @@ async function runInitCommand(name, options) {
|
|
|
25868
25978
|
} else {
|
|
25869
25979
|
s.start("Pushing database schema (drizzle-kit push)");
|
|
25870
25980
|
}
|
|
25871
|
-
const pushResult = await runDrizzlePush(cwd, {
|
|
25981
|
+
const pushResult = await runDrizzlePush(cwd, { interactive: useTerminalForDbPush });
|
|
25872
25982
|
if (pushResult.success) {
|
|
25873
25983
|
if (useTerminalForDbPush) {
|
|
25874
25984
|
const verification = await verifyDatabaseReachable(cwd);
|
|
@@ -26062,10 +26172,15 @@ Run manually: ${pc7.cyan(betterstartExecCommand(pm, "seed"))}`,
|
|
|
26062
26172
|
initialValue: linkedVercelProject
|
|
26063
26173
|
});
|
|
26064
26174
|
if (!p17.isCancel(deployNow) && deployNow) {
|
|
26065
|
-
await runVercelDeployFlow({ cwd, projectName, env: process.env });
|
|
26175
|
+
await runVercelDeployFlow({ cwd, projectName, neonResourceName, env: process.env });
|
|
26066
26176
|
}
|
|
26067
26177
|
} else if (linkedVercelProject && process.env.VERCEL_TOKEN) {
|
|
26068
|
-
const deployFlow = await runVercelDeployFlow({
|
|
26178
|
+
const deployFlow = await runVercelDeployFlow({
|
|
26179
|
+
cwd,
|
|
26180
|
+
projectName,
|
|
26181
|
+
neonResourceName,
|
|
26182
|
+
env: process.env
|
|
26183
|
+
});
|
|
26069
26184
|
if (!deployFlow.ok) {
|
|
26070
26185
|
p17.log.warn("Vercel deploy did not complete; continuing.");
|
|
26071
26186
|
}
|
|
@@ -26463,8 +26578,8 @@ function runQuietCommand(bin, args, options) {
|
|
|
26463
26578
|
});
|
|
26464
26579
|
});
|
|
26465
26580
|
}
|
|
26466
|
-
function
|
|
26467
|
-
return value.replace(
|
|
26581
|
+
function stripAnsi2(value) {
|
|
26582
|
+
return value.replace(ANSI_ESCAPE_PATTERN2, "");
|
|
26468
26583
|
}
|
|
26469
26584
|
function printAdminReadyNote(state) {
|
|
26470
26585
|
const lines = [`Admin: ${pc7.cyan(state.adminLoginUrl)}`];
|
|
@@ -26475,7 +26590,7 @@ function printAdminReadyNote(state) {
|
|
|
26475
26590
|
p17.note(lines.join("\n"), "Admin ready");
|
|
26476
26591
|
}
|
|
26477
26592
|
function shouldSuppressDevServerStartupLine(line) {
|
|
26478
|
-
const plain =
|
|
26593
|
+
const plain = stripAnsi2(line).trim();
|
|
26479
26594
|
if (plain.length === 0) {
|
|
26480
26595
|
return { suppress: true, isReadyLine: false };
|
|
26481
26596
|
}
|
|
@@ -26718,6 +26833,7 @@ function cleanupEmptyDirs3(cwd, deletedPaths, configPaths) {
|
|
|
26718
26833
|
const stopRoots = /* @__PURE__ */ new Set([
|
|
26719
26834
|
path54.join(cwd, ...configPaths.adminDir.split("/")),
|
|
26720
26835
|
path54.join(cwd, ...configPaths.adminNavigationDir.split("/")),
|
|
26836
|
+
path54.join(cwd, ...configPaths.adminWebhookEventsDir.split("/")),
|
|
26721
26837
|
path54.join(cwd, ...configPaths.pagesDir.split("/"))
|
|
26722
26838
|
]);
|
|
26723
26839
|
for (const deletedPath of deletedPaths) {
|
|
@@ -27504,6 +27620,11 @@ var TEMPLATE_REGISTRY = {
|
|
|
27504
27620
|
relPath: "components/layouts/admin-sidebar-nav-link-skeleton.tsx",
|
|
27505
27621
|
content: () => readTemplate("components/layouts/admin-sidebar-nav-link-skeleton.tsx")
|
|
27506
27622
|
},
|
|
27623
|
+
"admin-settings-sidebar": {
|
|
27624
|
+
relPath: "components/layouts/admin-settings-sidebar.tsx",
|
|
27625
|
+
content: () => readTemplate("components/layouts/admin-settings-sidebar.tsx"),
|
|
27626
|
+
dependencies: ["admin-sidebar-nav-link"]
|
|
27627
|
+
},
|
|
27507
27628
|
"admin-sidebar-user-menu": {
|
|
27508
27629
|
relPath: "components/layouts/admin-sidebar-user-menu.tsx",
|
|
27509
27630
|
content: () => readTemplate("components/layouts/admin-sidebar-user-menu.tsx"),
|
|
@@ -27898,6 +28019,11 @@ var TEMPLATE_REGISTRY = {
|
|
|
27898
28019
|
dependencies: ["audit-action"]
|
|
27899
28020
|
},
|
|
27900
28021
|
"use-users": { relPath: "hooks/use-users.ts", content: () => readTemplate("hooks/use-users.ts") },
|
|
28022
|
+
"use-webhooks": {
|
|
28023
|
+
relPath: "hooks/use-webhooks.ts",
|
|
28024
|
+
content: () => readTemplate("hooks/use-webhooks.ts"),
|
|
28025
|
+
dependencies: ["webhooks-action", "form-settings-action"]
|
|
28026
|
+
},
|
|
27901
28027
|
"use-mobile": {
|
|
27902
28028
|
relPath: "hooks/use-mobile.ts",
|
|
27903
28029
|
content: () => readTemplate("hooks/use-mobile.ts")
|
|
@@ -27946,6 +28072,10 @@ var TEMPLATE_REGISTRY = {
|
|
|
27946
28072
|
relPath: "types/table-meta.ts",
|
|
27947
28073
|
content: () => readTemplate("types/table-meta.ts")
|
|
27948
28074
|
},
|
|
28075
|
+
"webhooks-types": {
|
|
28076
|
+
relPath: "types/webhooks.ts",
|
|
28077
|
+
content: () => readTemplate("types/webhooks.ts")
|
|
28078
|
+
},
|
|
27949
28079
|
// Utils
|
|
27950
28080
|
"app-admin": {
|
|
27951
28081
|
relPath: ({ config }) => `utils/app/${resolveAdminNamespace(config.frameworkConfig.next.namespace).camel}.ts`,
|
|
@@ -28078,9 +28208,9 @@ var TEMPLATE_REGISTRY = {
|
|
|
28078
28208
|
relPath: "utils/validation/validation.ts",
|
|
28079
28209
|
content: () => readTemplate("utils/validation/validation.ts")
|
|
28080
28210
|
},
|
|
28081
|
-
webhook: {
|
|
28082
|
-
relPath: "utils/webhook/
|
|
28083
|
-
content: () => readTemplate("utils/webhook/
|
|
28211
|
+
"webhook-signature": {
|
|
28212
|
+
relPath: "utils/webhook/signature.ts",
|
|
28213
|
+
content: () => readTemplate("utils/webhook/signature.ts")
|
|
28084
28214
|
},
|
|
28085
28215
|
"dev-mode-code-block-height-utils": {
|
|
28086
28216
|
relPath: "utils/dev-mode/code-block-height.ts",
|
|
@@ -28113,7 +28243,8 @@ var TEMPLATE_REGISTRY = {
|
|
|
28113
28243
|
},
|
|
28114
28244
|
"lifecycle-hooks-register": {
|
|
28115
28245
|
relPath: "lib/lifecycle-hooks/register.ts",
|
|
28116
|
-
content: () => readTemplate("lib/lifecycle-hooks/register.ts")
|
|
28246
|
+
content: () => readTemplate("lib/lifecycle-hooks/register.ts"),
|
|
28247
|
+
dependencies: ["webhooks-register-action"]
|
|
28117
28248
|
},
|
|
28118
28249
|
"lifecycle-hooks-register-local": {
|
|
28119
28250
|
relPath: "lib/lifecycle-hooks/register.local.ts",
|
|
@@ -28298,6 +28429,119 @@ var TEMPLATE_REGISTRY = {
|
|
|
28298
28429
|
base: "cwd",
|
|
28299
28430
|
dependencies: ["profile-action", "users-action"]
|
|
28300
28431
|
},
|
|
28432
|
+
"settings-layout": {
|
|
28433
|
+
relPath: "app/(admin)/admin/(authenticated)/settings/layout.tsx",
|
|
28434
|
+
content: () => readTemplate("pages/settings/settings-layout.tsx"),
|
|
28435
|
+
base: "cwd",
|
|
28436
|
+
dependencies: ["admin-settings-sidebar"]
|
|
28437
|
+
},
|
|
28438
|
+
"forms-settings-page": {
|
|
28439
|
+
relPath: "app/(admin)/admin/(authenticated)/settings/forms/page.tsx",
|
|
28440
|
+
content: () => readTemplate("pages/settings/forms/forms-settings-page.tsx"),
|
|
28441
|
+
base: "cwd",
|
|
28442
|
+
dependencies: ["forms-settings-page-skeleton", "forms-settings-page-content"]
|
|
28443
|
+
},
|
|
28444
|
+
"forms-settings-page-skeleton": {
|
|
28445
|
+
relPath: "app/(admin)/admin/(authenticated)/settings/forms/forms-settings-page-skeleton.tsx",
|
|
28446
|
+
content: () => readTemplate("pages/settings/forms/forms-settings-page-skeleton.tsx"),
|
|
28447
|
+
base: "cwd"
|
|
28448
|
+
},
|
|
28449
|
+
"forms-settings-page-content": {
|
|
28450
|
+
relPath: "app/(admin)/admin/(authenticated)/settings/forms/forms-settings-page-content.tsx",
|
|
28451
|
+
content: () => readTemplate("pages/settings/forms/forms-settings-page-content.tsx"),
|
|
28452
|
+
base: "cwd",
|
|
28453
|
+
dependencies: ["edit-form-notifications-dialog", "use-webhooks"]
|
|
28454
|
+
},
|
|
28455
|
+
"edit-form-notifications-dialog": {
|
|
28456
|
+
relPath: "app/(admin)/admin/(authenticated)/settings/forms/edit-form-notifications-dialog.tsx",
|
|
28457
|
+
content: () => readTemplate("pages/settings/forms/edit-form-notifications-dialog.tsx"),
|
|
28458
|
+
base: "cwd",
|
|
28459
|
+
dependencies: ["form-settings-action"]
|
|
28460
|
+
},
|
|
28461
|
+
"webhooks-page": {
|
|
28462
|
+
relPath: "app/(admin)/admin/(authenticated)/settings/webhooks/page.tsx",
|
|
28463
|
+
content: () => readTemplate("pages/settings/webhooks/webhooks-page.tsx"),
|
|
28464
|
+
base: "cwd",
|
|
28465
|
+
dependencies: ["webhooks-page-skeleton", "webhooks-page-content"]
|
|
28466
|
+
},
|
|
28467
|
+
"webhooks-page-skeleton": {
|
|
28468
|
+
relPath: "app/(admin)/admin/(authenticated)/settings/webhooks/webhooks-page-skeleton.tsx",
|
|
28469
|
+
content: () => readTemplate("pages/settings/webhooks/webhooks-page-skeleton.tsx"),
|
|
28470
|
+
base: "cwd"
|
|
28471
|
+
},
|
|
28472
|
+
"webhooks-page-content": {
|
|
28473
|
+
relPath: "app/(admin)/admin/(authenticated)/settings/webhooks/webhooks-page-content.tsx",
|
|
28474
|
+
content: () => readTemplate("pages/settings/webhooks/webhooks-page-content.tsx"),
|
|
28475
|
+
base: "cwd",
|
|
28476
|
+
dependencies: [
|
|
28477
|
+
"webhooks-table",
|
|
28478
|
+
"webhooks-columns",
|
|
28479
|
+
"webhook-endpoint-dialog",
|
|
28480
|
+
"delete-webhook-dialog",
|
|
28481
|
+
"use-webhooks",
|
|
28482
|
+
"webhooks-action"
|
|
28483
|
+
]
|
|
28484
|
+
},
|
|
28485
|
+
"webhooks-table": {
|
|
28486
|
+
relPath: "app/(admin)/admin/(authenticated)/settings/webhooks/webhooks-table.tsx",
|
|
28487
|
+
content: () => readTemplate("pages/settings/webhooks/webhooks-table.tsx"),
|
|
28488
|
+
base: "cwd",
|
|
28489
|
+
dependencies: ["use-webhooks"]
|
|
28490
|
+
},
|
|
28491
|
+
"webhooks-columns": {
|
|
28492
|
+
relPath: "app/(admin)/admin/(authenticated)/settings/webhooks/webhooks-columns.tsx",
|
|
28493
|
+
content: () => readTemplate("pages/settings/webhooks/webhooks-columns.tsx"),
|
|
28494
|
+
base: "cwd",
|
|
28495
|
+
dependencies: ["webhook-actions", "webhook-enabled-switch"]
|
|
28496
|
+
},
|
|
28497
|
+
"webhook-actions": {
|
|
28498
|
+
relPath: "app/(admin)/admin/(authenticated)/settings/webhooks/webhook-actions.tsx",
|
|
28499
|
+
content: () => readTemplate("pages/settings/webhooks/webhook-actions.tsx"),
|
|
28500
|
+
base: "cwd",
|
|
28501
|
+
dependencies: ["use-webhooks"]
|
|
28502
|
+
},
|
|
28503
|
+
"webhook-enabled-switch": {
|
|
28504
|
+
relPath: "app/(admin)/admin/(authenticated)/settings/webhooks/webhook-enabled-switch.tsx",
|
|
28505
|
+
content: () => readTemplate("pages/settings/webhooks/webhook-enabled-switch.tsx"),
|
|
28506
|
+
base: "cwd",
|
|
28507
|
+
dependencies: ["use-webhooks"]
|
|
28508
|
+
},
|
|
28509
|
+
"webhook-endpoint-dialog": {
|
|
28510
|
+
relPath: "app/(admin)/admin/(authenticated)/settings/webhooks/webhook-endpoint-dialog.tsx",
|
|
28511
|
+
content: () => readTemplate("pages/settings/webhooks/webhook-endpoint-dialog.tsx"),
|
|
28512
|
+
base: "cwd",
|
|
28513
|
+
dependencies: ["use-webhooks", "webhooks-action"]
|
|
28514
|
+
},
|
|
28515
|
+
"delete-webhook-dialog": {
|
|
28516
|
+
relPath: "app/(admin)/admin/(authenticated)/settings/webhooks/delete-webhook-dialog.tsx",
|
|
28517
|
+
content: () => readTemplate("pages/settings/webhooks/delete-webhook-dialog.tsx"),
|
|
28518
|
+
base: "cwd",
|
|
28519
|
+
dependencies: ["webhooks-action"]
|
|
28520
|
+
},
|
|
28521
|
+
"webhooks-logs-page": {
|
|
28522
|
+
relPath: "app/(admin)/admin/(authenticated)/settings/webhooks/logs/page.tsx",
|
|
28523
|
+
content: () => readTemplate("pages/settings/webhooks/webhooks-logs-page.tsx"),
|
|
28524
|
+
base: "cwd",
|
|
28525
|
+
dependencies: ["webhooks-logs-page-content", "webhooks-page-skeleton"]
|
|
28526
|
+
},
|
|
28527
|
+
"webhooks-logs-page-content": {
|
|
28528
|
+
relPath: "app/(admin)/admin/(authenticated)/settings/webhooks/webhooks-logs-page-content.tsx",
|
|
28529
|
+
content: () => readTemplate("pages/settings/webhooks/webhooks-logs-page-content.tsx"),
|
|
28530
|
+
base: "cwd",
|
|
28531
|
+
dependencies: ["webhooks-logs-table", "webhooks-logs-columns", "use-webhooks"]
|
|
28532
|
+
},
|
|
28533
|
+
"webhooks-logs-table": {
|
|
28534
|
+
relPath: "app/(admin)/admin/(authenticated)/settings/webhooks/webhooks-logs-table.tsx",
|
|
28535
|
+
content: () => readTemplate("pages/settings/webhooks/webhooks-logs-table.tsx"),
|
|
28536
|
+
base: "cwd",
|
|
28537
|
+
dependencies: ["use-webhooks"]
|
|
28538
|
+
},
|
|
28539
|
+
"webhooks-logs-columns": {
|
|
28540
|
+
relPath: "app/(admin)/admin/(authenticated)/settings/webhooks/webhooks-logs-columns.tsx",
|
|
28541
|
+
content: () => readTemplate("pages/settings/webhooks/webhooks-logs-columns.tsx"),
|
|
28542
|
+
base: "cwd",
|
|
28543
|
+
dependencies: ["webhooks-action"]
|
|
28544
|
+
},
|
|
28301
28545
|
// Lib
|
|
28302
28546
|
"email-index": {
|
|
28303
28547
|
relPath: "lib/actions/email/index.ts",
|
|
@@ -28375,8 +28619,7 @@ var TEMPLATE_REGISTRY = {
|
|
|
28375
28619
|
"form-settings-types",
|
|
28376
28620
|
"get-form-settings-action",
|
|
28377
28621
|
"upsert-form-settings-action",
|
|
28378
|
-
"get-all-form-settings-action"
|
|
28379
|
-
"test-form-webhook-action"
|
|
28622
|
+
"get-all-form-settings-action"
|
|
28380
28623
|
]
|
|
28381
28624
|
},
|
|
28382
28625
|
"form-settings-types": {
|
|
@@ -28398,9 +28641,87 @@ var TEMPLATE_REGISTRY = {
|
|
|
28398
28641
|
content: () => readTemplate("lib/actions/forms/get-all-form-settings.ts"),
|
|
28399
28642
|
dependencies: ["form-settings-types"]
|
|
28400
28643
|
},
|
|
28401
|
-
"
|
|
28402
|
-
relPath: "lib/actions/
|
|
28403
|
-
content: () => readTemplate("lib/actions/
|
|
28644
|
+
"webhooks-action": {
|
|
28645
|
+
relPath: "lib/actions/webhooks/index.ts",
|
|
28646
|
+
content: () => readTemplate("lib/actions/webhooks/index.ts"),
|
|
28647
|
+
dependencies: [
|
|
28648
|
+
"webhooks-action-types",
|
|
28649
|
+
"internal-get-active-endpoints-action",
|
|
28650
|
+
"webhooks-dispatch",
|
|
28651
|
+
"get-webhooks-action",
|
|
28652
|
+
"create-webhook-action",
|
|
28653
|
+
"update-webhook-action",
|
|
28654
|
+
"delete-webhook-action",
|
|
28655
|
+
"get-webhook-secret-action",
|
|
28656
|
+
"regenerate-webhook-secret-action",
|
|
28657
|
+
"get-webhook-subscriptions-action",
|
|
28658
|
+
"send-test-webhook-action",
|
|
28659
|
+
"get-webhook-deliveries-action",
|
|
28660
|
+
"webhooks-register-action"
|
|
28661
|
+
]
|
|
28662
|
+
},
|
|
28663
|
+
"webhooks-action-types": {
|
|
28664
|
+
relPath: "lib/actions/webhooks/types.ts",
|
|
28665
|
+
content: () => readTemplate("lib/actions/webhooks/types.ts")
|
|
28666
|
+
},
|
|
28667
|
+
"internal-get-active-endpoints-action": {
|
|
28668
|
+
relPath: "lib/actions/webhooks/internal-get-active-endpoints.ts",
|
|
28669
|
+
content: () => readTemplate("lib/actions/webhooks/internal-get-active-endpoints.ts")
|
|
28670
|
+
},
|
|
28671
|
+
"webhooks-dispatch": {
|
|
28672
|
+
relPath: "lib/actions/webhooks/dispatch.ts",
|
|
28673
|
+
content: () => readTemplate("lib/actions/webhooks/dispatch.ts"),
|
|
28674
|
+
dependencies: ["webhook-signature", "internal-get-active-endpoints-action"]
|
|
28675
|
+
},
|
|
28676
|
+
"get-webhooks-action": {
|
|
28677
|
+
relPath: "lib/actions/webhooks/get-webhooks.ts",
|
|
28678
|
+
content: () => readTemplate("lib/actions/webhooks/get-webhooks.ts"),
|
|
28679
|
+
dependencies: ["webhooks-action-types"]
|
|
28680
|
+
},
|
|
28681
|
+
"create-webhook-action": {
|
|
28682
|
+
relPath: "lib/actions/webhooks/create-webhook.ts",
|
|
28683
|
+
content: () => readTemplate("lib/actions/webhooks/create-webhook.ts"),
|
|
28684
|
+
dependencies: ["webhooks-action-types", "webhook-signature"]
|
|
28685
|
+
},
|
|
28686
|
+
"update-webhook-action": {
|
|
28687
|
+
relPath: "lib/actions/webhooks/update-webhook.ts",
|
|
28688
|
+
content: () => readTemplate("lib/actions/webhooks/update-webhook.ts"),
|
|
28689
|
+
dependencies: ["webhooks-action-types"]
|
|
28690
|
+
},
|
|
28691
|
+
"delete-webhook-action": {
|
|
28692
|
+
relPath: "lib/actions/webhooks/delete-webhook.ts",
|
|
28693
|
+
content: () => readTemplate("lib/actions/webhooks/delete-webhook.ts"),
|
|
28694
|
+
dependencies: ["webhooks-action-types"]
|
|
28695
|
+
},
|
|
28696
|
+
"get-webhook-secret-action": {
|
|
28697
|
+
relPath: "lib/actions/webhooks/get-webhook-secret.ts",
|
|
28698
|
+
content: () => readTemplate("lib/actions/webhooks/get-webhook-secret.ts"),
|
|
28699
|
+
dependencies: ["webhooks-action-types"]
|
|
28700
|
+
},
|
|
28701
|
+
"regenerate-webhook-secret-action": {
|
|
28702
|
+
relPath: "lib/actions/webhooks/regenerate-webhook-secret.ts",
|
|
28703
|
+
content: () => readTemplate("lib/actions/webhooks/regenerate-webhook-secret.ts"),
|
|
28704
|
+
dependencies: ["webhooks-action-types", "webhook-signature"]
|
|
28705
|
+
},
|
|
28706
|
+
"get-webhook-subscriptions-action": {
|
|
28707
|
+
relPath: "lib/actions/webhooks/get-webhook-subscriptions.ts",
|
|
28708
|
+
content: () => readTemplate("lib/actions/webhooks/get-webhook-subscriptions.ts"),
|
|
28709
|
+
dependencies: ["webhooks-action-types"]
|
|
28710
|
+
},
|
|
28711
|
+
"send-test-webhook-action": {
|
|
28712
|
+
relPath: "lib/actions/webhooks/send-test-webhook.ts",
|
|
28713
|
+
content: () => readTemplate("lib/actions/webhooks/send-test-webhook.ts"),
|
|
28714
|
+
dependencies: ["webhooks-action-types", "webhook-signature", "webhooks-dispatch"]
|
|
28715
|
+
},
|
|
28716
|
+
"get-webhook-deliveries-action": {
|
|
28717
|
+
relPath: "lib/actions/webhooks/get-webhook-deliveries.ts",
|
|
28718
|
+
content: () => readTemplate("lib/actions/webhooks/get-webhook-deliveries.ts"),
|
|
28719
|
+
dependencies: ["webhooks-action-types"]
|
|
28720
|
+
},
|
|
28721
|
+
"webhooks-register-action": {
|
|
28722
|
+
relPath: "lib/actions/webhooks/register.ts",
|
|
28723
|
+
content: () => readTemplate("lib/actions/webhooks/register.ts"),
|
|
28724
|
+
dependencies: ["webhooks-dispatch", "webhooks-types"]
|
|
28404
28725
|
},
|
|
28405
28726
|
"entity-versions-action": {
|
|
28406
28727
|
relPath: "lib/actions/entity-versions/index.ts",
|
|
@@ -28688,44 +29009,50 @@ var TEMPLATE_REGISTRY = {
|
|
|
28688
29009
|
dependencies: ["use-media", "media-grid-pagination"]
|
|
28689
29010
|
},
|
|
28690
29011
|
"audit-log-page": {
|
|
28691
|
-
relPath: "app/(admin)/admin/(authenticated)/
|
|
28692
|
-
content: () => readTemplate("pages/audit-log/audit-log-page.tsx"),
|
|
29012
|
+
relPath: "app/(admin)/admin/(authenticated)/settings/audit-log/page.tsx",
|
|
29013
|
+
content: () => readTemplate("pages/settings/audit-log/audit-log-page.tsx"),
|
|
28693
29014
|
base: "cwd",
|
|
28694
29015
|
dependencies: ["audit-log-page-content", "audit-log-page-skeleton"]
|
|
28695
29016
|
},
|
|
28696
29017
|
"audit-log-page-skeleton": {
|
|
28697
|
-
relPath: "app/(admin)/admin/(authenticated)/
|
|
28698
|
-
content: () => readTemplate("pages/audit-log/audit-log-page-skeleton.tsx"),
|
|
29018
|
+
relPath: "app/(admin)/admin/(authenticated)/settings/audit-log/audit-log-page-skeleton.tsx",
|
|
29019
|
+
content: () => readTemplate("pages/settings/audit-log/audit-log-page-skeleton.tsx"),
|
|
28699
29020
|
base: "cwd",
|
|
28700
29021
|
dependencies: ["page-header", "skeleton"]
|
|
28701
29022
|
},
|
|
28702
29023
|
"audit-log-page-content": {
|
|
28703
|
-
relPath: "app/(admin)/admin/(authenticated)/
|
|
28704
|
-
content: () => readTemplate("pages/audit-log/audit-log-page-content.tsx"),
|
|
29024
|
+
relPath: "app/(admin)/admin/(authenticated)/settings/audit-log/audit-log-page-content.tsx",
|
|
29025
|
+
content: () => readTemplate("pages/settings/audit-log/audit-log-page-content.tsx"),
|
|
28705
29026
|
base: "cwd",
|
|
28706
29027
|
dependencies: [
|
|
29028
|
+
"audit-log-columns",
|
|
28707
29029
|
"audit-log-detail-drawer",
|
|
28708
|
-
"
|
|
28709
|
-
"button",
|
|
28710
|
-
"card",
|
|
28711
|
-
"data-grid",
|
|
28712
|
-
"data-table-pagination",
|
|
29030
|
+
"audit-log-table",
|
|
28713
29031
|
"entity-filters-bar",
|
|
28714
|
-
"page-header"
|
|
28715
|
-
"sort-indicator",
|
|
28716
|
-
"use-table-utils",
|
|
28717
|
-
"use-audit-log"
|
|
29032
|
+
"page-header"
|
|
28718
29033
|
]
|
|
28719
29034
|
},
|
|
29035
|
+
"audit-log-table": {
|
|
29036
|
+
relPath: "app/(admin)/admin/(authenticated)/settings/audit-log/audit-log-table.tsx",
|
|
29037
|
+
content: () => readTemplate("pages/settings/audit-log/audit-log-table.tsx"),
|
|
29038
|
+
base: "cwd",
|
|
29039
|
+
dependencies: ["data-grid", "data-table-pagination", "use-audit-log", "use-table-utils"]
|
|
29040
|
+
},
|
|
29041
|
+
"audit-log-columns": {
|
|
29042
|
+
relPath: "app/(admin)/admin/(authenticated)/settings/audit-log/audit-log-columns.tsx",
|
|
29043
|
+
content: () => readTemplate("pages/settings/audit-log/audit-log-columns.tsx"),
|
|
29044
|
+
base: "cwd",
|
|
29045
|
+
dependencies: ["badge", "button", "sort-indicator"]
|
|
29046
|
+
},
|
|
28720
29047
|
"audit-log-detail-drawer": {
|
|
28721
|
-
relPath: "app/(admin)/admin/(authenticated)/
|
|
28722
|
-
content: () => readTemplate("pages/audit-log/audit-log-detail-drawer.tsx"),
|
|
29048
|
+
relPath: "app/(admin)/admin/(authenticated)/settings/audit-log/audit-log-detail-drawer.tsx",
|
|
29049
|
+
content: () => readTemplate("pages/settings/audit-log/audit-log-detail-drawer.tsx"),
|
|
28723
29050
|
base: "cwd",
|
|
28724
29051
|
dependencies: ["audit-log-detail-row", "badge", "drawer", "scroll-area"]
|
|
28725
29052
|
},
|
|
28726
29053
|
"audit-log-detail-row": {
|
|
28727
|
-
relPath: "app/(admin)/admin/(authenticated)/
|
|
28728
|
-
content: () => readTemplate("pages/audit-log/audit-log-detail-row.tsx"),
|
|
29054
|
+
relPath: "app/(admin)/admin/(authenticated)/settings/audit-log/audit-log-detail-row.tsx",
|
|
29055
|
+
content: () => readTemplate("pages/settings/audit-log/audit-log-detail-row.tsx"),
|
|
28729
29056
|
base: "cwd"
|
|
28730
29057
|
}
|
|
28731
29058
|
};
|