@sealcode/sealgen 0.19.16 → 0.19.18

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.
Files changed (128) hide show
  1. package/@types/app-config/get-app-port.d.ts +1 -0
  2. package/@types/app-config/load-app-config.d.ts +4 -0
  3. package/@types/app-config/resolve-app-config-path.d.ts +1 -0
  4. package/@types/controllers/sealgen-table.stimulus.d.ts +9 -0
  5. package/@types/forms/controls/table.d.ts +2 -0
  6. package/@types/forms/fields/structured-array.d.ts +2 -2
  7. package/@types/utils/translate.d.ts +2 -1
  8. package/lib/controllers/sealgen-table.stimulus.js +98 -0
  9. package/lib/forms/controls/table.js +49 -43
  10. package/lib/forms/controls/tickable.js +1 -3
  11. package/lib/forms/fields/collection-field.js +2 -1
  12. package/lib/generate-routes.js +23 -1
  13. package/lib/mount.js +8 -10
  14. package/lib/utils/translate.js +4 -4
  15. package/package.json +2 -2
  16. package/src/controllers/sealgen-table.stimulus.ts +115 -0
  17. package/src/forms/controls/table.ts +94 -81
  18. package/src/forms/fields/collection-field.ts +2 -1
  19. package/src/forms/fields/structured-array.ts +2 -11
  20. package/src/generate-routes.ts +38 -9
  21. package/src/mount.ts +8 -12
  22. package/.xunit +0 -75
  23. package/@types/add-verbose-crud.d.ts +0 -3
  24. package/@types/builders/colors-builder.d.sync-conflict-20250918-184323-TFDLWFG.ts +0 -10
  25. package/@types/builders/fonts-builder.d.sync-conflict-20250918-184322-TFDLWFG.ts +0 -7
  26. package/@types/controllers/table-add-button.d.ts +0 -6
  27. package/@types/crud-field-snippets.d.ts +0 -1
  28. package/@types/find-css-includes.d.ts +0 -1
  29. package/@types/forms/controls/array.d.sync-conflict-20250918-184306-TFDLWFG.ts +0 -33
  30. package/@types/forms/controls/array.sync-conflict-20250918-222045-TFDLWFG.d.ts +0 -33
  31. package/@types/forms/controls/autocomplete.d.sync-conflict-20250918-222042-TFDLWFG.ts +0 -22
  32. package/@types/forms/controls/checkbox-group.d.sync-conflict-20250918-184319-TFDLWFG.ts +0 -21
  33. package/@types/forms/controls/checkboxed-list-input.d.sync-conflict-20250918-184323-TFDLWFG.ts +0 -21
  34. package/@types/forms/controls/derived-frame.d.sync-conflict-20250918-184314-TFDLWFG.ts +0 -19
  35. package/@types/forms/controls/dropdown.d.sync-conflict-20250918-222044-TFDLWFG.ts +0 -30
  36. package/@types/forms/controls/file.d.sync-conflict-20250918-222045-TFDLWFG.ts +0 -13
  37. package/@types/forms/controls/form-control.d.sync-conflict-20250918-184322-TFDLWFG.ts +0 -19
  38. package/@types/forms/controls/form-control.d.sync-conflict-20250918-222046-TFDLWFG.ts +0 -19
  39. package/@types/forms/controls/multiple-files.d.sync-conflict-20250918-184318-TFDLWFG.ts +0 -42
  40. package/@types/forms/controls/multiple-photos.d.ts +0 -19
  41. package/@types/forms/controls/number.d.sync-conflict-20250918-222046-TFDLWFG.ts +0 -13
  42. package/@types/forms/controls/photo.d.sync-conflict-20250918-184321-TFDLWFG.ts +0 -19
  43. package/@types/forms/controls/photo.d.ts +0 -19
  44. package/@types/forms/controls/photo.test.d.ts +0 -1
  45. package/@types/forms/controls/reverse-single-reference.d.ts +0 -1
  46. package/@types/forms/controls/simple-input.d.sync-conflict-20250918-184310-TFDLWFG.ts +0 -33
  47. package/@types/forms/controls/simple-input.d.sync-conflict-20250918-222042-TFDLWFG.ts +0 -33
  48. package/@types/forms/controls/simple-input.sync-conflict-20250918-222045-TFDLWFG.d.ts +0 -33
  49. package/@types/forms/controls/table.d.sync-conflict-20250918-184302-TFDLWFG.ts +0 -39
  50. package/@types/forms/controls/table.sync-conflict-20250918-222042-TFDLWFG.d.ts +0 -39
  51. package/@types/forms/controls/textarea.d.sync-conflict-20250918-222045-TFDLWFG.ts +0 -25
  52. package/@types/forms/fields/boolean.d.sync-conflict-20250918-184325-TFDLWFG.ts +0 -22
  53. package/@types/forms/fields/boolean.sync-conflict-20250918-222042-TFDLWFG.d.ts +0 -22
  54. package/@types/forms/fields/checkboxed-list.d.sync-conflict-20250918-184325-TFDLWFG.ts +0 -23
  55. package/@types/forms/fields/collection-field.d.sync-conflict-20250918-184319-TFDLWFG.ts +0 -22
  56. package/@types/forms/fields/collection-field.d.sync-conflict-20250918-222047-TFDLWFG.ts +0 -22
  57. package/@types/forms/fields/coordinates.d.sync-conflict-20250918-222044-TFDLWFG.ts +0 -14
  58. package/@types/forms/fields/datetime.d.sync-conflict-20250918-222050-TFDLWFG.ts +0 -4
  59. package/@types/forms/fields/email.d.sync-conflict-20250918-184303-TFDLWFG.ts +0 -8
  60. package/@types/forms/fields/enum-multiple-sealious.sync-conflict-20250918-222047-TFDLWFG.d.ts +0 -16
  61. package/@types/forms/fields/enum-multiple.d.ts +0 -18
  62. package/@types/forms/fields/enum-multiple.test.d.ts +0 -1
  63. package/@types/forms/fields/enum.d.ts +0 -18
  64. package/@types/forms/fields/enum.test.d.ts +0 -1
  65. package/@types/forms/fields/field.d.sync-conflict-20250918-184306-TFDLWFG.ts +0 -70
  66. package/@types/forms/fields/fields.d.sync-conflict-20250918-184314-TFDLWFG.ts +0 -29
  67. package/@types/forms/fields/file.d.sync-conflict-20250918-184310-TFDLWFG.ts +0 -23
  68. package/@types/forms/fields/file.d.sync-conflict-20250918-222046-TFDLWFG.ts +0 -23
  69. package/@types/forms/fields/file.sync-conflict-20250918-222049-TFDLWFG.d.ts +0 -23
  70. package/@types/forms/fields/get-field-for-sealious.d.sync-conflict-20250918-222046-TFDLWFG.ts +0 -29
  71. package/@types/forms/fields/get-field-for-sealious.sync-conflict-20250918-222042-TFDLWFG.d.ts +0 -29
  72. package/@types/forms/fields/image.d.sync-conflict-20250918-222042-TFDLWFG.ts +0 -5
  73. package/@types/forms/fields/multiple-files.d.sync-conflict-20250918-184304-TFDLWFG.ts +0 -16
  74. package/@types/forms/fields/number.d.sync-conflict-20250918-184317-TFDLWFG.ts +0 -25
  75. package/@types/forms/fields/number.d.sync-conflict-20250918-222047-TFDLWFG.ts +0 -25
  76. package/@types/forms/fields/pick-from-list.d.sync-conflict-20250918-184322-TFDLWFG.ts +0 -15
  77. package/@types/forms/fields/proxy-field.d.sync-conflict-20250918-184307-TFDLWFG.ts +0 -15
  78. package/@types/forms/fields/regexp.d.sync-conflict-20250918-184305-TFDLWFG.ts +0 -21
  79. package/@types/forms/fields/regexp.d.sync-conflict-20250918-222045-TFDLWFG.ts +0 -21
  80. package/@types/forms/fields/regexp.sync-conflict-20250918-222047-TFDLWFG.d.ts +0 -21
  81. package/@types/forms/fields/reverse-single-reference.d.ts +0 -13
  82. package/@types/forms/fields/simple-form-field.d.sync-conflict-20250918-184309-TFDLWFG.ts +0 -29
  83. package/@types/forms/fields/simple-form-field.d.sync-conflict-20250918-222044-TFDLWFG.ts +0 -29
  84. package/@types/forms/fields/simple-form-field.sync-conflict-20250918-222049-TFDLWFG.d.ts +0 -29
  85. package/@types/forms/fields/single-reference.sync-conflict-20250918-222043-TFDLWFG.d.ts +0 -10
  86. package/@types/forms/fields/structured-array.d.sync-conflict-20250918-184302-TFDLWFG.ts +0 -27
  87. package/@types/forms/fields/structured-array.d.sync-conflict-20250918-222049-TFDLWFG.ts +0 -27
  88. package/@types/forms/fields/structured-array.sync-conflict-20250918-222047-TFDLWFG.d.ts +0 -27
  89. package/@types/forms/fields/table.d.sync-conflict-20250918-184303-TFDLWFG.ts +0 -16
  90. package/@types/forms/form-types.d.sync-conflict-20250918-222045-TFDLWFG.ts +0 -26
  91. package/@types/forms/form.d.sync-conflict-20250918-184315-TFDLWFG.ts +0 -32
  92. package/@types/forms/form.d.sync-conflict-20250918-222049-TFDLWFG.ts +0 -32
  93. package/@types/forms/form.sync-conflict-20250918-222049-TFDLWFG.d.ts +0 -33
  94. package/@types/forms/form.test.d.sync-conflict-20250918-184318-TFDLWFG.ts +0 -6
  95. package/@types/forms/form.test.d.sync-conflict-20250918-222047-TFDLWFG.ts +0 -6
  96. package/@types/forms/multiform.d.sync-conflict-20250918-184308-TFDLWFG.ts +0 -23
  97. package/@types/forms/multiform.sync-conflict-20250918-222044-TFDLWFG.d.ts +0 -23
  98. package/@types/index.d.sync-conflict-20250918-184316-TFDLWFG.ts +0 -46
  99. package/@types/mount.d.sync-conflict-20250918-184320-TFDLWFG.ts +0 -6
  100. package/@types/page/list.d.sync-conflict-20250918-184318-TFDLWFG.ts +0 -48
  101. package/@types/page/list.d.sync-conflict-20250918-222046-TFDLWFG.ts +0 -48
  102. package/@types/page/list.sync-conflict-20250918-222048-TFDLWFG.d.ts +0 -48
  103. package/@types/page/mountable-with-fields.d.sync-conflict-20250918-184321-TFDLWFG.ts +0 -42
  104. package/@types/page/mountable-with-fields.d.sync-conflict-20250918-222046-TFDLWFG.ts +0 -42
  105. package/@types/page/mountable-with-fields.sync-conflict-20250918-222044-TFDLWFG.d.ts +0 -42
  106. package/@types/page/mountable.d.sync-conflict-20250918-184306-TFDLWFG.ts +0 -10
  107. package/@types/page/page.d.sync-conflict-20250918-184320-TFDLWFG.ts +0 -18
  108. package/@types/page/props-parser.d.sync-conflict-20250918-184305-TFDLWFG.ts +0 -15
  109. package/@types/page/stateful-page.d.sync-conflict-20250918-184326-TFDLWFG.ts +0 -62
  110. package/@types/templates/shared/handlers/boolean.d.ts +0 -2
  111. package/@types/templates/shared/handlers/date.d.ts +0 -2
  112. package/@types/templates/shared/handlers/deep-reverse-single-reference.d.ts +0 -2
  113. package/@types/templates/shared/handlers/default.d.ts +0 -2
  114. package/@types/templates/shared/handlers/enum.d.ts +0 -2
  115. package/@types/templates/shared/handlers/file.d.ts +0 -2
  116. package/@types/templates/shared/handlers/image.d.ts +0 -2
  117. package/@types/templates/shared/handlers/int.d.ts +0 -2
  118. package/@types/templates/shared/handlers/jdd.d.ts +0 -2
  119. package/@types/templates/shared/handlers/single-reference.d.ts +0 -2
  120. package/@types/templates/shared/handlers/structured-array.d.ts +0 -2
  121. package/@types/templates/shared/shared-crud-form-fields.d.sync-conflict-20250918-184306-TFDLWFG.ts +0 -1
  122. package/@types/test_utils/test-on-real-app.d.sync-conflict-20250918-184320-TFDLWFG.ts +0 -26
  123. package/@types/utils/extract-fields-from-collection.d.sync-conflict-20250918-184312-TFDLWFG.ts +0 -18
  124. package/@types/utils/extract-fields-from-collection.sync-conflict-20250918-222045-TFDLWFG.d.ts +0 -18
  125. package/lib/controllers/table-add-button.stimulus.js +0 -35
  126. package/src/controllers/table-add-button.stimulus.ts +0 -35
  127. /package/@types/{add-crud.d.sync-conflict-20250918-184311-TFDLWFG.ts → app-config/get-app-port.test.d.ts} +0 -0
  128. /package/@types/{crud-field-snippets.d.sync-conflict-20250918-184323-TFDLWFG.ts → app-config/load-app-config.test.d.ts} +0 -0
