@sealcode/sealgen 0.10.4 → 0.10.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.
@@ -12,6 +12,10 @@ export declare const BaseListPageFields: {
12
12
  readonly itemsPerPage: NumberField<12, false>;
13
13
  readonly sort: SimpleFormField<false>;
14
14
  };
15
+ export type ListSort = {
16
+ field: string;
17
+ order: "asc" | "desc";
18
+ };
15
19
  export declare abstract class ListPage<ItemType, F extends typeof BaseListPageFields> extends Page<F> {
16
20
  abstract getItems(ctx: Context, page: number, itemsPerPage: number, values: Record<string, FormDataValue>): Promise<ItemType[]>;
17
21
  abstract getTotalPages(ctx: Context, itemsPerPage: number, values: Record<string, FormDataValue>): Promise<number>;
@@ -29,13 +33,11 @@ export declare abstract class ListPage<ItemType, F extends typeof BaseListPageFi
29
33
  renderPagination(ctx: Context, values: Record<string, FormDataValue>): Promise<FlatTemplatable>;
30
34
  private renderPageButton;
31
35
  getFilterValues(ctx: Context): Promise<Record<string, unknown>>;
32
- getSort(ctx: Context): Promise<{
33
- field: string;
34
- order: "asc" | "desc";
35
- } | null>;
36
+ getSort(ctx: Context): Promise<ListSort | null>;
36
37
  makeSortLink(ctx: Context, field: string, order: "asc" | "desc"): string;
37
38
  renderFilters(ctx: Context): Promise<FlatTemplatable>;
38
39
  renderHeading(ctx: Context, field: string, label?: string): Promise<FlatTemplatable>;
40
+ getDefaultSort(_: Context): ListSort | null;
39
41
  renderTableHead(ctx: Context, fields: {
40
42
  field: string;
41
43
  label?: string;
@@ -10,6 +10,7 @@ export declare abstract class SealiousItemListPage<C extends Collection, F exten
10
10
  protected addFilter(ctx: Context, list: ItemList<C>): Promise<void>;
11
11
  makeQuery(ctx: Context): Promise<ItemList<C>>;
12
12
  getItems(ctx: Context, page: number, itemsPerPage: number): Promise<CollectionItem<C>[]>;
13
+ getFilterValues(ctx: Context): Promise<Record<string, string | undefined>>;
13
14
  renderItem(_: Context, item: CollectionItem<C>, index: number): Promise<FlatTemplatable>;
14
15
  canAccess: (ctx: Context) => Promise<{
15
16
  canAccess: boolean;
package/lib/page/list.js CHANGED
@@ -135,7 +135,13 @@ ${this.renderListContainer(ctx, this.renderItems(ctx, values))}`;
135
135
  }
136
136
  async getSort(ctx) {
137
137
  const { sort } = await this.extractRawValues(ctx);
138
- return decodeSort(sort);
138
+ const decoded = decodeSort(sort);
139
+ if (decoded === null) {
140
+ return this.getDefaultSort(ctx);
141
+ }
142
+ else {
143
+ return decoded;
144
+ }
139
145
  }
140
146
  makeSortLink(ctx, field, order) {
141
147
  const url = new URL(ctx.url, "https://example.com");
@@ -169,6 +175,9 @@ ${this.renderListContainer(ctx, this.renderItems(ctx, values))}`;
169
175
  >
170
176
  </th>`;
171
177
  }
178
+ getDefaultSort(_) {
179
+ return null;
180
+ }
172
181
  renderTableHead(ctx, fields) {
173
182
  return (0, tempstream_1.tempstream /* HTML */) `<thead>
174
183
  <tr>
@@ -1,8 +1,13 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.SealiousItemListPage = void 0;
4
7
  const list_1 = require("./list");
5
8
  const access_control_1 = require("./access-control");
9
+ const qs_1 = __importDefault(require("qs"));
10
+ const ts_predicates_1 = require("@sealcode/ts-predicates");
6
11
  class SealiousItemListPage extends list_1.ListPage {
7
12
  constructor(collection) {
8
13
  super();
@@ -45,6 +50,14 @@ class SealiousItemListPage extends list_1.ListPage {
45
50
  .fetch();
46
51
  return items;
47
52
  }
53
+ async getFilterValues(ctx) {
54
+ const query_params = qs_1.default.parse(ctx.search.slice(1));
55
+ const _filter_values = query_params?.filter || {};
56
+ let filter_values = (0, ts_predicates_1.is)(_filter_values, ts_predicates_1.predicates.record(ts_predicates_1.predicates.string, ts_predicates_1.predicates.string))
57
+ ? _filter_values
58
+ : {};
59
+ return filter_values;
60
+ }
48
61
  async renderItem(_, item, index) {
49
62
  return `<div>${item.id}</div>`;
50
63
  }
@@ -33,7 +33,12 @@ import { CollectionItem, Field } from "sealious";
33
33
  import { FlatTemplatable, tempstream } from "tempstream";
34
34
  import { ${uppercase_collection} } from "${rel("src/back/collections/collections.js")}";
35
35
  import html from "${rel("src/back/html.js")}";
36
- import { SealiousItemListPage, BaseListPageFields, DefaultListFilters } from "@sealcode/sealgen";
36
+ import {
37
+ SealiousItemListPage,
38
+ BaseListPageFields,
39
+ DefaultListFilters,
40
+ ListFilterRender,
41
+ } from "@sealcode/sealgen";;
37
42
  import qs from "qs";
38
43
  import { is, predicates } from "@sealcode/ts-predicates";
39
44
 
@@ -47,7 +52,7 @@ ${collection_fields
47
52
  .join(",\n")}
48
53
  ] as {
49
54
  field: keyof (typeof PatronEvents)["fields"];
50
- render?: (value: string, field: Field) => string;
55
+ render?: ListFilterRender;
51
56
  }[];
52
57
 
53
58
  const displayFields = [
@@ -64,7 +69,11 @@ ${collection_fields
64
69
  return ` {
65
70
  field: "${field.name}",
66
71
  label: "${field.name}",
67
- format: (v: number) => {const d = new Date(); d.setTime(v); return d.toString();},
72
+ format: (v: number) => {
73
+ const d = new Date();
74
+ d.setTime(v);
75
+ return d.toString().split(" ").slice(1, 5).join(" ");
76
+ },
68
77
  }`;
69
78
  }
70
79
  return ` { field: "${field.name}", label: "${field.name}" }`;
@@ -78,22 +87,6 @@ export default new (class ${action_name}Page extends SealiousItemListPage<
78
87
  > {
79
88
  fields = BaseListPageFields;
80
89
 
81
- async render(ctx: Context) {
82
- return html(
83
- ctx,
84
- "${action_name}",
85
- tempstream/* HTML */ \`<div>
86
- <h2>${action_name}</h2>
87
- <table class="sealious-list">
88
- \${this.renderTableHead(ctx, displayFields)}
89
- <tbody>
90
- \${super.render(ctx)}
91
- </tbody>
92
- </table>
93
- </div>\`
94
- );
95
- }
96
-
97
90
  async renderFilters(ctx: Context): Promise<FlatTemplatable> {
98
91
  const query_params = qs.parse(ctx.search.slice(1));
99
92
  query_params.page = "1";
@@ -109,34 +102,20 @@ export default new (class ${action_name}Page extends SealiousItemListPage<
109
102
  value="\${value}"
110
103
  />\`;
111
104
  })}
112
- \${filterFields.map((field_name) => {
113
- const filter =
114
- FieldToFilter[this.collection.fields[field_name].typeName] ||
115
- FieldToFilter.boolean;
105
+ \${filterFields.map(({ field, render }) => {
106
+ if (!render) {
107
+ render = DefaultListFilters.fallback;
108
+ }
116
109
 
117
110
  return (
118
- filter?.render(
119
- filter_values[field_name] || "",
120
- this.collection.fields[field_name]
121
- ) || ""
111
+ render(filter_values[field] || "", this.collection.fields[field]) ||
112
+ ""
122
113
  );
123
114
  })}
124
115
  <input type="submit" />
125
116
  </form>\`;
126
117
  }
127
118
 
128
- async getFilterValues(ctx: Context) {
129
- const query_params = qs.parse(ctx.search.slice(1));
130
- const _filter_values = query_params?.filter || {};
131
- let filter_values: Record<string, string | undefined> = is(
132
- _filter_values,
133
- predicates.record(predicates.string, predicates.string)
134
- )
135
- ? _filter_values
136
- : {};
137
- return filter_values;
138
- }
139
-
140
119
  async renderItem(_: Context, item: CollectionItem<typeof ${uppercase_collection}>) {
141
120
  return tempstream/* HTML */ \`<tr>
142
121
  \${displayFields.map(({ field, format }) => {
@@ -145,6 +124,23 @@ export default new (class ${action_name}Page extends SealiousItemListPage<
145
124
  })}
146
125
  </tr>\`;
147
126
  }
127
+
128
+ async render(ctx: Context) {
129
+ return html(
130
+ ctx,
131
+ "${action_name}",
132
+ tempstream/* HTML */ \`<div>
133
+ <h2>${action_name}</h2>
134
+ <table class="sealious-list">
135
+ \${this.renderTableHead(ctx, displayFields)}
136
+ <tbody>
137
+ \${super.render(ctx)}
138
+ </tbody>
139
+ </table>
140
+ </div>\`
141
+ );
142
+ }
143
+
148
144
  })(${uppercase_collection});
149
145
  `;
150
146
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sealcode/sealgen",
3
- "version": "0.10.4",
3
+ "version": "0.10.6",
4
4
  "description": "Module to automate adding routes and collections to a sealious application",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {
package/src/page/list.ts CHANGED
@@ -18,10 +18,10 @@ export const BaseListPageFields = <const>{
18
18
  sort: new SimpleFormField(false),
19
19
  };
20
20
 
21
+ export type ListSort = { field: string; order: "asc" | "desc" };
22
+
21
23
  const SORT_SEPARATOR = ":";
22
- function decodeSort(
23
- s: unknown
24
- ): { field: string; order: "asc" | "desc" } | null {
24
+ function decodeSort(s: unknown): ListSort | null {
25
25
  if (typeof s !== "string" || !s.includes(SORT_SEPARATOR)) {
26
26
  return null;
27
27
  }
@@ -38,7 +38,7 @@ function decodeSort(
38
38
  }
39
39
  }
40
40
 
41
- function encodeSort(field: string, order: "asc" | "desc") {
41
+ function encodeSort(field: string, order: "asc" | "desc"): string {
42
42
  return [field, order].join(SORT_SEPARATOR);
43
43
  }
44
44
 
@@ -185,11 +185,14 @@ ${this.renderListContainer(ctx, this.renderItems(ctx, values))}`;
185
185
  return filter;
186
186
  }
187
187
 
188
- async getSort(
189
- ctx: Context
190
- ): Promise<{ field: string; order: "asc" | "desc" } | null> {
188
+ async getSort(ctx: Context): Promise<ListSort | null> {
191
189
  const { sort } = await this.extractRawValues(ctx);
192
- return decodeSort(sort);
190
+ const decoded = decodeSort(sort);
191
+ if (decoded === null) {
192
+ return this.getDefaultSort(ctx);
193
+ } else {
194
+ return decoded;
195
+ }
193
196
  }
194
197
 
195
198
  makeSortLink(ctx: Context, field: string, order: "asc" | "desc"): string {
@@ -238,6 +241,10 @@ ${this.renderListContainer(ctx, this.renderItems(ctx, values))}`;
238
241
  </th>`;
239
242
  }
240
243
 
244
+ getDefaultSort(_: Context): ListSort | null {
245
+ return null;
246
+ }
247
+
241
248
  renderTableHead(
242
249
  ctx: Context,
243
250
  fields: { field: string; label?: string }[]
@@ -9,6 +9,8 @@ import {
9
9
  } from "sealious";
10
10
  import { FlatTemplatable } from "tempstream";
11
11
  import { peopleWhoCan } from "./access-control";
12
+ import qs from "qs";
13
+ import { is, predicates } from "@sealcode/ts-predicates";
12
14
 
13
15
  export abstract class SealiousItemListPage<
14
16
  C extends Collection,
@@ -64,6 +66,18 @@ export abstract class SealiousItemListPage<
64
66
  return items;
65
67
  }
66
68
 
69
+ async getFilterValues(ctx: Context) {
70
+ const query_params = qs.parse(ctx.search.slice(1));
71
+ const _filter_values = query_params?.filter || {};
72
+ let filter_values: Record<string, string | undefined> = is(
73
+ _filter_values,
74
+ predicates.record(predicates.string, predicates.string)
75
+ )
76
+ ? _filter_values
77
+ : {};
78
+ return filter_values;
79
+ }
80
+
67
81
  async renderItem(
68
82
  _: Context,
69
83
  item: CollectionItem<C>,
@@ -39,7 +39,12 @@ import { ${uppercase_collection} } from "${rel(
39
39
  "src/back/collections/collections.js"
40
40
  )}";
41
41
  import html from "${rel("src/back/html.js")}";
42
- import { SealiousItemListPage, BaseListPageFields, DefaultListFilters } from "@sealcode/sealgen";
42
+ import {
43
+ SealiousItemListPage,
44
+ BaseListPageFields,
45
+ DefaultListFilters,
46
+ ListFilterRender,
47
+ } from "@sealcode/sealgen";;
43
48
  import qs from "qs";
44
49
  import { is, predicates } from "@sealcode/ts-predicates";
45
50
 
@@ -58,7 +63,7 @@ ${collection_fields
58
63
  .join(",\n")}
59
64
  ] as {
60
65
  field: keyof (typeof PatronEvents)["fields"];
61
- render?: (value: string, field: Field) => string;
66
+ render?: ListFilterRender;
62
67
  }[];
63
68
 
64
69
  const displayFields = [
@@ -75,7 +80,11 @@ ${collection_fields
75
80
  return ` {
76
81
  field: "${field.name}",
77
82
  label: "${field.name}",
78
- format: (v: number) => {const d = new Date(); d.setTime(v); return d.toString();},
83
+ format: (v: number) => {
84
+ const d = new Date();
85
+ d.setTime(v);
86
+ return d.toString().split(" ").slice(1, 5).join(" ");
87
+ },
79
88
  }`;
80
89
  }
81
90
  return ` { field: "${field.name}", label: "${field.name}" }`;
@@ -89,22 +98,6 @@ export default new (class ${action_name}Page extends SealiousItemListPage<
89
98
  > {
90
99
  fields = BaseListPageFields;
91
100
 
92
- async render(ctx: Context) {
93
- return html(
94
- ctx,
95
- "${action_name}",
96
- tempstream/* HTML */ \`<div>
97
- <h2>${action_name}</h2>
98
- <table class="sealious-list">
99
- \${this.renderTableHead(ctx, displayFields)}
100
- <tbody>
101
- \${super.render(ctx)}
102
- </tbody>
103
- </table>
104
- </div>\`
105
- );
106
- }
107
-
108
101
  async renderFilters(ctx: Context): Promise<FlatTemplatable> {
109
102
  const query_params = qs.parse(ctx.search.slice(1));
110
103
  query_params.page = "1";
@@ -120,34 +113,20 @@ export default new (class ${action_name}Page extends SealiousItemListPage<
120
113
  value="\${value}"
121
114
  />\`;
122
115
  })}
123
- \${filterFields.map((field_name) => {
124
- const filter =
125
- FieldToFilter[this.collection.fields[field_name].typeName] ||
126
- FieldToFilter.boolean;
116
+ \${filterFields.map(({ field, render }) => {
117
+ if (!render) {
118
+ render = DefaultListFilters.fallback;
119
+ }
127
120
 
128
121
  return (
129
- filter?.render(
130
- filter_values[field_name] || "",
131
- this.collection.fields[field_name]
132
- ) || ""
122
+ render(filter_values[field] || "", this.collection.fields[field]) ||
123
+ ""
133
124
  );
134
125
  })}
135
126
  <input type="submit" />
136
127
  </form>\`;
137
128
  }
138
129
 
139
- async getFilterValues(ctx: Context) {
140
- const query_params = qs.parse(ctx.search.slice(1));
141
- const _filter_values = query_params?.filter || {};
142
- let filter_values: Record<string, string | undefined> = is(
143
- _filter_values,
144
- predicates.record(predicates.string, predicates.string)
145
- )
146
- ? _filter_values
147
- : {};
148
- return filter_values;
149
- }
150
-
151
130
  async renderItem(_: Context, item: CollectionItem<typeof ${uppercase_collection}>) {
152
131
  return tempstream/* HTML */ \`<tr>
153
132
  \${displayFields.map(({ field, format }) => {
@@ -156,6 +135,23 @@ export default new (class ${action_name}Page extends SealiousItemListPage<
156
135
  })}
157
136
  </tr>\`;
158
137
  }
138
+
139
+ async render(ctx: Context) {
140
+ return html(
141
+ ctx,
142
+ "${action_name}",
143
+ tempstream/* HTML */ \`<div>
144
+ <h2>${action_name}</h2>
145
+ <table class="sealious-list">
146
+ \${this.renderTableHead(ctx, displayFields)}
147
+ <tbody>
148
+ \${super.render(ctx)}
149
+ </tbody>
150
+ </table>
151
+ </div>\`
152
+ );
153
+ }
154
+
159
155
  })(${uppercase_collection});
160
156
  `;
161
157
  };