Page Menu
Home
Sealhub
Search
Configure Global Search
Log In
Files
F10361120
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
7 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/src/templates/shared/collection-list.ts b/src/templates/shared/collection-list.ts
index d3467b7..fbfa5fa 100644
--- a/src/templates/shared/collection-list.ts
+++ b/src/templates/shared/collection-list.ts
@@ -1,243 +1,243 @@
import { extractCollectionClassname } from "../../generate-collections.js";
import extract_fields_from_collection, {
ExtractedFieldInfo,
} from "../../utils/extract-fields-from-collection.js";
import _locreq from "locreq";
import { DefaultListFilters } from "../../page/default-list-filters.js";
import { toKebabCase, toPascalCase } from "js-convert-case";
import { formatWithPrettier } from "../../utils/prettier.js";
const target_locreq = _locreq(process.cwd());
function fieldImport({ type }: ExtractedFieldInfo): string {
if (type == "image") {
return `
import type { FilePointer } from "@sealcode/file-manager";
- import { imageRouter } from ""src/back/image-router.js";
+ import { imageRouter } from "src/back/image-router.js";
`;
}
return "";
}
export function makeDefaultFilterFields(
collection_fields: { name: string; type: string }[]
) {
return collection_fields
.map((field) => {
const type = field.type;
return `{ field: "${field.name}", ...${
type in DefaultListFilters
? `DefaultListFilters["${field.type}"]`
: `DefaultListFilters.fallback`
} }`;
})
.join(",\n");
}
export function makeDefaultDisplayFields(
collection_fields: { name: string; type: string }[]
) {
return collection_fields
.map((field) => {
if (field.type == "boolean") {
return ` {
field: "${field.name}",
label: "${field.name}",
format: (v: boolean) => (v ? "YES" : "NO"),
}`;
}
if (field.type == "datetime") {
return ` {
field: "${field.name}",
label: "${field.name}",
format: (v: number) => {
const d = new Date();
d.setTime(v);
return d.toString().split(" ").slice(1, 5).join(" ");
},
}`;
}
if (field.type == "image") {
return `{
field: "${field.name}",
label: "${field.name}",
format: async (value: FilePointer) => {
return imageRouter.image(await value.getPath(), {
container: { width: 45, height: 45 },
crop: { width: 45, height: 45 },
alt: "",
});
},
}`;
}
return ` { field: "${field.name}", label: "${field.name}" }`;
})
.join(",\n");
}
const default_hooks = {
pre_header_html: "",
post_header_html: "",
post_import_js: "",
render_item: (
collection_name: string
) => ` async renderItem(_ctx: Context, item: CollectionItem<typeof ${toPascalCase(
collection_name
)}>) {
return <tr>
{displayFields.map(({ field, format }) => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-explicit-any
const value = item.get(field as any);
return <td>{format ? format(value, item) : value}</td>;
})}
</tr>;
}`,
};
export async function collectionListTemplate(
collection_name: string,
action_name: string,
_: string,
_hooks: Partial<typeof default_hooks> = {}
) {
const hooks = { ...default_hooks, ..._hooks };
const [uppercase_collection, collection_fields] = await Promise.all([
extractCollectionClassname(
target_locreq.resolve(
"src/back/collections/" + collection_name + ".ts"
)
),
extract_fields_from_collection(collection_name),
]);
const field_import_string = Array.from(
new Set(collection_fields.map((field) => fieldImport(field)))
).join("\n");
const result = `import type { Context } from "koa";
import type { CollectionItem } from "sealious";
import type { FlatTemplatable, Templatable } from "tempstream";
import { TempstreamJSX, tempstream } from "tempstream";
import { ${uppercase_collection} } from "src/back/collections/collections.js";
import html from "src/back/html.js";
import type { ListFilterRender } from "@sealcode/sealgen";
import {
SealiousItemListPage,
BaseListPageFields,
DefaultListFilters,
} from "@sealcode/sealgen";
import qs from "qs";
${hooks.post_import_js}
${field_import_string}
export const actionName = "${action_name}";
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
const filterFields = [
${makeDefaultFilterFields(collection_fields)}
] as {
field: keyof (typeof ${uppercase_collection})["fields"];
render?: ListFilterRender;
prepareValue?: (filter_value: unknown)=>unknown; // set this function to change what filter value is passed to Sealious
}[];
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
const displayFields = [
${makeDefaultDisplayFields(collection_fields)}
] as {
field: string;
label: string;
format?: (value: unknown, item: CollectionItem<typeof ${toPascalCase(
collection_name
)}>) => FlatTemplatable;
}[];
export default new (class ${action_name}Page extends SealiousItemListPage<
typeof ${uppercase_collection},
typeof BaseListPageFields
> {
fields = BaseListPageFields;
async renderFilters(ctx: Context): Promise<FlatTemplatable> {
const query_params = qs.parse(ctx.search.slice(1));
query_params.page = "1";
const filter_values = await super.getFilterValues(ctx);
return <form>
{Object.entries(query_params).map(([key, value]) => {
if (key == "filter") {
return "";
}
// this is necessary to not lose any query params when the user changes the filter values
return <input type="hidden" name={key} value={value}/>;
})}
{filterFields.map(({ field, render }) => {
if (!render) {
render = DefaultListFilters.fallback.render;
}
return (
render(filter_values[field] || "", this.collection.fields[field]) ||
""
);
})}
<input type="submit" />
</form>;
}
async getFilterValues(ctx: Context) {
// adding opportunity to adjust the values for a given field filter before it's sent to Sealious
const values = await super.getFilterValues(ctx);
for (const filterField of filterFields) {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
const key = filterField.field as keyof typeof values;
if (key in values) {
const prepare_fn = filterField.prepareValue;
if (prepare_fn) {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment
values[key] = prepare_fn(values[key]) as any;
}
}
}
return values;
}
${hooks.render_item(collection_name)}
renderListContainer(ctx: Context, content: Templatable): FlatTemplatable {
return (
<table class="sealious-list ${toKebabCase(action_name)}-table">
{this.renderTableHead(ctx, displayFields)}
<tbody>{content}</tbody>
</table>
);
}
renderTableHead(
ctx: Context,
fields: { field: string; label?: string }[]
): FlatTemplatable {
return tempstream/* HTML */ \`<thead>
<tr>
\${fields.map(({ label, field }) => this.renderHeading(ctx, field, label))}
<th>Actions</th>
</tr>
</thead>\`;
}
async render(ctx: Context) {
return html({
ctx,
title: "${action_name}",
description: "",
body: <div class="sealious-list-wrapper ${toKebabCase(action_name)}--wrapper">
${hooks.pre_header_html}
<h2>${action_name} List</h2>
${hooks.post_header_html}
{super.render(ctx)}
</div>
});
}
})(${uppercase_collection});
`;
return await formatWithPrettier(result);
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Nov 8, 11:17 (20 h, 20 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1034514
Default Alt Text
(7 KB)
Attached To
Mode
rSGEN sealgen
Attached
Detach File
Event Timeline
Log In to Comment