@@ -0,0 +1 @@
1
+ export declare function getAppPort(projectDir: string): Promise<number | null>;
@@ -0,0 +1,4 @@
1
+ export type AppConfigModule = {
2
+ PORT?: number;
3
+ };
4
+ export declare function loadAppConfigModule(projectDir: string): Promise<AppConfigModule | null>;
@@ -0,0 +1 @@
1
+ export declare function resolveAppConfigModulePath(projectDir: string): string;
@@ -0,0 +1,9 @@
1
+ import { Controller } from "stimulus";
2
+ export default class TableController extends Controller {
3
+ static targets: string[];
4
+ tableTarget: HTMLTableElement;
5
+ templateTarget: HTMLTemplateElement;
6
+ getTbody(): HTMLTableSectionElement;
7
+ addRow(): void;
8
+ swapRows(e: MouseEvent): void;
9
+ }
@@ -10,6 +10,7 @@ export type TableControlOptions<F extends Record<string, FormField>> = {
10
10
  [field_name in keyof F]: FormControl;
11
11
  };
12
12
  allow_removing?: boolean;
13
+ allow_reordering?: boolean;
13
14
  label_add?: string;
14
15
  label: string;
15
16
  label_remove?: string;
@@ -36,4 +37,5 @@ export declare class Table<F extends Record<string, FormField>> extends FormCont
36
37
  setLabel(value: string): this;
