betterstart-cli 0.0.5 → 0.0.6
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/cli.js +471 -37
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -3867,6 +3867,61 @@ function generateFieldMapping(field, source = "input") {
|
|
|
3867
3867
|
function getFieldType(field, mode = "output") {
|
|
3868
3868
|
return toTypeScriptType(field, mode);
|
|
3869
3869
|
}
|
|
3870
|
+
function getReadFieldType(field) {
|
|
3871
|
+
if (field.type === "select") return "SelectOptionValue[]";
|
|
3872
|
+
if (field.type === "group" && field.fields && field.fields.length > 0) {
|
|
3873
|
+
const groupType = field.fields.map(
|
|
3874
|
+
(nestedField) => `${quotePropertyName(nestedField.name)}?: ${getReadFieldType(nestedField)}`
|
|
3875
|
+
).join("; ");
|
|
3876
|
+
return `{ ${groupType} }`;
|
|
3877
|
+
}
|
|
3878
|
+
if (field.type === "list" && field.fields && field.fields.length > 0) {
|
|
3879
|
+
const nestedType = field.fields.flatMap((nestedField) => {
|
|
3880
|
+
const fields = [`${quotePropertyName(nestedField.name)}?: ${getReadFieldType(nestedField)}`];
|
|
3881
|
+
if (nestedField.hasIcon) {
|
|
3882
|
+
fields.push(`${quotePropertyName(`${nestedField.name}Icon`)}?: string`);
|
|
3883
|
+
}
|
|
3884
|
+
return fields;
|
|
3885
|
+
}).join("; ");
|
|
3886
|
+
return `Array<{ ${nestedType} }>`;
|
|
3887
|
+
}
|
|
3888
|
+
return getFieldType(field, "output");
|
|
3889
|
+
}
|
|
3890
|
+
function collectReadSelectFields(fields, path52 = []) {
|
|
3891
|
+
const matches = fields.flatMap((field) => {
|
|
3892
|
+
const currentPath = [...path52, field.name];
|
|
3893
|
+
const matches2 = field.type === "select" ? [{ field, path: currentPath }] : [];
|
|
3894
|
+
if (field.fields) {
|
|
3895
|
+
matches2.push(...collectReadSelectFields(field.fields, currentPath));
|
|
3896
|
+
}
|
|
3897
|
+
if (field.tabs) {
|
|
3898
|
+
for (const tab of field.tabs) {
|
|
3899
|
+
matches2.push(...collectReadSelectFields(tab.fields ?? [], currentPath));
|
|
3900
|
+
if (tab.slot?.main?.fields) {
|
|
3901
|
+
matches2.push(...collectReadSelectFields(tab.slot.main.fields, currentPath));
|
|
3902
|
+
}
|
|
3903
|
+
if (tab.slot?.sidebar?.fields) {
|
|
3904
|
+
matches2.push(...collectReadSelectFields(tab.slot.sidebar.fields, currentPath));
|
|
3905
|
+
}
|
|
3906
|
+
}
|
|
3907
|
+
}
|
|
3908
|
+
return matches2;
|
|
3909
|
+
});
|
|
3910
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3911
|
+
return matches.filter((match) => {
|
|
3912
|
+
const key = match.path.join(".");
|
|
3913
|
+
if (seen.has(key)) return false;
|
|
3914
|
+
seen.add(key);
|
|
3915
|
+
return true;
|
|
3916
|
+
});
|
|
3917
|
+
}
|
|
3918
|
+
function buildReadSelectOptionType(selectFields) {
|
|
3919
|
+
if (selectFields.length === 0) return null;
|
|
3920
|
+
return `export interface SelectOptionValue {
|
|
3921
|
+
label: string
|
|
3922
|
+
value: string
|
|
3923
|
+
}`;
|
|
3924
|
+
}
|
|
3870
3925
|
function buildRelationshipSelect(allDbFields, relationshipFields, tableVar, htmlFields = [], extraSelects = [], extraJoins = "") {
|
|
3871
3926
|
const fieldSelects = allDbFields.filter((f) => f.type !== "relationship").map((f) => ` ${f.name}: ${tableVar}.${f.name}`);
|
|
3872
3927
|
const htmlSelects = htmlFields.map((f) => ` ${f.name}Html: ${tableVar}.${f.name}Html`);
|
|
@@ -3931,7 +3986,7 @@ ${rowMappings}
|
|
|
3931
3986
|
return `${mapBlock}
|
|
3932
3987
|
|
|
3933
3988
|
return {
|
|
3934
|
-
${camelPlural}: mapped${Plural} as ${Singular}[],
|
|
3989
|
+
${camelPlural}: mapped${Plural} as unknown as ${Singular}[],
|
|
3935
3990
|
total
|
|
3936
3991
|
}`;
|
|
3937
3992
|
}
|
|
@@ -3956,7 +4011,7 @@ function buildSingleRowMapping(allDbFields, _relationshipFields, typeName, htmlF
|
|
|
3956
4011
|
].join(",\n");
|
|
3957
4012
|
return `{
|
|
3958
4013
|
${mappings}
|
|
3959
|
-
} as ${typeName}`;
|
|
4014
|
+
} as unknown as ${typeName}`;
|
|
3960
4015
|
}
|
|
3961
4016
|
function buildExplicitSelect(fields, tableVar, htmlFields = [], extraSelects = [], extraJoins = "") {
|
|
3962
4017
|
const fieldSelects = fields.map((f) => ` ${f.name}: ${tableVar}.${f.name}`);
|
|
@@ -4382,6 +4437,14 @@ function sampleSchemaOutputValue(field) {
|
|
|
4382
4437
|
if (field.name === "id") return SAMPLE_UUID;
|
|
4383
4438
|
if (field.name === "createdAt" || field.name === "updatedAt") return "2026-01-01T00:00:00.000Z";
|
|
4384
4439
|
if (field.name === "createdBy" || field.name === "updatedBy") return "user-id";
|
|
4440
|
+
if (field.type === "select") {
|
|
4441
|
+
const sampleValue = sampleSchemaFieldValue(field);
|
|
4442
|
+
const values = Array.isArray(sampleValue) ? sampleValue : sampleValue ? [sampleValue] : [];
|
|
4443
|
+
return values.filter((value) => typeof value === "string" && value.length > 0).map((value) => ({
|
|
4444
|
+
label: field.options?.find((option) => option.value === value)?.label ?? value,
|
|
4445
|
+
value
|
|
4446
|
+
}));
|
|
4447
|
+
}
|
|
4385
4448
|
if (field.type === "relationship" && field.relationship && !field.multiple) {
|
|
4386
4449
|
return {
|
|
4387
4450
|
id: SAMPLE_UUID,
|
|
@@ -4391,6 +4454,18 @@ function sampleSchemaOutputValue(field) {
|
|
|
4391
4454
|
label: "Example related record"
|
|
4392
4455
|
};
|
|
4393
4456
|
}
|
|
4457
|
+
if (field.type === "group" && field.fields && field.fields.length > 0) {
|
|
4458
|
+
return Object.fromEntries(
|
|
4459
|
+
field.fields.filter((nestedField) => nestedField.name && !isLayoutField(nestedField.type)).map((nestedField) => [nestedField.name, sampleSchemaOutputValue(nestedField)])
|
|
4460
|
+
);
|
|
4461
|
+
}
|
|
4462
|
+
if (field.type === "list" && field.fields && field.fields.length > 0) {
|
|
4463
|
+
return [
|
|
4464
|
+
Object.fromEntries(
|
|
4465
|
+
field.fields.filter((nestedField) => nestedField.name && !isLayoutField(nestedField.type)).map((nestedField) => [nestedField.name, sampleSchemaOutputValue(nestedField)])
|
|
4466
|
+
)
|
|
4467
|
+
];
|
|
4468
|
+
}
|
|
4394
4469
|
return sampleSchemaFieldValue(field);
|
|
4395
4470
|
}
|
|
4396
4471
|
function sampleSingleOutputValue(field) {
|
|
@@ -8030,7 +8105,10 @@ function genHelpersContent(ctx) {
|
|
|
8030
8105
|
drizzleImports.add("inArray");
|
|
8031
8106
|
schemaImports.add("adminMedia");
|
|
8032
8107
|
}
|
|
8033
|
-
if (ctx.
|
|
8108
|
+
if (ctx.hasCreatableSelectFields) {
|
|
8109
|
+
schemaImports.add(ctx.selectOptionsTableVar);
|
|
8110
|
+
}
|
|
8111
|
+
if (ctx.hasM2M || ctx.hasListRels || ctx.hasMediaFields || ctx.hasCreatableSelectFields) {
|
|
8034
8112
|
lines.push(`import db from '@admin/db'`);
|
|
8035
8113
|
}
|
|
8036
8114
|
const tables = [...schemaImports].sort();
|
|
@@ -8043,7 +8121,8 @@ function genHelpersContent(ctx) {
|
|
|
8043
8121
|
if (ctx.hasMediaFields) {
|
|
8044
8122
|
lines.push(`import type { AdminMedia } from '@admin/types'`);
|
|
8045
8123
|
}
|
|
8046
|
-
|
|
8124
|
+
const typeImports = ctx.hasSelectFields ? `${ctx.Singular}, SelectOptionValue` : ctx.Singular;
|
|
8125
|
+
lines.push(`import type { ${typeImports} } from './types'`);
|
|
8047
8126
|
lines.push("");
|
|
8048
8127
|
lines.push(`export function formatActionDate(value: unknown): string {
|
|
8049
8128
|
if (typeof value !== 'string') return ''
|
|
@@ -8067,6 +8146,10 @@ function genHelpersContent(ctx) {
|
|
|
8067
8146
|
lines.push(generateResolveMediaFunction(ctx));
|
|
8068
8147
|
lines.push("");
|
|
8069
8148
|
}
|
|
8149
|
+
if (ctx.hasSelectFields) {
|
|
8150
|
+
lines.push(generateResolveSelectFieldsFunction(ctx));
|
|
8151
|
+
lines.push("");
|
|
8152
|
+
}
|
|
8070
8153
|
lines.push(generateVersionSnapshotHelpers(ctx));
|
|
8071
8154
|
lines.push("");
|
|
8072
8155
|
return lines.join("\n");
|
|
@@ -8117,7 +8200,7 @@ const VERSION_RESTORE_KEYS = [${restoreKeys}] as const
|
|
|
8117
8200
|
const VERSION_M2M_KEYS = [${m2mKeys}] as const
|
|
8118
8201
|
|
|
8119
8202
|
export function build${ctx.Singular}VersionSnapshot(row: Partial<${ctx.Singular}> | Record<string, unknown>): Record<string, unknown> {
|
|
8120
|
-
const source = row as Record<string, unknown>
|
|
8203
|
+
const source = row as unknown as Record<string, unknown>
|
|
8121
8204
|
const snapshot: Record<string, unknown> = {}
|
|
8122
8205
|
|
|
8123
8206
|
for (const key of VERSION_SNAPSHOT_KEYS) {
|
|
@@ -8222,6 +8305,95 @@ ${assignArray}` : ""}
|
|
|
8222
8305
|
return rows
|
|
8223
8306
|
}`;
|
|
8224
8307
|
}
|
|
8308
|
+
function generateResolveSelectFieldsFunction(ctx) {
|
|
8309
|
+
const staticLabelMaps = ctx.selectFields.map((readField) => {
|
|
8310
|
+
const key = readField.path.join(".");
|
|
8311
|
+
const entries = (readField.field.options ?? []).map((option) => `${JSON.stringify(option.value)}: ${JSON.stringify(option.label)}`).join(", ");
|
|
8312
|
+
return ` ${JSON.stringify(key)}: { ${entries} }`;
|
|
8313
|
+
}).join(",\n");
|
|
8314
|
+
const dynamicRowsBlock = ctx.hasCreatableSelectFields ? `
|
|
8315
|
+
const dynamicRows = await db
|
|
8316
|
+
.select({
|
|
8317
|
+
fieldName: ${ctx.selectOptionsTableVar}.fieldName,
|
|
8318
|
+
label: ${ctx.selectOptionsTableVar}.label,
|
|
8319
|
+
value: ${ctx.selectOptionsTableVar}.value
|
|
8320
|
+
})
|
|
8321
|
+
.from(${ctx.selectOptionsTableVar})
|
|
8322
|
+
|
|
8323
|
+
for (const row of dynamicRows) {
|
|
8324
|
+
labelMaps[row.fieldName] ??= {}
|
|
8325
|
+
labelMaps[row.fieldName][row.value] = row.label
|
|
8326
|
+
}
|
|
8327
|
+
` : "";
|
|
8328
|
+
const assignments = ctx.selectFields.map((readField) => {
|
|
8329
|
+
const key = readField.path.join(".");
|
|
8330
|
+
return ` resolveSelectFieldPath(source, ${JSON.stringify(readField.path)}, labelMaps[${JSON.stringify(key)}] ?? {})`;
|
|
8331
|
+
}).join("\n");
|
|
8332
|
+
return `const STATIC_SELECT_OPTION_LABELS = {
|
|
8333
|
+
${staticLabelMaps}
|
|
8334
|
+
} satisfies Record<string, Record<string, string>>
|
|
8335
|
+
|
|
8336
|
+
function cloneSelectOptionLabelMaps(): Record<string, Record<string, string>> {
|
|
8337
|
+
return Object.fromEntries(
|
|
8338
|
+
Object.entries(STATIC_SELECT_OPTION_LABELS).map(([fieldName, labels]) => [
|
|
8339
|
+
fieldName,
|
|
8340
|
+
{ ...labels }
|
|
8341
|
+
])
|
|
8342
|
+
)
|
|
8343
|
+
}
|
|
8344
|
+
|
|
8345
|
+
function toSelectOptionValues(value: unknown, labels: Record<string, string>): SelectOptionValue[] {
|
|
8346
|
+
const values = Array.isArray(value) ? value : value ? [value] : []
|
|
8347
|
+
|
|
8348
|
+
return values
|
|
8349
|
+
.filter((item): item is string => typeof item === 'string' && item.length > 0)
|
|
8350
|
+
.map((item) => ({
|
|
8351
|
+
label: labels[item] ?? item,
|
|
8352
|
+
value: item
|
|
8353
|
+
}))
|
|
8354
|
+
}
|
|
8355
|
+
|
|
8356
|
+
function resolveSelectFieldPath(
|
|
8357
|
+
source: Record<string, unknown>,
|
|
8358
|
+
path: readonly string[],
|
|
8359
|
+
labels: Record<string, string>
|
|
8360
|
+
): void {
|
|
8361
|
+
const [fieldName, ...rest] = path
|
|
8362
|
+
if (!fieldName) return
|
|
8363
|
+
|
|
8364
|
+
if (rest.length === 0) {
|
|
8365
|
+
source[fieldName] = toSelectOptionValues(source[fieldName], labels)
|
|
8366
|
+
return
|
|
8367
|
+
}
|
|
8368
|
+
|
|
8369
|
+
const value = source[fieldName]
|
|
8370
|
+
if (Array.isArray(value)) {
|
|
8371
|
+
for (const item of value) {
|
|
8372
|
+
if (item && typeof item === 'object') {
|
|
8373
|
+
resolveSelectFieldPath(item as Record<string, unknown>, rest, labels)
|
|
8374
|
+
}
|
|
8375
|
+
}
|
|
8376
|
+
return
|
|
8377
|
+
}
|
|
8378
|
+
|
|
8379
|
+
if (value && typeof value === 'object') {
|
|
8380
|
+
resolveSelectFieldPath(value as Record<string, unknown>, rest, labels)
|
|
8381
|
+
}
|
|
8382
|
+
}
|
|
8383
|
+
|
|
8384
|
+
export async function resolve${ctx.Singular}SelectFields(rows: ${ctx.Singular}[]): Promise<${ctx.Singular}[]> {
|
|
8385
|
+
if (rows.length === 0) return rows
|
|
8386
|
+
|
|
8387
|
+
const labelMaps = cloneSelectOptionLabelMaps()
|
|
8388
|
+
${dynamicRowsBlock}
|
|
8389
|
+
for (const row of rows) {
|
|
8390
|
+
const source = row as unknown as Record<string, unknown>
|
|
8391
|
+
${assignments}
|
|
8392
|
+
}
|
|
8393
|
+
|
|
8394
|
+
return rows
|
|
8395
|
+
}`;
|
|
8396
|
+
}
|
|
8225
8397
|
function genGetPluralContent(ctx) {
|
|
8226
8398
|
const dbImports = [ctx.tableVar, "user", ...ctx.relTableImports].sort();
|
|
8227
8399
|
const drizzle = ["asc", "desc"];
|
|
@@ -8235,6 +8407,7 @@ function genGetPluralContent(ctx) {
|
|
|
8235
8407
|
const sortedDrizzle = [...new Set(drizzle)].sort();
|
|
8236
8408
|
const typeImports = [`${ctx.Plural}Page`, `${ctx.Plural}Query`, `${ctx.Singular}`];
|
|
8237
8409
|
const helperImports = ["formatActionDate"];
|
|
8410
|
+
if (ctx.hasSelectFields) helperImports.push(`resolve${ctx.Singular}SelectFields`);
|
|
8238
8411
|
if (ctx.hasListRels) helperImports.push(`populate${ctx.Singular}ListRelationships`);
|
|
8239
8412
|
if (ctx.hasMediaFields) helperImports.push(`resolve${ctx.Singular}MediaFields`);
|
|
8240
8413
|
const populateImport = helperImports.length > 0 ? `
|
|
@@ -8325,6 +8498,7 @@ function genGetByIdContent(ctx) {
|
|
|
8325
8498
|
const drizzle = ["eq"];
|
|
8326
8499
|
const sortedDrizzle = [...new Set(drizzle)].sort();
|
|
8327
8500
|
const byIdHelperImports = ["formatActionDate"];
|
|
8501
|
+
if (ctx.hasSelectFields) byIdHelperImports.push(`resolve${ctx.Singular}SelectFields`);
|
|
8328
8502
|
if (ctx.hasListRels) byIdHelperImports.push(`populate${ctx.Singular}ListRelationships`);
|
|
8329
8503
|
if (ctx.hasMediaFields) byIdHelperImports.push(`resolve${ctx.Singular}MediaFields`);
|
|
8330
8504
|
const populateImport = byIdHelperImports.length > 0 ? `
|
|
@@ -8363,6 +8537,7 @@ function genGetBySlugContent(ctx) {
|
|
|
8363
8537
|
const drizzle = ["eq"];
|
|
8364
8538
|
const sortedDrizzle = [...new Set(drizzle)].sort();
|
|
8365
8539
|
const bySlugHelperImports = ["formatActionDate"];
|
|
8540
|
+
if (ctx.hasSelectFields) bySlugHelperImports.push(`resolve${ctx.Singular}SelectFields`);
|
|
8366
8541
|
if (ctx.hasListRels) bySlugHelperImports.push(`populate${ctx.Singular}ListRelationships`);
|
|
8367
8542
|
if (ctx.hasMediaFields) bySlugHelperImports.push(`resolve${ctx.Singular}MediaFields`);
|
|
8368
8543
|
const populateImport = bySlugHelperImports.length > 0 ? `
|
|
@@ -8398,7 +8573,7 @@ export async function get${ctx.Singular}BySlug(slug: string): Promise<${ctx.Sing
|
|
|
8398
8573
|
function genCreateContent(ctx) {
|
|
8399
8574
|
const kebabSingular = toKebabCase(ctx.singular);
|
|
8400
8575
|
const snapshotImport = ctx.hasM2M ? `build${ctx.Singular}VersionSnapshotWithRelationships` : `build${ctx.Singular}VersionSnapshot`;
|
|
8401
|
-
const snapshotData = ctx.hasM2M ? `await build${ctx.Singular}VersionSnapshotWithRelationships(createdRow as ${ctx.Singular}, tx)` : `build${ctx.Singular}VersionSnapshot(createdRow as ${ctx.Singular})`;
|
|
8576
|
+
const snapshotData = ctx.hasM2M ? `await build${ctx.Singular}VersionSnapshotWithRelationships(createdRow as unknown as ${ctx.Singular}, tx)` : `build${ctx.Singular}VersionSnapshot(createdRow as unknown as ${ctx.Singular})`;
|
|
8402
8577
|
const slugImport = ctx.hasAutoSlug ? `
|
|
8403
8578
|
import { slugify } from '@admin/utils/validation/validation'` : "";
|
|
8404
8579
|
const markdownImport = ctx.hasHtmlOutput ? `
|
|
@@ -8492,7 +8667,7 @@ ${ctx.htmlCreateMappings},` : ""}${ctx.hasDraft ? `
|
|
|
8492
8667
|
typeof created${ctx.Singular}Id === 'string'
|
|
8493
8668
|
? await get${ctx.Singular}ById(created${ctx.Singular}Id)
|
|
8494
8669
|
: null
|
|
8495
|
-
const created${ctx.Singular}Data = created${ctx.Singular} ?? (result[0] as ${ctx.Singular})
|
|
8670
|
+
const created${ctx.Singular}Data = created${ctx.Singular} ?? (result[0] as unknown as ${ctx.Singular})
|
|
8496
8671
|
const created${ctx.Singular}Context = ${createResultContext}
|
|
8497
8672
|
${afterHook("afterCreate", `created${ctx.Singular}Context`)}
|
|
8498
8673
|
${createAfterPublishBlock}
|
|
@@ -8511,7 +8686,7 @@ ${createAfterPublishBlock}
|
|
|
8511
8686
|
function genUpdateContent(ctx) {
|
|
8512
8687
|
const kebabSingular = toKebabCase(ctx.singular);
|
|
8513
8688
|
const snapshotImport = ctx.hasM2M ? `build${ctx.Singular}VersionSnapshotWithRelationships` : `build${ctx.Singular}VersionSnapshot`;
|
|
8514
|
-
const previousSnapshot = ctx.hasM2M ? `await build${ctx.Singular}VersionSnapshotWithRelationships(previousRow as ${ctx.Singular}, tx)` : `build${ctx.Singular}VersionSnapshot(previousRow as ${ctx.Singular})`;
|
|
8689
|
+
const previousSnapshot = ctx.hasM2M ? `await build${ctx.Singular}VersionSnapshotWithRelationships(previousRow as unknown as ${ctx.Singular}, tx)` : `build${ctx.Singular}VersionSnapshot(previousRow as unknown as ${ctx.Singular})`;
|
|
8515
8690
|
const slugImport = ctx.hasAutoSlug ? `
|
|
8516
8691
|
import { slugify } from '@admin/utils/validation/validation'` : "";
|
|
8517
8692
|
const markdownImport = ctx.hasHtmlOutput ? `
|
|
@@ -8635,7 +8810,7 @@ ${htmlUpdateBlock}
|
|
|
8635
8810
|
${ctx.cacheInvalidationFn}(${ctx.camelPlural}CacheTags.byId(id))
|
|
8636
8811
|
${ctx.cacheInvalidationFn}(entityVersionsCacheTags.for('${ctx.plural}', id))
|
|
8637
8812
|
const updated${ctx.Singular} = await get${ctx.Singular}ById(id)
|
|
8638
|
-
const updated${ctx.Singular}Data = updated${ctx.Singular} ?? (result[0] as ${ctx.Singular})
|
|
8813
|
+
const updated${ctx.Singular}Data = updated${ctx.Singular} ?? (result[0] as unknown as ${ctx.Singular})
|
|
8639
8814
|
const updated${ctx.Singular}Context = ${updateResultContext}
|
|
8640
8815
|
${updateAfterPublishBlock}
|
|
8641
8816
|
${afterHook("afterUpdate", `updated${ctx.Singular}Context`)}
|
|
@@ -8690,7 +8865,7 @@ function buildRestoreManyToManyStatements(ctx) {
|
|
|
8690
8865
|
function genRestoreContent(ctx) {
|
|
8691
8866
|
const kebabSingular = toKebabCase(ctx.singular);
|
|
8692
8867
|
const snapshotImport = ctx.hasM2M ? `build${ctx.Singular}VersionSnapshotWithRelationships` : `build${ctx.Singular}VersionSnapshot`;
|
|
8693
|
-
const currentSnapshot = ctx.hasM2M ? `await build${ctx.Singular}VersionSnapshotWithRelationships(currentRow as ${ctx.Singular}, tx)` : `build${ctx.Singular}VersionSnapshot(currentRow as ${ctx.Singular})`;
|
|
8868
|
+
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})`;
|
|
8694
8869
|
const dbImports = [
|
|
8695
8870
|
"entityVersions",
|
|
8696
8871
|
ctx.tableVar,
|
|
@@ -8769,7 +8944,7 @@ ${restoreM2M}
|
|
|
8769
8944
|
|
|
8770
8945
|
return {
|
|
8771
8946
|
success: true,
|
|
8772
|
-
${ctx.camelSingular}: restored${ctx.Singular} ?? (result[0] as ${ctx.Singular})
|
|
8947
|
+
${ctx.camelSingular}: restored${ctx.Singular} ?? (result[0] as unknown as ${ctx.Singular})
|
|
8773
8948
|
}
|
|
8774
8949
|
} catch (error) {
|
|
8775
8950
|
console.error('Error restoring ${ctx.singular} version:', error)
|
|
@@ -9812,6 +9987,8 @@ function buildEntityContext(schema, nextMajorVersion) {
|
|
|
9812
9987
|
(f) => f.type === "select" && f.creatable === true
|
|
9813
9988
|
);
|
|
9814
9989
|
const hasCreatableSelectFields = creatableSelectFields.length > 0;
|
|
9990
|
+
const selectFields = collectReadSelectFields(allDbFields);
|
|
9991
|
+
const hasSelectFields = selectFields.length > 0;
|
|
9815
9992
|
const dateRangeFilterFields = new Set(
|
|
9816
9993
|
resolvedFilters.filter((filter) => filter.type === "date-range").map((filter) => filter.field)
|
|
9817
9994
|
);
|
|
@@ -9835,7 +10012,7 @@ function buildEntityContext(schema, nextMajorVersion) {
|
|
|
9835
10012
|
const relTableImports = relationshipFields.map((f) => toCamelCase(f.relationship));
|
|
9836
10013
|
const listRelTableImports = allListRelQueries.map((q) => q.relTable);
|
|
9837
10014
|
const dataFields = allDbFields.map(
|
|
9838
|
-
(f) => ` ${quotePropertyName(f.name)}: ${
|
|
10015
|
+
(f) => ` ${quotePropertyName(f.name)}: ${getReadFieldType(f)}${f.type === "select" || f.required || f.primaryKey ? "" : " | null"}`
|
|
9839
10016
|
).join("\n");
|
|
9840
10017
|
const m2mFieldTypes = m2mFields.map((f) => ` ${quotePropertyName(f.name)}: string[]`).join("\n");
|
|
9841
10018
|
const htmlFieldTypes = htmlOutputFields.map((f) => ` ${f.name}Html: string`).join("\n");
|
|
@@ -9849,7 +10026,10 @@ import type { AdminMedia } from '@admin/types'
|
|
|
9849
10026
|
const hasTimestampFields = allDbFields.some((f) => f.name === "createdAt") && allDbFields.some((f) => f.name === "updatedAt");
|
|
9850
10027
|
const hasFormattedTimestampFields = allDbFields.some((f) => f.name === "createdAtFormatted");
|
|
9851
10028
|
const timestampFields = hasTimestampFields && !hasFormattedTimestampFields ? "\n createdAtFormatted: string\n updatedAtFormatted: string" : "";
|
|
9852
|
-
const
|
|
10029
|
+
const readSelectOptionType = buildReadSelectOptionType(selectFields);
|
|
10030
|
+
const dataInterface = `${mediaTypeImport}${buildAuthorshipUserType()}${readSelectOptionType ? `
|
|
10031
|
+
|
|
10032
|
+
${readSelectOptionType}` : ""}
|
|
9853
10033
|
|
|
9854
10034
|
export interface ${Singular} {
|
|
9855
10035
|
${dataFields}${htmlFieldTypes ? `
|
|
@@ -9954,7 +10134,8 @@ ${searchFields.map((f) => ` ilike(${tableVar}.${f}, searchTerm)`).join(
|
|
|
9954
10134
|
Singular,
|
|
9955
10135
|
hasListRels
|
|
9956
10136
|
);
|
|
9957
|
-
const
|
|
10137
|
+
const selectResultMapping = hasSelectFields ? wrapWithSelectResolution(baseResultMapping, camelPlural, Singular) : baseResultMapping;
|
|
10138
|
+
const resultMapping = hasMediaFields ? wrapWithMediaResolution(selectResultMapping, camelPlural, Singular) : selectResultMapping;
|
|
9958
10139
|
const baseListResultMapping = hasHtmlOutput ? buildResultMapping(
|
|
9959
10140
|
listDbFields,
|
|
9960
10141
|
relationshipFields,
|
|
@@ -9963,7 +10144,8 @@ ${searchFields.map((f) => ` ilike(${tableVar}.${f}, searchTerm)`).join(
|
|
|
9963
10144
|
Singular,
|
|
9964
10145
|
hasListRels
|
|
9965
10146
|
) : baseResultMapping;
|
|
9966
|
-
const
|
|
10147
|
+
const selectListResultMapping = hasSelectFields ? wrapWithSelectResolution(baseListResultMapping, camelPlural, Singular) : baseListResultMapping;
|
|
10148
|
+
const listResultMapping = hasMediaFields ? wrapWithMediaResolution(selectListResultMapping, camelPlural, Singular) : selectListResultMapping;
|
|
9967
10149
|
const fieldMeta = createFields.map((f) => `{ name: '${f.name}', type: '${f.type}', required: ${f.required ?? false} }`).join(",\n ");
|
|
9968
10150
|
const createMappings = createFields.map((f) => ` ${f.name}: ${generateFieldMapping(f)}`).join(",\n");
|
|
9969
10151
|
const htmlCreateBlock = hasHtmlOutput ? `
|
|
@@ -10004,9 +10186,11 @@ ${searchFields.map((f) => ` ilike(${tableVar}.${f}, searchTerm)`).join(
|
|
|
10004
10186
|
return `const row = result[0]
|
|
10005
10187
|
return ${singleRowMapping}`;
|
|
10006
10188
|
})();
|
|
10007
|
-
const
|
|
10008
|
-
|
|
10009
|
-
|
|
10189
|
+
const singleRowResolvers = [
|
|
10190
|
+
...hasSelectFields ? [`resolve${Singular}SelectFields`] : [],
|
|
10191
|
+
...hasMediaFields ? [`resolve${Singular}MediaFields`] : []
|
|
10192
|
+
];
|
|
10193
|
+
const singleRowReturn = singleRowResolvers.length > 0 ? wrapSingleRowReturnWithResolvers(baseSingleRowReturn, singleRowResolvers) : baseSingleRowReturn;
|
|
10010
10194
|
const nextMajor = nextMajorVersion ?? 16;
|
|
10011
10195
|
const cacheInvalidationFn = nextMajor >= 16 ? "updateTag" : "revalidateTag";
|
|
10012
10196
|
const cacheReadImport = nextMajor >= 16 ? `import { cacheLife, cacheTag } from 'next/cache'` : `import { unstable_cacheTag as cacheTag } from 'next/cache'`;
|
|
@@ -10036,9 +10220,11 @@ ${searchFields.map((f) => ` ilike(${tableVar}.${f}, searchTerm)`).join(
|
|
|
10036
10220
|
hasSearch,
|
|
10037
10221
|
hasFilters,
|
|
10038
10222
|
hasAutoSlug,
|
|
10223
|
+
hasSelectFields,
|
|
10039
10224
|
hasCreatableSelectFields,
|
|
10040
10225
|
searchFields,
|
|
10041
10226
|
htmlOutputFields,
|
|
10227
|
+
selectFields,
|
|
10042
10228
|
creatableSelectFields,
|
|
10043
10229
|
m2mFields,
|
|
10044
10230
|
filterableFields,
|
|
@@ -10089,11 +10275,135 @@ function wrapWithMediaResolution(mapping, camelPlural, Singular) {
|
|
|
10089
10275
|
}
|
|
10090
10276
|
return mapping.replace(
|
|
10091
10277
|
new RegExp(`${camelPlural}: (results as ${Singular}\\[\\])`),
|
|
10092
|
-
`${camelPlural}: await resolve${Singular}MediaFields($1)`
|
|
10278
|
+
`${camelPlural}: await resolve${Singular}MediaFields($1 as unknown as ${Singular}[])`
|
|
10093
10279
|
);
|
|
10094
10280
|
}
|
|
10281
|
+
function wrapWithSelectResolution(mapping, camelPlural, Singular) {
|
|
10282
|
+
const returnPattern = new RegExp(
|
|
10283
|
+
`return \\{\\n\\s+${camelPlural}: ([^,]+),\\n\\s+total\\n\\s+\\}`
|
|
10284
|
+
);
|
|
10285
|
+
const match = mapping.match(returnPattern);
|
|
10286
|
+
if (match) {
|
|
10287
|
+
const arrayExpr = match[1].trim();
|
|
10288
|
+
return mapping.replace(
|
|
10289
|
+
match[0],
|
|
10290
|
+
`const resolved${Singular}SelectFields = await resolve${Singular}SelectFields(${arrayExpr})
|
|
10291
|
+
|
|
10292
|
+
return {
|
|
10293
|
+
${camelPlural}: resolved${Singular}SelectFields,
|
|
10294
|
+
total
|
|
10295
|
+
}`
|
|
10296
|
+
);
|
|
10297
|
+
}
|
|
10298
|
+
return mapping.replace(
|
|
10299
|
+
new RegExp(`${camelPlural}: (results as ${Singular}\\[\\])`),
|
|
10300
|
+
`${camelPlural}: await resolve${Singular}SelectFields($1 as unknown as ${Singular}[])`
|
|
10301
|
+
);
|
|
10302
|
+
}
|
|
10303
|
+
function wrapSingleRowReturnWithResolvers(singleRowReturn, resolvers) {
|
|
10304
|
+
return singleRowReturn.replace(/return ([\s\S]+)$/, (_, expression) => {
|
|
10305
|
+
const lines = [`const singleRow = ${expression}`];
|
|
10306
|
+
let current = "singleRow";
|
|
10307
|
+
for (const resolver of resolvers) {
|
|
10308
|
+
const resolvedName = resolver.replace(/^resolve/, "resolved").replace(/Fields$/, "Row");
|
|
10309
|
+
lines.push(` const [${resolvedName}] = await ${resolver}([${current}])`);
|
|
10310
|
+
current = resolvedName;
|
|
10311
|
+
}
|
|
10312
|
+
lines.push(` return ${current}`);
|
|
10313
|
+
return lines.join("\n");
|
|
10314
|
+
});
|
|
10315
|
+
}
|
|
10095
10316
|
|
|
10096
10317
|
// adapters/next/generators/actions/single-actions.ts
|
|
10318
|
+
function generateSingleResolveSelectFieldsFunction(Singular, selectFields, selectOptionsTableVar, hasCreatableSelectFields) {
|
|
10319
|
+
const staticLabelMaps = selectFields.map((readField) => {
|
|
10320
|
+
const key = readField.path.join(".");
|
|
10321
|
+
const entries = (readField.field.options ?? []).map((option) => `${JSON.stringify(option.value)}: ${JSON.stringify(option.label)}`).join(", ");
|
|
10322
|
+
return ` ${JSON.stringify(key)}: { ${entries} }`;
|
|
10323
|
+
}).join(",\n");
|
|
10324
|
+
const dynamicRowsBlock = hasCreatableSelectFields ? `
|
|
10325
|
+
const dynamicRows = await db
|
|
10326
|
+
.select({
|
|
10327
|
+
fieldName: ${selectOptionsTableVar}.fieldName,
|
|
10328
|
+
label: ${selectOptionsTableVar}.label,
|
|
10329
|
+
value: ${selectOptionsTableVar}.value
|
|
10330
|
+
})
|
|
10331
|
+
.from(${selectOptionsTableVar})
|
|
10332
|
+
|
|
10333
|
+
for (const row of dynamicRows) {
|
|
10334
|
+
labelMaps[row.fieldName] ??= {}
|
|
10335
|
+
labelMaps[row.fieldName][row.value] = row.label
|
|
10336
|
+
}
|
|
10337
|
+
` : "";
|
|
10338
|
+
const assignments = selectFields.map((readField) => {
|
|
10339
|
+
const key = readField.path.join(".");
|
|
10340
|
+
return ` resolveSelectFieldPath(source, ${JSON.stringify(readField.path)}, labelMaps[${JSON.stringify(key)}] ?? {})`;
|
|
10341
|
+
}).join("\n");
|
|
10342
|
+
return `const STATIC_SELECT_OPTION_LABELS = {
|
|
10343
|
+
${staticLabelMaps}
|
|
10344
|
+
} satisfies Record<string, Record<string, string>>
|
|
10345
|
+
|
|
10346
|
+
function cloneSelectOptionLabelMaps(): Record<string, Record<string, string>> {
|
|
10347
|
+
return Object.fromEntries(
|
|
10348
|
+
Object.entries(STATIC_SELECT_OPTION_LABELS).map(([fieldName, labels]) => [
|
|
10349
|
+
fieldName,
|
|
10350
|
+
{ ...labels }
|
|
10351
|
+
])
|
|
10352
|
+
)
|
|
10353
|
+
}
|
|
10354
|
+
|
|
10355
|
+
function toSelectOptionValues(value: unknown, labels: Record<string, string>): SelectOptionValue[] {
|
|
10356
|
+
const values = Array.isArray(value) ? value : value ? [value] : []
|
|
10357
|
+
|
|
10358
|
+
return values
|
|
10359
|
+
.filter((item): item is string => typeof item === 'string' && item.length > 0)
|
|
10360
|
+
.map((item) => ({
|
|
10361
|
+
label: labels[item] ?? item,
|
|
10362
|
+
value: item
|
|
10363
|
+
}))
|
|
10364
|
+
}
|
|
10365
|
+
|
|
10366
|
+
function resolveSelectFieldPath(
|
|
10367
|
+
source: Record<string, unknown>,
|
|
10368
|
+
path: readonly string[],
|
|
10369
|
+
labels: Record<string, string>
|
|
10370
|
+
): void {
|
|
10371
|
+
const [fieldName, ...rest] = path
|
|
10372
|
+
if (!fieldName) return
|
|
10373
|
+
|
|
10374
|
+
if (rest.length === 0) {
|
|
10375
|
+
source[fieldName] = toSelectOptionValues(source[fieldName], labels)
|
|
10376
|
+
return
|
|
10377
|
+
}
|
|
10378
|
+
|
|
10379
|
+
const value = source[fieldName]
|
|
10380
|
+
if (Array.isArray(value)) {
|
|
10381
|
+
for (const item of value) {
|
|
10382
|
+
if (item && typeof item === 'object') {
|
|
10383
|
+
resolveSelectFieldPath(item as Record<string, unknown>, rest, labels)
|
|
10384
|
+
}
|
|
10385
|
+
}
|
|
10386
|
+
return
|
|
10387
|
+
}
|
|
10388
|
+
|
|
10389
|
+
if (value && typeof value === 'object') {
|
|
10390
|
+
resolveSelectFieldPath(value as Record<string, unknown>, rest, labels)
|
|
10391
|
+
}
|
|
10392
|
+
}
|
|
10393
|
+
|
|
10394
|
+
async function resolve${Singular}SelectFields(rows: ${Singular}[]): Promise<${Singular}[]> {
|
|
10395
|
+
if (rows.length === 0) return rows
|
|
10396
|
+
|
|
10397
|
+
const labelMaps = cloneSelectOptionLabelMaps()
|
|
10398
|
+
${dynamicRowsBlock}
|
|
10399
|
+
for (const row of rows) {
|
|
10400
|
+
const source = row as unknown as Record<string, unknown>
|
|
10401
|
+
${assignments}
|
|
10402
|
+
}
|
|
10403
|
+
|
|
10404
|
+
return rows
|
|
10405
|
+
}`;
|
|
10406
|
+
}
|
|
10097
10407
|
function generateSingleActions(schema, actionsDir, options = {}) {
|
|
10098
10408
|
const singular = singularize(schema.name);
|
|
10099
10409
|
const plural = pluralize(schema.name);
|
|
@@ -10113,6 +10423,8 @@ function generateSingleActions(schema, actionsDir, options = {}) {
|
|
|
10113
10423
|
(field) => field.type === "select" && field.creatable === true
|
|
10114
10424
|
);
|
|
10115
10425
|
const hasCreatableSelectFields = creatableSelectFields.length > 0;
|
|
10426
|
+
const selectFields = collectReadSelectFields(dbFields);
|
|
10427
|
+
const hasSelectFields = selectFields.length > 0;
|
|
10116
10428
|
const allDbFields = [...dbFields];
|
|
10117
10429
|
if (!dbFields.some((f) => f.name === "createdAt")) {
|
|
10118
10430
|
allDbFields.push({ name: "createdAt", type: "timestamp", required: true });
|
|
@@ -10129,7 +10441,7 @@ function generateSingleActions(schema, actionsDir, options = {}) {
|
|
|
10129
10441
|
(f) => !f.primaryKey && f.name !== "createdAt" && f.name !== "updatedAt" && !isAuthorshipFieldName(f.name)
|
|
10130
10442
|
);
|
|
10131
10443
|
const dataFields = allDbFields.map(
|
|
10132
|
-
(f) => ` ${quotePropertyName(f.name)}: ${
|
|
10444
|
+
(f) => ` ${quotePropertyName(f.name)}: ${getReadFieldType(f)}${f.type === "select" || f.required || f.primaryKey ? "" : " | null"}`
|
|
10133
10445
|
).join("\n");
|
|
10134
10446
|
const htmlFieldTypes = htmlOutputFields.map((f) => ` ${f.name}Html: string`).join("\n");
|
|
10135
10447
|
const hasTimestampFields = allDbFields.some((f) => f.name === "createdAt") && allDbFields.some((f) => f.name === "updatedAt");
|
|
@@ -10158,6 +10470,7 @@ function generateSingleActions(schema, actionsDir, options = {}) {
|
|
|
10158
10470
|
};
|
|
10159
10471
|
const typesContent = `${[
|
|
10160
10472
|
buildAuthorshipUserType(),
|
|
10473
|
+
buildReadSelectOptionType(selectFields),
|
|
10161
10474
|
`export interface ${Singular} {
|
|
10162
10475
|
${dataFields}${htmlFieldTypes ? `
|
|
10163
10476
|
${htmlFieldTypes}` : ""}${timestampFields}
|
|
@@ -10186,17 +10499,29 @@ ${upsertInterfaceFields}
|
|
|
10186
10499
|
authorshipSelects,
|
|
10187
10500
|
authorshipJoins
|
|
10188
10501
|
);
|
|
10189
|
-
const
|
|
10190
|
-
|
|
10502
|
+
const singleRowMapping = buildSingleRowMapping(allDbFields, [], `${Singular}`, htmlOutputFields);
|
|
10503
|
+
const singleRowReturn = hasSelectFields ? `const row = result[0]
|
|
10504
|
+
const singleRow = ${singleRowMapping}
|
|
10505
|
+
const [resolvedSelectRow] = await resolve${Singular}SelectFields([singleRow])
|
|
10506
|
+
return resolvedSelectRow` : `const row = result[0]
|
|
10507
|
+
return ${singleRowMapping}`;
|
|
10508
|
+
const getDbImports = [
|
|
10509
|
+
tableVar,
|
|
10510
|
+
"user",
|
|
10511
|
+
...hasCreatableSelectFields ? [`${tableVar}SelectOptions`] : []
|
|
10512
|
+
].sort();
|
|
10513
|
+
const selectResolutionFunctions = hasSelectFields ? `
|
|
10514
|
+
${generateSingleResolveSelectFieldsFunction(Singular, selectFields, `${tableVar}SelectOptions`, hasCreatableSelectFields)}
|
|
10515
|
+
` : "";
|
|
10191
10516
|
const getContent = `'use server'
|
|
10192
10517
|
|
|
10193
10518
|
import db from '@admin/db'
|
|
10194
|
-
import { ${
|
|
10519
|
+
import { ${getDbImports.join(", ")} } from '@admin/db/schema'
|
|
10195
10520
|
import { eq } from 'drizzle-orm'
|
|
10196
10521
|
import { alias } from 'drizzle-orm/pg-core'
|
|
10197
10522
|
${cacheReadImport}
|
|
10198
10523
|
import { ${cacheTagsVar} } from './types'
|
|
10199
|
-
import type { ${Singular} } from './types'
|
|
10524
|
+
import type { ${Singular}${hasSelectFields ? ", SelectOptionValue" : ""} } from './types'
|
|
10200
10525
|
|
|
10201
10526
|
${buildAuthorshipAliasBlock()}
|
|
10202
10527
|
|
|
@@ -10214,7 +10539,7 @@ function formatActionDate(value: unknown): string {
|
|
|
10214
10539
|
timeZone: 'UTC'
|
|
10215
10540
|
})
|
|
10216
10541
|
}
|
|
10217
|
-
|
|
10542
|
+
${selectResolutionFunctions}
|
|
10218
10543
|
export async function get${Singular}(): Promise<${Singular} | null> {
|
|
10219
10544
|
'use cache'${cacheLifeLine}
|
|
10220
10545
|
cacheTag(${cacheTagsVar}.all)
|
|
@@ -10294,7 +10619,7 @@ ${htmlUpsertBlock}
|
|
|
10294
10619
|
|
|
10295
10620
|
return {
|
|
10296
10621
|
success: true,
|
|
10297
|
-
${camelSingular}: saved${Singular} ?? (result[0] as ${Singular})
|
|
10622
|
+
${camelSingular}: saved${Singular} ?? (result[0] as unknown as ${Singular})
|
|
10298
10623
|
}
|
|
10299
10624
|
} catch (error) {
|
|
10300
10625
|
console.error('Error upserting ${singular}:', error)
|
|
@@ -10523,6 +10848,22 @@ function fieldHasMediaCompanion(column, fields) {
|
|
|
10523
10848
|
const field = fields.find((item) => item.name === column.accessorKey);
|
|
10524
10849
|
return field?.type === "image" || field?.type === "media" || field?.type === "video";
|
|
10525
10850
|
}
|
|
10851
|
+
function fieldIsSelect(column, fields) {
|
|
10852
|
+
return fields.find((item) => item.name === column.accessorKey)?.type === "select";
|
|
10853
|
+
}
|
|
10854
|
+
function generateSelectLabel(valueExpression) {
|
|
10855
|
+
return `const label = Array.isArray(${valueExpression})
|
|
10856
|
+
? ${valueExpression}
|
|
10857
|
+
.map((option) =>
|
|
10858
|
+
typeof option === 'object' && option !== null && 'label' in option
|
|
10859
|
+
? String(option.label)
|
|
10860
|
+
: String(option)
|
|
10861
|
+
)
|
|
10862
|
+
.join(', ')
|
|
10863
|
+
: ${valueExpression} === null || ${valueExpression} === undefined
|
|
10864
|
+
? null
|
|
10865
|
+
: String(${valueExpression})`;
|
|
10866
|
+
}
|
|
10526
10867
|
function buildImageUrlExpression(column, fields, fallbackExpression) {
|
|
10527
10868
|
const fallback = `(${fallbackExpression} as string | null | undefined)`;
|
|
10528
10869
|
if (!fieldHasMediaCompanion(column, fields)) {
|
|
@@ -10603,6 +10944,7 @@ function generateColumnDef2(column, fields) {
|
|
|
10603
10944
|
}` : `header: '${column.header}'`;
|
|
10604
10945
|
let cellDef = "";
|
|
10605
10946
|
const authorshipUserAccessor = getAuthorshipUserAccessor(column.accessorKey);
|
|
10947
|
+
const isSelectColumn = fieldIsSelect(column, fields);
|
|
10606
10948
|
if (authorshipUserAccessor) {
|
|
10607
10949
|
cellDef = `cell: ({ row }) => {
|
|
10608
10950
|
${generateAuthorshipValue(authorshipUserAccessor)}
|
|
@@ -10623,7 +10965,15 @@ function generateColumnDef2(column, fields) {
|
|
|
10623
10965
|
}`;
|
|
10624
10966
|
break;
|
|
10625
10967
|
case "badge":
|
|
10626
|
-
cellDef = `cell: ({ row }) => {
|
|
10968
|
+
cellDef = isSelectColumn ? `cell: ({ row }) => {
|
|
10969
|
+
const value = row.getValue('${column.accessorKey}')
|
|
10970
|
+
${generateSelectLabel("value")}
|
|
10971
|
+
return (
|
|
10972
|
+
<Badge variant="outline">
|
|
10973
|
+
{label || 'Unavailable'}
|
|
10974
|
+
</Badge>
|
|
10975
|
+
)
|
|
10976
|
+
}` : `cell: ({ row }) => {
|
|
10627
10977
|
const value = row.getValue('${column.accessorKey}')
|
|
10628
10978
|
return (
|
|
10629
10979
|
<Badge variant="outline">
|
|
@@ -10705,14 +11055,22 @@ function generateColumnDef2(column, fields) {
|
|
|
10705
11055
|
return <${column.component} data={row.original} />
|
|
10706
11056
|
}`;
|
|
10707
11057
|
} else {
|
|
10708
|
-
cellDef = `cell: ({ row }) => {
|
|
11058
|
+
cellDef = isSelectColumn ? `cell: ({ row }) => {
|
|
11059
|
+
const value = row.getValue('${column.accessorKey}')
|
|
11060
|
+
${generateSelectLabel("value")}
|
|
11061
|
+
return <div>{label || 'Unavailable'}</div>
|
|
11062
|
+
}` : `cell: ({ row }) => {
|
|
10709
11063
|
const value = row.getValue('${column.accessorKey}')
|
|
10710
11064
|
return <div>{value === null || value === undefined ? 'Unavailable' : String(value)}</div>
|
|
10711
11065
|
}`;
|
|
10712
11066
|
}
|
|
10713
11067
|
break;
|
|
10714
11068
|
default:
|
|
10715
|
-
cellDef = `cell: ({ row }) => {
|
|
11069
|
+
cellDef = isSelectColumn ? `cell: ({ row }) => {
|
|
11070
|
+
const value = row.getValue('${column.accessorKey}')
|
|
11071
|
+
${generateSelectLabel("value")}
|
|
11072
|
+
return <div>{label || 'Unavailable'}</div>
|
|
11073
|
+
}` : `cell: ({ row }) => {
|
|
10716
11074
|
const value = row.getValue('${column.accessorKey}')
|
|
10717
11075
|
return <div>{value === null || value === undefined ? 'Unavailable' : String(value)}</div>
|
|
10718
11076
|
}`;
|
|
@@ -10754,6 +11112,7 @@ function generateFirstColumnDef(column, fields, options = {}) {
|
|
|
10754
11112
|
)`;
|
|
10755
11113
|
let cellDef = "";
|
|
10756
11114
|
const authorshipUserAccessor = getAuthorshipUserAccessor(column.accessorKey);
|
|
11115
|
+
const isSelectColumn = fieldIsSelect(column, fields);
|
|
10757
11116
|
if (authorshipUserAccessor) {
|
|
10758
11117
|
cellDef = `cell: ({ row }) => {
|
|
10759
11118
|
${generateAuthorshipValue(authorshipUserAccessor)}
|
|
@@ -10785,7 +11144,22 @@ function generateFirstColumnDef(column, fields, options = {}) {
|
|
|
10785
11144
|
}`;
|
|
10786
11145
|
break;
|
|
10787
11146
|
case "badge":
|
|
10788
|
-
cellDef = `cell: ({ row }) => {
|
|
11147
|
+
cellDef = isSelectColumn ? `cell: ({ row }) => {
|
|
11148
|
+
const value = row.original.${column.accessorKey}
|
|
11149
|
+
${generateSelectLabel("value")}
|
|
11150
|
+
return (
|
|
11151
|
+
<div className="flex items-center gap-4 h-full pl-1">
|
|
11152
|
+
<Checkbox
|
|
11153
|
+
checked={row.getIsSelected()}
|
|
11154
|
+
onCheckedChange={(value) => row.toggleSelected(!!value)}
|
|
11155
|
+
aria-label="Select row"
|
|
11156
|
+
/>
|
|
11157
|
+
<Badge variant="outline">
|
|
11158
|
+
{label || 'Unavailable'}
|
|
11159
|
+
</Badge>
|
|
11160
|
+
</div>
|
|
11161
|
+
)
|
|
11162
|
+
}` : `cell: ({ row }) => {
|
|
10789
11163
|
const value = row.original.${column.accessorKey}
|
|
10790
11164
|
return (
|
|
10791
11165
|
<div className="flex items-center gap-4 h-full pl-1">
|
|
@@ -10908,7 +11282,22 @@ function generateFirstColumnDef(column, fields, options = {}) {
|
|
|
10908
11282
|
)
|
|
10909
11283
|
}`;
|
|
10910
11284
|
} else {
|
|
10911
|
-
cellDef = `cell: ({ row }) => {
|
|
11285
|
+
cellDef = isSelectColumn ? `cell: ({ row }) => {
|
|
11286
|
+
const value = row.original.${column.accessorKey}
|
|
11287
|
+
${generateSelectLabel("value")}
|
|
11288
|
+
return (
|
|
11289
|
+
<div className="flex items-center gap-4 h-full pl-1">
|
|
11290
|
+
<Checkbox
|
|
11291
|
+
checked={row.getIsSelected()}
|
|
11292
|
+
onCheckedChange={(value) => row.toggleSelected(!!value)}
|
|
11293
|
+
aria-label="Select row"
|
|
11294
|
+
/>
|
|
11295
|
+
<span className="truncate max-w-[300px]">
|
|
11296
|
+
{label || 'Unavailable'}
|
|
11297
|
+
</span>
|
|
11298
|
+
</div>
|
|
11299
|
+
)
|
|
11300
|
+
}` : `cell: ({ row }) => {
|
|
10912
11301
|
const value = row.original.${column.accessorKey}
|
|
10913
11302
|
return (
|
|
10914
11303
|
<div className="flex items-center gap-4 h-full pl-1">
|
|
@@ -10954,7 +11343,22 @@ function generateFirstColumnDef(column, fields, options = {}) {
|
|
|
10954
11343
|
}`;
|
|
10955
11344
|
break;
|
|
10956
11345
|
default:
|
|
10957
|
-
cellDef = `cell: ({ row }) => {
|
|
11346
|
+
cellDef = isSelectColumn ? `cell: ({ row }) => {
|
|
11347
|
+
const value = row.original.${column.accessorKey}
|
|
11348
|
+
${generateSelectLabel("value")}
|
|
11349
|
+
return (
|
|
11350
|
+
<div className="flex items-center gap-4 h-full pl-1">
|
|
11351
|
+
<Checkbox
|
|
11352
|
+
checked={row.getIsSelected()}
|
|
11353
|
+
onCheckedChange={(value) => row.toggleSelected(!!value)}
|
|
11354
|
+
aria-label="Select row"
|
|
11355
|
+
/>
|
|
11356
|
+
<span className="truncate max-w-[300px]">
|
|
11357
|
+
{label || 'Unavailable'}
|
|
11358
|
+
</span>
|
|
11359
|
+
</div>
|
|
11360
|
+
)
|
|
11361
|
+
}` : `cell: ({ row }) => {
|
|
10958
11362
|
const value = row.original.${column.accessorKey}
|
|
10959
11363
|
return (
|
|
10960
11364
|
<div className="flex items-center gap-4 h-full pl-1">
|
|
@@ -11626,9 +12030,38 @@ function defaultFallbackValue(f) {
|
|
|
11626
12030
|
function hasInitialValueExpression(fieldName, dataSource = "initialData") {
|
|
11627
12031
|
return `${dataSource}?.${fieldName} !== undefined && ${dataSource}?.${fieldName} !== null && ${dataSource}?.${fieldName} !== ''`;
|
|
11628
12032
|
}
|
|
12033
|
+
function selectReadValuesExpression(fieldName, dataSource = "initialData") {
|
|
12034
|
+
return `(() => {
|
|
12035
|
+
const selectValue = ${dataSource}?.${fieldName} as unknown
|
|
12036
|
+
const values = Array.isArray(selectValue) ? selectValue : [selectValue]
|
|
12037
|
+
return values
|
|
12038
|
+
.map((option) => {
|
|
12039
|
+
if (typeof option === 'string') return option
|
|
12040
|
+
if (option && typeof option === 'object' && 'value' in option) {
|
|
12041
|
+
return String(option.value)
|
|
12042
|
+
}
|
|
12043
|
+
return null
|
|
12044
|
+
})
|
|
12045
|
+
.filter((value): value is string => typeof value === 'string' && value.length > 0)
|
|
12046
|
+
})()`;
|
|
12047
|
+
}
|
|
11629
12048
|
function generateDefaultValue(f, fieldMap, dataSource = "initialData") {
|
|
11630
12049
|
if (f.defaultValueFrom && f.defaultValueFrom.trim() !== f.name && fieldMap?.has(f.defaultValueFrom.trim())) {
|
|
11631
12050
|
const sourceName = f.defaultValueFrom.trim();
|
|
12051
|
+
if (f.type === "select") {
|
|
12052
|
+
const targetValuesExpression = selectReadValuesExpression(f.name, dataSource);
|
|
12053
|
+
const sourceValuesExpression = selectReadValuesExpression(sourceName, dataSource);
|
|
12054
|
+
if (f.multiple) {
|
|
12055
|
+
const fallback2 = JSON.stringify(selectDefaultValues(f));
|
|
12056
|
+
return ` ${f.name}: ${targetValuesExpression}.length > 0
|
|
12057
|
+
? ${targetValuesExpression}
|
|
12058
|
+
: ${sourceValuesExpression}.length > 0
|
|
12059
|
+
? ${sourceValuesExpression}
|
|
12060
|
+
: ${fallback2}`;
|
|
12061
|
+
}
|
|
12062
|
+
const fallback = f.default !== void 0 && f.default !== null ? JSON.stringify(f.default) : "''";
|
|
12063
|
+
return ` ${f.name}: ${targetValuesExpression}[0] ?? ${sourceValuesExpression}[0] ?? ${fallback}`;
|
|
12064
|
+
}
|
|
11632
12065
|
return ` ${f.name}: ${hasInitialValueExpression(f.name, dataSource)}
|
|
11633
12066
|
? ${dataSource}.${f.name}
|
|
11634
12067
|
: ${hasInitialValueExpression(sourceName, dataSource)}
|
|
@@ -11658,22 +12091,23 @@ function generateDefaultValue(f, fieldMap, dataSource = "initialData") {
|
|
|
11658
12091
|
return ` ${f.name}: ${dataSource}?.${f.name} ?? undefined`;
|
|
11659
12092
|
}
|
|
11660
12093
|
if (f.type === "select") {
|
|
12094
|
+
const selectedValuesExpression = selectReadValuesExpression(f.name, dataSource);
|
|
11661
12095
|
if (f.multiple) {
|
|
11662
12096
|
const fallback2 = JSON.stringify(selectDefaultValues(f));
|
|
11663
12097
|
if (f.creatable) {
|
|
11664
|
-
return ` ${f.name}:
|
|
12098
|
+
return ` ${f.name}: ${selectedValuesExpression}.length > 0 ? ${selectedValuesExpression} : ${fallback2}`;
|
|
11665
12099
|
}
|
|
11666
12100
|
const validValuesExpression2 = `([${(f.options || []).map((option) => JSON.stringify(option.value)).join(", ")}] as const as readonly string[])`;
|
|
11667
|
-
return ` ${f.name}:
|
|
11668
|
-
? ${
|
|
12101
|
+
return ` ${f.name}: ${selectedValuesExpression}.length > 0
|
|
12102
|
+
? ${selectedValuesExpression}.filter((value) => ${validValuesExpression2}.includes(value))
|
|
11669
12103
|
: ${fallback2}`;
|
|
11670
12104
|
}
|
|
11671
12105
|
const fallback = f.default !== void 0 && f.default !== null ? JSON.stringify(f.default) : "''";
|
|
11672
12106
|
if (f.creatable) {
|
|
11673
|
-
return ` ${f.name}:
|
|
12107
|
+
return ` ${f.name}: ${selectedValuesExpression}[0] ?? ${fallback}`;
|
|
11674
12108
|
}
|
|
11675
12109
|
const validValuesExpression = `([${(f.options || []).map((option) => JSON.stringify(option.value)).join(", ")}] as const as readonly string[])`;
|
|
11676
|
-
return ` ${f.name}:
|
|
12110
|
+
return ` ${f.name}: ${selectedValuesExpression}[0] && ${validValuesExpression}.includes(${selectedValuesExpression}[0]) ? ${selectedValuesExpression}[0] : ${fallback}`;
|
|
11677
12111
|
}
|
|
11678
12112
|
if (f.default !== void 0 && f.default !== null) {
|
|
11679
12113
|
const def = typeof f.default === "string" ? `'${f.default}'` : f.default;
|