Page Menu
Home
Sealhub
Search
Configure Global Search
Log In
Files
F995249
collection-list.ts
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
7 KB
Referenced Files
None
Subscribers
None
collection-list.ts
View Options
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";
`
;
}
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-java
Expires
Mon, Dec 23, 00:57 (4 h, 59 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
556735
Default Alt Text
collection-list.ts (7 KB)
Attached To
Mode
rSGEN sealgen
Attached
Detach File
Event Timeline
Log In to Comment