37
38
  setRemoveLabel(value: string): this;
38
39
  setAddLabel(value: string): this;
40
+ setAllowReordering(value: boolean): this;
39
41
  }
@@ -1,5 +1,5 @@
1
1
  import { Context } from "koa";
2
- import { Field as SealiousField, FieldTypes as SealiousFieldTypes, FieldsetInput } from "sealious";
2
+ import { Field as SealiousField, FieldTypes as SealiousFieldTypes } from "sealious";
3
3
  import { FormDataValue } from "../form-types.js";
4
4
  import { Table as TableControl } from "../controls/table.js";
5
5
  import { SealiousToFormField } from "./get-field-for-sealious.js";
@@ -18,6 +18,6 @@ export declare class StructuredArray<SealiousFields extends Record<string, Seali
18
18
  form_field_types: string;
19
19
  sealious_field: string;
20
20
  }): string;
21
- getSealiousCreateValue(fctx: FormControlContext): Promise<SealiousFieldTypes.ArrayStorageInput<FieldsetInput<SealiousFields>>>;
21
+ getSealiousCreateValue(fctx: FormControlContext): Promise<import("./table.js").TableFieldParsed<{ [name in keyof SealiousFields]: SealiousToFormField<SealiousFields[name]>; }>>;
22
22
  sealiousValueToForm(ctx: Context, sealiousValue: Record<string, FormDataValue | null>[] | null): Promise<FormDataValue>;
23
23
  }
@@ -1,3 +1,4 @@
1
1
  import { Context } from "koa";
2
2
  import { Translation } from "sealious";
3
- export declare function t(ctx: Context, key: string, props: unknown[], default_translation: Translation): string;
3
+ /** deprecated */
4
+ export declare function t(ctx: Context, key: string, _props: unknown[], _default_translation: Translation): string;
@@ -0,0 +1,98 @@
1
+ import { Controller } from "stimulus";
2
+ class TableController extends Controller {
3
+ static {
4
+ this.targets = ["table", "template"];
5
+ }
6
+ getTbody() {
7
+ const tbody = this.element.closest("turbo-frame")?.querySelector("tbody");
8
+ if (!tbody) {
9
+ throw new Error("tbody not found");
10
+ }
11
+ return tbody;
12
+ }
13
+ getRowIndex(tr) {
14
+ let result = 0;
15
+ for (const child of Array.from(this.getTbody().children)) {
16
+ if (child == tr) {
17
+ return result;
18
+ }
19
+ result++;
20
+ }
21
+ return -1;
22
+ }
23
+ addRow() {
24
+ const tbody = this.getTbody();
25
+ const orig_template = this.templateTarget.innerHTML;
26
+ const placeholder = this.element.getAttribute("data-table-placeholder");
27
+ if (!placeholder) {
28
+ throw new Error("Could not find placeholder attribute");
29
+ }
30
+ this.templateTarget.innerHTML = orig_template.replaceAll(
31
+ placeholder,
32
+ String(tbody.querySelectorAll("tr").length)
33
+ );
34
+ tbody.appendChild(this.templateTarget.cloneNode(true).content);
35
+ this.templateTarget.innerHTML = orig_template;
36
+ this.reindex();
37
+ }
38
+ swapRows(index_a, index_b) {
39
+ const tbody = this.getTbody();
40
+ const [a, b] = [index_a, index_b].sort().reverse();
41
+ tbody.insertBefore(tbody.children[a], tbody.children[b]);
42
+ this.reindex();
43
+ }
44
+ moveUp(e) {
45
+ const target = e.target;
46
+ const tr = target.closest("tr");
47
+ if (!tr) {
48
+ console.error("Not within a tr");
49
+ return;
50
+ }
51
+ const index_a = this.getRowIndex(tr);
52
+ if (index_a < 0) {
53
+ return;
54
+ }
55
+ const index_b = index_a - 1;
56
+ this.swapRows(index_a, index_b);
57
+ }
58
+ moveDown(e) {
59
+ const target = e.target;
60
+ const tr = target.closest("tr");
61
+ if (!tr) {
62
+ console.error("Not within a tr");
63
+ return;
64
+ }
65
+ const index_a = this.getRowIndex(tr);
66
+ if (index_a < 0) {
67
+ return;
68
+ }
69
+ const index_b = index_a + 1;
70
+ this.swapRows(index_a, index_b);
71
+ }
72
+ reindex() {
73
+ let result = 0;
74
+ for (const tr of Array.from(this.getTbody().children)) {
75
+ tr.querySelectorAll("input").forEach((input) => {
76
+ input.setAttribute(
77
+ "name",
78
+ (input.getAttribute("name") || "").replace(
79
+ /[(\d+)](?!.*\d)/,
80
+ // last number in a regex
81
+ result.toString()
82
+ )
83
+ );
84
+ });
85
+ result++;
86
+ }
87
+ this.element.querySelectorAll(
88
+ `[data-action="sealgen-table#moveUp"], [data-action="sealgen-table#moveDown"]`
89
+ ).forEach((e) => e.disabled = false);
90
+ this.element.querySelectorAll(
91
+ 'tr:first-child [data-action="sealgen-table#moveUp"], tr:last-child [data-action="sealgen-table#moveDown"]'
92
+ ).forEach((e) => e.disabled = true);
93
+ }
94
+ }
95
+ export {
96
+ TableController as default
97
+ };
98
+ //# sourceMappingURL=sealgen-table.stimulus.js.map
@@ -49,19 +49,17 @@ class Table extends FormControl {
49
49
  ${this.options.allow_removing ? (
50
50
  /* HTML */
51
51
  `<td>
52
- <button
53
- onclick="this.closest('tr').remove()"
54
- >
55
- remove
56
- </button>
57
- <noscript>
58
- <input
59
- type="submit"
60
- data-turbo-frame="${this.getFrameID()}"
61
- value="${this.options.label_remove || "remove"}"
62
- form="${fctx.form_id}"
63
- formnovalidate
64
- formaction="${this.getActionURL(
52
+ <button onclick="this.closest('tr').remove()">
53
+ remove
54
+ </button>
55
+ <noscript>
56
+ <input
57
+ type="submit"
58
+ data-turbo-frame="${this.getFrameID()}"
59
+ value="${this.options.label_remove || "remove"}"
60
+ form="${fctx.form_id}"
61
+ formnovalidate
62
+ formaction="${this.getActionURL(
65
63
  this.table_field.name,
66
64
  {
67
65
  remove: {
@@ -69,9 +67,19 @@ class Table extends FormControl {
69
67
  }
70
68
  }
71
69
  )}"
72
- />
73
- </noscript>
74
- </td>`
70
+ />
71
+ </noscript>
72
+ </td>`
73
+ ) : ""}${this.options.allow_reordering ? (
74
+ /* HTML */
75
+ `<td>
76
+ <button data-action="sealgen-table#moveUp">
77
+ \u2191
78
+ </button>
79
+ <button data-action="sealgen-table#moveDown">
80
+ \u2193
81
+ </button>
82
+ </td>`
75
83
  ) : ""}
76
84
  </tr>`
77
85
  );
@@ -89,13 +97,17 @@ class Table extends FormControl {
89
97
  ].join(" ")}"
90
98
  >
91
99
  <label>${this.options.label || this.table_field.label}</label>
92
- <div class="table__wrapper">
93
- <table>
100
+ <div
101
+ class="table__wrapper"
102
+ data-controller="sealgen-table"
103
+ data-table-placeholder="${TABLE_COLUMN_FIELD_INDEX_PLACEHOLDER}"
104
+ >
105
+ <table data-sealgen-table-target="table">
94
106
  <tbody>
95
107
  ${rows?.map((row, index) => make_row(row, index))}
96
108
  </tbody>
97
109
  </table>
98
- <template>
110
+ <template data-sealgen-table-target="template">
99
111
  ${make_row(null, TABLE_COLUMN_FIELD_INDEX_PLACEHOLDER)}
100
112
  </template>
101
113
 
@@ -104,19 +116,17 @@ class Table extends FormControl {
104
116
  this.options.allow_adding ? (
105
117
  /* HTML */
106
118
  `<button
107
- data-controller="table-add-button"
108
- data-action="click->table-add-button#addRow"
109
- data-table-placeholder="${TABLE_COLUMN_FIELD_INDEX_PLACEHOLDER}"
110
- >
111
- ${this.options.label_add || "add"}
112
- </button>
113
- <noscript>
114
- <input
115
- type="submit"
116
- value="add"
117
- form="${fctx.form_id}"
118
- formnovalidate
119
- formaction="${this.getActionURL(
119
+ data-action="click->sealgen-table#addRow"
120
+ >
121
+ ${this.options.label_add || "add"}
122
+ </button>
123
+ <noscript>
124
+ <input
125
+ type="submit"
126
+ value="add"
127
+ form="${fctx.form_id}"
128
+ formnovalidate
129
+ formaction="${this.getActionURL(
120
130
  this.table_field.name,
121
131
  {
122
132
  insert: {
@@ -125,8 +135,8 @@ class Table extends FormControl {
125
135
  }
126
136
  }
127
137
  )}"
128
- />
129
- </noscript>`
138
+ />
139
+ </noscript>`
130
140
  ) : ""}
131
141
  </div>
132
142
  </turbo-frame>`;
@@ -144,7 +154,7 @@ class Table extends FormControl {
144
154
  router.post("/", async (ctx, next) => {
145
155
  const action = ctx.$body.action;
146
156
  const field_name = ctx.$body.field_name;
147
- if (!is(action, predicates.object) || !is(field_name, predicates.string)) {
157
+ if (!is(action, predicates.object) || !is(field_name, predicates.string) || field_name !== this.table_field.name) {
148
158
  await next();
149
159
  return;
150
160
  }
@@ -154,10 +164,6 @@ class Table extends FormControl {
154
164
  },
155
165
  action
156
166
  )) {
157
- if (field_name !== this.table_field.name) {
158
- await next();
159
- return;
160
- }
161
167
  if (!ctx.$body[this.table_field.name]) {
162
168
  ctx.$body[this.table_field.name] = {};
163
169
  }
@@ -169,10 +175,6 @@ class Table extends FormControl {
169
175
  },
170
176
  action
171
177
  )) {
172
- if (field_name !== this.table_field.name) {
173
- await next();
174
- return;
175
- }
176
178
  if (!ctx.$body[this.table_field.name]) {
177
179
  ctx.$body[this.table_field.name] = {};
178
180
  }
@@ -221,6 +223,10 @@ class Table extends FormControl {
221
223
  this.options.label_add = value;
222
224
  return this;
223
225
  }
226
+ setAllowReordering(value) {
227
+ this.options.allow_reordering = value;
228
+ return this;
229
+ }
224
230
  }
225
231
  export {
226
232
  TABLE_COLUMN_FIELD_INDEX_PLACEHOLDER,
@@ -21,7 +21,6 @@ class Tickable extends FormFieldControl {
21
21
  ];
22
22
  }
23
23
  async render(fctx) {
24
- console.log("!! Rendering checkbox", this.field.name);
25
24
  const {
26
25
  parsed: _parsed,
27
26
  valid,
@@ -32,7 +31,6 @@ class Tickable extends FormFieldControl {
32
31
  true
33
32
  );
34
33
  const field_message = fctx.data.field_messages[this.field.name];
35
- console.log(this.field.name, fctx.data.field_messages, field_message);
36
34
  const parsed = _parsed === null ? this.options.default_value : _parsed;
37
35
  const value = this.getValueAttribute(
38
36
  fctx.ctx,
@@ -75,7 +73,7 @@ class Tickable extends FormFieldControl {
75
73
  })();
76
74
  </script>
77
75
 
78
- ${(~valid || !!field_message) && !this.options.hide_errors && fctx.validate ? `<div class="input__error">${Array.from(new Set([message, field_message].filter((e) => !!e))).join(" \u2022 ")}</div>` : ""}
76
+ ${(~valid || !!field_message) && !this.options.hide_errors && fctx.validate ? `<div class="input__error">${Array.from(new Set([message, field_message.message].filter((e) => !!e))).join(" \u2022 ")}</div>` : ""}
79
77
  `
80
78
  );
81
79
  }
@@ -34,7 +34,8 @@ class CollectionField extends FormField {
34
34
  ctx.$context,
35
35
  value,
36
36
  void 0,
37
- null
37
+ null,
38
+ void 0
38
39
  );
39
40
  return { valid, message: reason || (!valid ? "Wrong value" : "") };
40
41
  }
@@ -70,8 +70,28 @@ async function generateRoutes() {
70
70
  ).replace(/\/\//g, "/")
71
71
  }))
72
72
  );
73
+ const url_tree = { children: {} };
74
+ sortRoutes(files).forEach(({ actionName, url }) => {
75
+ const elements = url.split("/").filter((e) => e != "");
76
+ let pointer = url_tree;
77
+ for (const [index, element] of elements.entries()) {
78
+ if (!pointer.children[element]) {
79
+ pointer.children[element] = { children: {} };
80
+ }
81
+ pointer = pointer.children[element];
82
+ if (index == elements.length - 1) {
83
+ pointer.actionName = actionName;
84
+ }
85
+ }
86
+ });
73
87
  const routes_content = `// DO NOT EDIT! This file is generated automaticaly with npm run generate-routes
74
88
 
89
+ export type URLTree = {
90
+ actionName?: string;
91
+ children: { [key: string]: URLTree };
92
+ };
93
+ export const url_tree = ${JSON.stringify(url_tree)};
94
+
75
95
  import type Router from "@koa/router";
76
96
  import { mount } from "@sealcode/sealgen";
77
97
  import * as URLs from "./urls.js"
@@ -88,7 +108,9 @@ ${sortRoutes(files).map(
88
108
  ({ actionName }) => ` mount(router, URLs.${actionName}URL, ${actionName});`
89
109
  ).join("\n")}
90
110
  }`;
91
- const urls_content = `${sortRoutes(files).map(({ actionName, url }) => generateURL(actionName, url)).join("\n")}
111
+ const urls_content = `/* DO NOT EDIT! This file is generated automaticall with npm run generate-routes. */
112
+
113
+ ${sortRoutes(files).map(({ actionName, url }) => generateURL(actionName, url)).join("\n")}
92
114
  `;
93
115
  await fs.writeFile(
94
116
  target_locreq.resolve("src/back/routes/routes.ts"),
package/lib/mount.js CHANGED
@@ -10,19 +10,17 @@ async function handleHtmlPromise(ctx, next) {
10
10
  }
11
11
  function mount(router, url, mountable, use_dummy_app = false, file_manager = use_dummy_app ? new FileManager("/tmp", "/uploaded_files") : void 0) {
12
12
  const raw_url = typeof url === "string" ? url : url.rawURL;
13
- const imageRouter = new KoaResponsiveImageRouter({
14
- staticPath: "/tmp",
15
- thumbnailSize: 10,
16
- cacheManagerResolutionThreshold: 10,
17
- imageStoragePath: "/tmp",
18
- smartCropStoragePath: "/tmp"
19
- });
20
- const fileManager = new FileManager("/tmp", "/uploaded_files");
21
13
  const args = use_dummy_app ? [
22
14
  async (ctx, next) => {
23
15
  ctx.$app = {
24
- fileManager,
25
- imageRouter,
16
+ fileManager: new FileManager("/tmp", "/uploaded_files"),
17
+ imageRouter: new KoaResponsiveImageRouter({
18
+ staticPath: "/tmp",
19
+ thumbnailSize: 10,
20
+ cacheManagerResolutionThreshold: 10,
21
+ imageStoragePath: "/tmp",
22
+ smartCropStoragePath: "/tmp"
23
+ }),
26
24
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
27
25
  Logger: new Proxy(
28
26
  {},
@@ -1,9 +1,9 @@
1
- function t(ctx, key, props, default_translation) {
1
+ function t(ctx, key, _props, _default_translation) {
2
2
  return (
3
3
  /* HTML */
4
- `<span translation-key="${key.replace('"', '\\"')}"
5
- >${ctx.$app.getString(key, props, default_translation)}</span
6
- >`
4
+ `<span translation-key="${key.replace('"', '\\"')}">
5
+ ${ctx.i18n`${key}`}
6
+ </span>`
7
7
  );
8
8
  }
9
9
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sealcode/sealgen",
3
- "version": "0.19.16",
3
+ "version": "0.19.18",
4
4
  "description": "Module to automate adding routes and collections to a sealious application",
5
5
  "main": "lib/index.js",
6
6
  "type": "module",
@@ -92,7 +92,7 @@
92
92
  "peerDependencies": {
93
93
  "koa": "^2.13.0",
94
94
  "koa-responsive-image-router": "^0.2.24",
95
- "sealious": "^0.21.29",
95
+ "sealious": "^0.21.36",
96
96
  "stimulus": "^3.2.2"
97
97
  }
98
98
  }
@@ -0,0 +1,115 @@
1
+ /// <reference lib="dom" />
2
+ import { Controller } from "stimulus";
3
+
4
+ export default class TableController extends Controller {
5
+ static targets = ["table", "template"];
6
+ declare tableTarget: HTMLTableElement;
7
+ declare templateTarget: HTMLTemplateElement;
8
+
9
+ getTbody() {
10
+ const tbody = this.element
11
+ .closest("turbo-frame")
12
+ ?.querySelector("tbody");
13
+ if (!tbody) {
14
+ throw new Error("tbody not found");
15
+ }
16
+ return tbody;
17
+ }
18
+
19
+ getRowIndex(tr: HTMLTableRowElement) {
20
+ let result = 0;
21
+ for (const child of Array.from(this.getTbody().children)) {
22
+ if (child == tr) {
23
+ return result;
24
+ }
25
+ result++;
26
+ }
27
+ return -1;
28
+ }
29
+
30
+ addRow() {
31
+ const tbody = this.getTbody();
32
+ const orig_template = this.templateTarget.innerHTML;
33
+ const placeholder = this.element.getAttribute("data-table-placeholder");
34
+ if (!placeholder) {
35
+ throw new Error("Could not find placeholder attribute");
36
+ }
37
+ this.templateTarget.innerHTML = orig_template.replaceAll(
38
+ placeholder,
39
+ String(tbody.querySelectorAll("tr").length)
40
+ );
41
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any
42
+ tbody.appendChild((this.templateTarget.cloneNode(true) as any).content);
43
+ this.templateTarget.innerHTML = orig_template;
44
+ this.reindex();
45
+ }
46
+
47
+ swapRows(index_a: number, index_b: number) {
48
+ const tbody = this.getTbody();
49
+ const [a, b] = [index_a, index_b].sort().reverse(); // we want them in descending order
50
+ tbody.insertBefore(tbody.children[a], tbody.children[b]);
51
+ this.reindex();
52
+ }
53
+
54
+ moveUp(e: MouseEvent) {
55
+ const target = e.target as HTMLButtonElement;
56
+ const tr = target.closest("tr");
57
+ if (!tr) {
58
+ console.error("Not within a tr");
59
+ return;
60
+ }
61
+ const index_a = this.getRowIndex(tr);
62
+ if (index_a < 0) {
63
+ return;
64
+ }
65
+ const index_b = index_a - 1;
66
+ this.swapRows(index_a, index_b);
67
+ }
68
+
69
+ moveDown(e: MouseEvent) {
70
+ const target = e.target as HTMLButtonElement;
71
+ const tr = target.closest("tr");
72
+ if (!tr) {
73
+ console.error("Not within a tr");
74
+ return;
75
+ }
76
+ const index_a = this.getRowIndex(tr);
77
+ if (index_a < 0) {
78
+ return;
79
+ }
80
+ const index_b = index_a + 1;
81
+ this.swapRows(index_a, index_b);
82
+ }
83
+
84
+ reindex() {
85
+ let result = 0;
86
+
87
+ // assign proper number to each input within a tr by changing input names
88
+ for (const tr of Array.from(this.getTbody().children)) {
89
+ tr.querySelectorAll("input").forEach((input) => {
90
+ input.setAttribute(
91
+ "name",
92
+ (input.getAttribute("name") || "").replace(
93
+ /[(\d+)](?!.*\d)/, // last number in a regex
94
+ result.toString()
95
+ )
96
+ );
97
+ });
98
+ result++;
99
+ }
100
+
101
+ // disable up/down buttons for first/last items
102
+ // first reset all states to enabled
103
+ this.element
104
+ .querySelectorAll(
105
+ `[data-action="sealgen-table#moveUp"], [data-action="sealgen-table#moveDown"]`
106
+ )
107
+ .forEach((e: HTMLButtonElement) => (e.disabled = false));
108
+ // then disable the ones at the top and bottom
109
+ this.element
110
+ .querySelectorAll(
111
+ 'tr:first-child [data-action="sealgen-table#moveUp"], tr:last-child [data-action="sealgen-table#moveDown"]'
112
+ )
113
+ .forEach((e: HTMLButtonElement) => (e.disabled = true));
114
+ }
115
+ }