@antelopejs/dms 0.7.21 → 0.8.1

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 (208) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/dist/implementations/dms/resolver-timeout.d.ts +1 -0
  3. package/dist/implementations/dms/resolver-timeout.js +13 -3
  4. package/dist/implementations/dms/resolver-timeout.js.map +1 -1
  5. package/dist/implementations/dms-auth/account-emails.d.ts +4 -0
  6. package/dist/implementations/dms-auth/account-emails.js +62 -0
  7. package/dist/implementations/dms-auth/account-emails.js.map +1 -0
  8. package/dist/implementations/dms-auth/index.d.ts +1 -3
  9. package/dist/implementations/dms-auth/index.js +15 -61
  10. package/dist/implementations/dms-auth/index.js.map +1 -1
  11. package/dist/pages/settings/users/email-change.js +3 -4
  12. package/dist/pages/settings/users/email-change.js.map +1 -1
  13. package/dist/pages/settings/users/invites.js +1 -1
  14. package/dist/pages/settings/users/invites.js.map +1 -1
  15. package/dist/pages/settings/users/members.js +1 -1
  16. package/dist/pages/settings/users/members.js.map +1 -1
  17. package/dist/pages/settings/users/notifications.js +1 -0
  18. package/dist/pages/settings/users/notifications.js.map +1 -1
  19. package/dist/test/antelope.test.js +2 -1
  20. package/dist/test/antelope.test.js.map +1 -1
  21. package/dist/test/helpers/db.js +19 -11
  22. package/dist/test/helpers/db.js.map +1 -1
  23. package/dist/test/integration/auth/two-factor-codes.test.js +4 -2
  24. package/dist/test/integration/auth/two-factor-codes.test.js.map +1 -1
  25. package/dist/test/unit/implementations/dms/dynamic-menu-hardening.test.js +8 -5
  26. package/dist/test/unit/implementations/dms/dynamic-menu-hardening.test.js.map +1 -1
  27. package/dist/test/unit/implementations/dms/layout-banners.test.js +20 -7
  28. package/dist/test/unit/implementations/dms/layout-banners.test.js.map +1 -1
  29. package/dist/test/unit/implementations/dms-html-render/built-in-emails.test.js +34 -0
  30. package/dist/test/unit/implementations/dms-html-render/built-in-emails.test.js.map +1 -0
  31. package/dist/test/unit/interfaces/dms/hook-handler-results.test.js +49 -0
  32. package/dist/test/unit/interfaces/dms/hook-handler-results.test.js.map +1 -0
  33. package/dist/test/unit/interfaces/dms/page-topics.test.js +17 -0
  34. package/dist/test/unit/interfaces/dms/page-topics.test.js.map +1 -1
  35. package/dist/test/unit/interfaces/dms-base/confirm-dialog-secondary-action.test.js +2 -2
  36. package/dist/test/unit/interfaces/dms-base/confirm-dialog-secondary-action.test.js.map +1 -1
  37. package/dist/test/unit/interfaces/dms-base/query-response-delta.test.js +29 -0
  38. package/dist/test/unit/interfaces/dms-base/query-response-delta.test.js.map +1 -0
  39. package/dist/test/unit/interfaces/dms-base/resource-form.test.js +5 -0
  40. package/dist/test/unit/interfaces/dms-base/resource-form.test.js.map +1 -1
  41. package/dist/test/unit/interfaces/dms-base/table-view-form-redirect.test.js +12 -2
  42. package/dist/test/unit/interfaces/dms-base/table-view-form-redirect.test.js.map +1 -1
  43. package/dist/test/unit/interfaces/dms-base/table-view-reduced-chrome.test.js +29 -4
  44. package/dist/test/unit/interfaces/dms-base/table-view-reduced-chrome.test.js.map +1 -1
  45. package/dist/test/unit/interfaces/dms-base/table-view-source-reorder.test.js +14 -11
  46. package/dist/test/unit/interfaces/dms-base/table-view-source-reorder.test.js.map +1 -1
  47. package/dist/test/unit/interfaces/dms-base/table-view-views.test.js +8 -5
  48. package/dist/test/unit/interfaces/dms-base/table-view-views.test.js.map +1 -1
  49. package/dist/test/unit/utils/email-subjects.test.js +27 -0
  50. package/dist/test/unit/utils/email-subjects.test.js.map +1 -0
  51. package/dist/utils/admin-invite-email.js +2 -4
  52. package/dist/utils/admin-invite-email.js.map +1 -1
  53. package/dist/utils/email-change-mail.d.ts +1 -1
  54. package/dist/utils/email-change-mail.js +11 -6
  55. package/dist/utils/email-change-mail.js.map +1 -1
  56. package/dist/utils/email-subjects.d.ts +3 -0
  57. package/dist/utils/email-subjects.js +32 -0
  58. package/dist/utils/email-subjects.js.map +1 -0
  59. package/dist/utils/export-jobs.js +15 -10
  60. package/dist/utils/export-jobs.js.map +1 -1
  61. package/frontend-vue/layers/dms-core/app/utils/url-interpolation.ts +29 -11
  62. package/frontend-vue/layers/dms-core/shared/types/app-config.ts +17 -0
  63. package/frontend-vue/layers/dms-layout/app/app.config.ts +5 -0
  64. package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardHeader.vue +18 -2
  65. package/frontend-vue/layers/dms-layout/app/build/components/layout/Footer.vue +16 -1
  66. package/frontend-vue/layers/dms-layout/app/build/composables/layout/useHeaderActionControls.ts +14 -0
  67. package/frontend-vue/layers/dms-layout/app/components/layout/HStack.vue +16 -0
  68. package/frontend-vue/layers/dms-layout/app/components/layout/VStack.vue +2 -0
  69. package/frontend-vue/layers/dms-layout/app/composables/useFooterLinks.ts +11 -1
  70. package/frontend-vue/layers/dms-layout/app/custom-pages/settings/roles.vue +1 -1
  71. package/frontend-vue/layers/dms-layout/app/emails/EmailAdminInvite.vue +1 -1
  72. package/frontend-vue/layers/dms-layout/app/emails/EmailChangeNotice.vue +13 -7
  73. package/frontend-vue/layers/dms-layout/app/emails/EmailChangeVerification.vue +18 -7
  74. package/frontend-vue/layers/dms-layout/app/emails/EmailExportReady.vue +23 -12
  75. package/frontend-vue/layers/dms-layout/app/emails/EmailResetPassword.vue +18 -7
  76. package/frontend-vue/layers/dms-layout/app/emails/EmailTwoFactor.vue +23 -4
  77. package/frontend-vue/layers/dms-layout/app/emails/EmailUserValidation.vue +18 -6
  78. package/frontend-vue/layers/dms-layout/app/emails/components/EmailOTP.vue +8 -2
  79. package/frontend-vue/layers/dms-layout/i18n/locales/layout-en-GB.json +40 -0
  80. package/frontend-vue/layers/dms-layout/i18n/locales/layout-fr-FR.json +40 -0
  81. package/frontend-vue/layers/dms-ui/app/build/components/form/FormFieldControl.vue +2 -1
  82. package/frontend-vue/layers/dms-ui/app/build/components/form/FormLoadError.vue +11 -3
  83. package/frontend-vue/layers/dms-ui/app/build/composables/actions/useActionTargets.ts +27 -36
  84. package/frontend-vue/layers/dms-ui/app/build/composables/chart/apexTheme.ts +59 -2
  85. package/frontend-vue/layers/dms-ui/app/build/composables/confirm/confirmDialogTexts.ts +27 -4
  86. package/frontend-vue/layers/dms-ui/app/build/composables/confirm/useActionConfirm.ts +10 -2
  87. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/registerDefaults.ts +0 -5
  88. package/frontend-vue/layers/dms-ui/app/build/composables/form/formEntryOrder.ts +23 -0
  89. package/frontend-vue/layers/dms-ui/app/build/composables/form/formFooter.ts +19 -15
  90. package/frontend-vue/layers/dms-ui/app/build/composables/form/formRecordLoad.ts +26 -2
  91. package/frontend-vue/layers/dms-ui/app/build/composables/page/pageUrlValues.ts +41 -0
  92. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/registerDefaultFunctions.ts +2 -2
  93. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableRows.ts +3 -5
  94. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableViewConfig.ts +7 -12
  95. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableViewRowActions.ts +3 -3
  96. package/frontend-vue/layers/dms-ui/app/build/utils/link.ts +7 -3
  97. package/frontend-vue/layers/dms-ui/app/build/utils/urlVariables.ts +32 -9
  98. package/frontend-vue/layers/dms-ui/app/components/activity-feed/ActivityFeed.vue +8 -1
  99. package/frontend-vue/layers/dms-ui/app/components/banner/Banner.vue +9 -4
  100. package/frontend-vue/layers/dms-ui/app/components/blocks/BannerBlock.vue +5 -11
  101. package/frontend-vue/layers/dms-ui/app/components/blocks/NavCardGridBlock.vue +2 -1
  102. package/frontend-vue/layers/dms-ui/app/components/chart/ApexChartHost.vue +32 -1
  103. package/frontend-vue/layers/dms-ui/app/components/check-list/CheckList.vue +1 -1
  104. package/frontend-vue/layers/dms-ui/app/components/form/Form.vue +12 -2
  105. package/frontend-vue/layers/dms-ui/app/components/form/components/Cascader.vue +7 -3
  106. package/frontend-vue/layers/dms-ui/app/components/form/components/File.vue +7 -0
  107. package/frontend-vue/layers/dms-ui/app/components/form/components/InputAddress.vue +4 -1
  108. package/frontend-vue/layers/dms-ui/app/components/form/components/InputCode.vue +4 -2
  109. package/frontend-vue/layers/dms-ui/app/components/form/components/InputSecret.vue +3 -2
  110. package/frontend-vue/layers/dms-ui/app/components/form/components/Relation.vue +4 -1
  111. package/frontend-vue/layers/dms-ui/app/components/grid/GridRow.vue +14 -6
  112. package/frontend-vue/layers/dms-ui/app/components/grid/columns.ts +52 -3
  113. package/frontend-vue/layers/dms-ui/app/components/key-value-list/KeyValueList.vue +2 -1
  114. package/frontend-vue/layers/dms-ui/app/components/list-row/ListRow.vue +9 -2
  115. package/frontend-vue/layers/dms-ui/app/components/save-bar/InstantSaveBadge.vue +13 -5
  116. package/frontend-vue/layers/dms-ui/app/components/save-bar/SaveBar.vue +1 -1
  117. package/frontend-vue/layers/dms-ui/app/components/stat-group/StatGroup.vue +3 -2
  118. package/frontend-vue/layers/dms-ui/app/components/table-view/CascaderPath.vue +53 -31
  119. package/frontend-vue/layers/dms-ui/app/composables/chart/apexPlotOptions.ts +15 -4
  120. package/frontend-vue/layers/dms-ui/app/composables/chart/apexYRange.ts +123 -0
  121. package/frontend-vue/layers/dms-ui/app/composables/chart/useApexChart.ts +49 -49
  122. package/frontend-vue/layers/dms-ui/app/composables/chart/useChartTheme.ts +20 -1
  123. package/frontend-vue/layers/dms-ui/app/composables/confirm/types.ts +1 -1
  124. package/frontend-vue/layers/dms-ui/app/composables/form/types/props.ts +2 -0
  125. package/frontend-vue/layers/dms-ui/app/composables/form/useForm.ts +8 -6
  126. package/frontend-vue/layers/dms-ui/app/composables/table-view/types/action-target.ts +1 -1
  127. package/frontend-vue/layers/dms-ui/app/composables/table-view/types/config.ts +3 -5
  128. package/frontend-vue/layers/dms-ui/app/utils/bannerToneIcons.ts +13 -0
  129. package/frontend-vue/layers/dms-ui/app/utils/cascader.ts +26 -0
  130. package/frontend-vue/layers/dms-ui/i18n/locales/ui-en-GB.json +4 -0
  131. package/frontend-vue/layers/dms-ui/i18n/locales/ui-fr-FR.json +4 -0
  132. package/frontend-vue/package.json +1 -1
  133. package/frontend-vue/pnpm-lock.yaml +5 -5
  134. package/frontend-vue/tests/activity-feed-fill-height.test.ts +7 -0
  135. package/frontend-vue/tests/banner-tone-icon.test.ts +55 -0
  136. package/frontend-vue/tests/builtin-emails.test.ts +141 -0
  137. package/frontend-vue/tests/cascader.test.ts +27 -0
  138. package/frontend-vue/tests/chart-auto-y-range.test.ts +25 -9
  139. package/frontend-vue/tests/chart-colors.test.ts +8 -0
  140. package/frontend-vue/tests/chart-resize-after-animation.test.ts +100 -0
  141. package/frontend-vue/tests/chart-type-defaults.test.ts +128 -0
  142. package/frontend-vue/tests/check-list-marker.test.ts +58 -0
  143. package/frontend-vue/tests/confirm-from.test.ts +1 -1
  144. package/frontend-vue/tests/confirm-secondary-action.test.ts +2 -2
  145. package/frontend-vue/tests/context-links.test.ts +2 -2
  146. package/frontend-vue/tests/custom-action-confirm-from.test.ts +2 -2
  147. package/frontend-vue/tests/download-action-target.test.ts +2 -2
  148. package/frontend-vue/tests/file-drop-prompt.test.ts +72 -0
  149. package/frontend-vue/tests/footer-config.test.ts +135 -0
  150. package/frontend-vue/tests/form-actions.test.ts +7 -0
  151. package/frontend-vue/tests/form-enclosing-form.test.ts +0 -21
  152. package/frontend-vue/tests/form-entry-order.test.ts +45 -0
  153. package/frontend-vue/tests/form-footer-kind.test.ts +11 -6
  154. package/frontend-vue/tests/form-load-error.test.ts +38 -23
  155. package/frontend-vue/tests/grid-responsive-columns.test.ts +39 -31
  156. package/frontend-vue/tests/header-actions.test.ts +55 -9
  157. package/frontend-vue/tests/instant-save-badge.test.ts +11 -4
  158. package/frontend-vue/tests/list-row-truncate.test.ts +46 -0
  159. package/frontend-vue/tests/nuxt-ui-aria-labels.test.ts +1 -28
  160. package/frontend-vue/tests/period-live-pause.test.ts +0 -13
  161. package/frontend-vue/tests/period-max-days.test.ts +0 -14
  162. package/frontend-vue/tests/roles-name-errors.test.ts +2 -3
  163. package/frontend-vue/tests/row-side-panel.test.ts +0 -12
  164. package/frontend-vue/tests/save-bar.test.ts +15 -3
  165. package/frontend-vue/tests/save-status-error.test.ts +2 -2
  166. package/frontend-vue/tests/table-cell-wrap.test.ts +0 -12
  167. package/frontend-vue/tests/table-density-menu.test.ts +0 -21
  168. package/frontend-vue/tests/table-live-hold.test.ts +0 -44
  169. package/frontend-vue/tests/table-row-action-errors.test.ts +5 -5
  170. package/frontend-vue/tests/table-row-hover.test.ts +2 -12
  171. package/frontend-vue/tests/table-scroll-area.test.ts +0 -8
  172. package/frontend-vue/tests/table-view-card-props.test.ts +0 -17
  173. package/frontend-vue/tests/table-view-cards-reorder.test.ts +0 -16
  174. package/frontend-vue/tests/table-view-grouped.test.ts +0 -55
  175. package/frontend-vue/tests/table-view-pinned-rows.test.ts +0 -15
  176. package/frontend-vue/tests/table-view-record-link.test.ts +0 -17
  177. package/frontend-vue/tests/table-view-refresh.test.ts +0 -17
  178. package/frontend-vue/tests/table-view-sources.test.ts +1 -1
  179. package/frontend-vue/tests/table-view-url-tab.test.ts +0 -14
  180. package/frontend-vue/tests/template-tokens.test.ts +235 -0
  181. package/frontend-vue/tests/tone.test.ts +0 -19
  182. package/frontend-vue/tests/url-interpolation.test.ts +6 -6
  183. package/package.json +6 -6
  184. package/skills/dms/SKILL.md +2 -1
  185. package/skills/dms-pages/REFERENCE.md +2 -2
  186. package/skills/dms-project/SKILL.md +0 -1
  187. package/dist/test/integration/auth/login.test.js +0 -57
  188. package/dist/test/integration/auth/login.test.js.map +0 -1
  189. package/dist/test/integration/auth/refresh.test.js +0 -59
  190. package/dist/test/integration/auth/refresh.test.js.map +0 -1
  191. package/dist/test/integration/auth/sessions.test.js +0 -58
  192. package/dist/test/integration/auth/sessions.test.js.map +0 -1
  193. package/dist/test/integration/auth/signup.test.js +0 -99
  194. package/dist/test/integration/auth/signup.test.js.map +0 -1
  195. package/dist/test/unit/skills/dms-dev-script.test.d.ts +0 -1
  196. package/dist/test/unit/skills/dms-dev-script.test.js +0 -137
  197. package/dist/test/unit/skills/dms-dev-script.test.js.map +0 -1
  198. package/frontend-vue/tests/form-reload-on-reopen.test.ts +0 -20
  199. package/frontend-vue/tests/icon-aria-hidden.test.ts +0 -29
  200. package/frontend-vue/tests/skeleton-paragraph.test.ts +0 -30
  201. package/frontend-vue/tests/tab-slot-spacing.test.ts +0 -29
  202. package/frontend-vue/tests/table-empty-body-viewport.test.ts +0 -25
  203. package/frontend-vue/tests/table-header-placement.test.ts +0 -21
  204. package/frontend-vue/tests/vue-inventory.test.ts +0 -107
  205. /package/dist/test/{integration/auth/login.test.d.ts → unit/implementations/dms-html-render/built-in-emails.test.d.ts} +0 -0
  206. /package/dist/test/{integration/auth/sessions.test.d.ts → unit/interfaces/dms/hook-handler-results.test.d.ts} +0 -0
  207. /package/dist/test/{integration/auth/refresh.test.d.ts → unit/interfaces/dms-base/query-response-delta.test.d.ts} +0 -0
  208. /package/dist/test/{integration/auth/signup.test.d.ts → unit/utils/email-subjects.test.d.ts} +0 -0
@@ -1,99 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const chai_1 = require("chai");
4
- const db_1 = require("../../helpers/db");
5
- const fixtures_1 = require("../../helpers/fixtures");
6
- const http_1 = require("../../helpers/http");
7
- const SIGNUP_URL = "/api/auth/signup";
8
- const VALID_PASSWORD = "TestPassw0rd!";
9
- const WEAK_PASSWORD = "weak";
10
- const TEST_EMAIL = "signup-success@test.local";
11
- const OTHER_EMAIL = "other@test.local";
12
- const NAME = "Signup User";
13
- const LANG = "en";
14
- const EXPIRED_INVITE_MS = -1000;
15
- const UNKNOWN_TOKEN = "00000000-0000-0000-0000-000000000000";
16
- describe.skip("[integration] auth/signup", () => {
17
- beforeEach(async () => {
18
- await (0, db_1.resetDatabase)();
19
- });
20
- it("signs up a user with a valid invite and returns tokens", async () => {
21
- const invite = await (0, fixtures_1.seedUserInvite)({ email: TEST_EMAIL });
22
- const client = (0, http_1.createClient)();
23
- const response = await client.post(SIGNUP_URL, {
24
- name: NAME,
25
- email: TEST_EMAIL,
26
- password: VALID_PASSWORD,
27
- lang: LANG,
28
- token: invite.token,
29
- });
30
- (0, chai_1.expect)(response.status).to.equal(200);
31
- (0, chai_1.expect)(response.data.token_type).to.equal("Bearer");
32
- (0, chai_1.expect)(response.data.access_token).to.be.a("string").and.not.empty;
33
- (0, chai_1.expect)(response.data.refresh_token).to.be.a("string").and.not.empty;
34
- (0, chai_1.expect)(response.data.user?.email).to.equal(TEST_EMAIL);
35
- });
36
- it("rejects signup with an unknown token with 400", async () => {
37
- const client = (0, http_1.createClient)();
38
- const response = await client.post(SIGNUP_URL, {
39
- name: NAME,
40
- email: TEST_EMAIL,
41
- password: VALID_PASSWORD,
42
- lang: LANG,
43
- token: UNKNOWN_TOKEN,
44
- });
45
- (0, chai_1.expect)(response.status).to.equal(400);
46
- });
47
- it("rejects signup when body email does not match invite email with 400", async () => {
48
- const invite = await (0, fixtures_1.seedUserInvite)({ email: TEST_EMAIL });
49
- const client = (0, http_1.createClient)();
50
- const response = await client.post(SIGNUP_URL, {
51
- name: NAME,
52
- email: OTHER_EMAIL,
53
- password: VALID_PASSWORD,
54
- lang: LANG,
55
- token: invite.token,
56
- });
57
- (0, chai_1.expect)(response.status).to.equal(400);
58
- });
59
- it("rejects signup when invite is expired with 400", async () => {
60
- const invite = await (0, fixtures_1.seedUserInvite)({
61
- email: TEST_EMAIL,
62
- lifetimeMs: EXPIRED_INVITE_MS,
63
- });
64
- const client = (0, http_1.createClient)();
65
- const response = await client.post(SIGNUP_URL, {
66
- name: NAME,
67
- email: TEST_EMAIL,
68
- password: VALID_PASSWORD,
69
- lang: LANG,
70
- token: invite.token,
71
- });
72
- (0, chai_1.expect)(response.status).to.equal(400);
73
- });
74
- it("rejects signup with a malformed email with 400", async () => {
75
- const invite = await (0, fixtures_1.seedUserInvite)({ email: TEST_EMAIL });
76
- const client = (0, http_1.createClient)();
77
- const response = await client.post(SIGNUP_URL, {
78
- name: NAME,
79
- email: "not-an-email",
80
- password: VALID_PASSWORD,
81
- lang: LANG,
82
- token: invite.token,
83
- });
84
- (0, chai_1.expect)(response.status).to.equal(400);
85
- });
86
- it("rejects signup with a weak password with 400", async () => {
87
- const invite = await (0, fixtures_1.seedUserInvite)({ email: TEST_EMAIL });
88
- const client = (0, http_1.createClient)();
89
- const response = await client.post(SIGNUP_URL, {
90
- name: NAME,
91
- email: TEST_EMAIL,
92
- password: WEAK_PASSWORD,
93
- lang: LANG,
94
- token: invite.token,
95
- });
96
- (0, chai_1.expect)(response.status).to.equal(400);
97
- });
98
- });
99
- //# sourceMappingURL=signup.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"signup.test.js","sourceRoot":"","sources":["../../../../src/test/integration/auth/signup.test.ts"],"names":[],"mappings":";;AAAA,+BAA8B;AAC9B,yCAAiD;AACjD,qDAAwD;AACxD,6CAAkD;AAElD,MAAM,UAAU,GAAG,kBAAkB,CAAC;AACtC,MAAM,cAAc,GAAG,eAAe,CAAC;AACvC,MAAM,aAAa,GAAG,MAAM,CAAC;AAC7B,MAAM,UAAU,GAAG,2BAA2B,CAAC;AAC/C,MAAM,WAAW,GAAG,kBAAkB,CAAC;AACvC,MAAM,IAAI,GAAG,aAAa,CAAC;AAC3B,MAAM,IAAI,GAAG,IAAI,CAAC;AAClB,MAAM,iBAAiB,GAAG,CAAC,IAAI,CAAC;AAChC,MAAM,aAAa,GAAG,sCAAsC,CAAC;AAM7D,QAAQ,CAAC,IAAI,CAAC,2BAA2B,EAAE,GAAG,EAAE;IAC9C,UAAU,CAAC,KAAK,IAAI,EAAE;QACpB,MAAM,IAAA,kBAAa,GAAE,CAAC;IACxB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,KAAK,IAAI,EAAE;QACtE,MAAM,MAAM,GAAG,MAAM,IAAA,yBAAc,EAAC,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,CAAC;QAE3D,MAAM,MAAM,GAAG,IAAA,mBAAY,GAAE,CAAC;QAC9B,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE;YAC7C,IAAI,EAAE,IAAI;YACV,KAAK,EAAE,UAAU;YACjB,QAAQ,EAAE,cAAc;YACxB,IAAI,EAAE,IAAI;YACV,KAAK,EAAE,MAAM,CAAC,KAAK;SACpB,CAAC,CAAC;QAEH,IAAA,aAAM,EAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACtC,IAAA,aAAM,EAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QACpD,IAAA,aAAM,EAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC;QACnE,IAAA,aAAM,EAAC,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC;QACpE,IAAA,aAAM,EAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;QAC7D,MAAM,MAAM,GAAG,IAAA,mBAAY,GAAE,CAAC;QAC9B,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE;YAC7C,IAAI,EAAE,IAAI;YACV,KAAK,EAAE,UAAU;YACjB,QAAQ,EAAE,cAAc;YACxB,IAAI,EAAE,IAAI;YACV,KAAK,EAAE,aAAa;SACrB,CAAC,CAAC;QAEH,IAAA,aAAM,EAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qEAAqE,EAAE,KAAK,IAAI,EAAE;QACnF,MAAM,MAAM,GAAG,MAAM,IAAA,yBAAc,EAAC,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,CAAC;QAE3D,MAAM,MAAM,GAAG,IAAA,mBAAY,GAAE,CAAC;QAC9B,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE;YAC7C,IAAI,EAAE,IAAI;YACV,KAAK,EAAE,WAAW;YAClB,QAAQ,EAAE,cAAc;YACxB,IAAI,EAAE,IAAI;YACV,KAAK,EAAE,MAAM,CAAC,KAAK;SACpB,CAAC,CAAC;QAEH,IAAA,aAAM,EAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,KAAK,IAAI,EAAE;QAC9D,MAAM,MAAM,GAAG,MAAM,IAAA,yBAAc,EAAC;YAClC,KAAK,EAAE,UAAU;YACjB,UAAU,EAAE,iBAAiB;SAC9B,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,IAAA,mBAAY,GAAE,CAAC;QAC9B,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE;YAC7C,IAAI,EAAE,IAAI;YACV,KAAK,EAAE,UAAU;YACjB,QAAQ,EAAE,cAAc;YACxB,IAAI,EAAE,IAAI;YACV,KAAK,EAAE,MAAM,CAAC,KAAK;SACpB,CAAC,CAAC;QAEH,IAAA,aAAM,EAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,KAAK,IAAI,EAAE;QAC9D,MAAM,MAAM,GAAG,MAAM,IAAA,yBAAc,EAAC,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,CAAC;QAE3D,MAAM,MAAM,GAAG,IAAA,mBAAY,GAAE,CAAC;QAC9B,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE;YAC7C,IAAI,EAAE,IAAI;YACV,KAAK,EAAE,cAAc;YACrB,QAAQ,EAAE,cAAc;YACxB,IAAI,EAAE,IAAI;YACV,KAAK,EAAE,MAAM,CAAC,KAAK;SACpB,CAAC,CAAC;QAEH,IAAA,aAAM,EAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8CAA8C,EAAE,KAAK,IAAI,EAAE;QAC5D,MAAM,MAAM,GAAG,MAAM,IAAA,yBAAc,EAAC,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,CAAC;QAE3D,MAAM,MAAM,GAAG,IAAA,mBAAY,GAAE,CAAC;QAC9B,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE;YAC7C,IAAI,EAAE,IAAI;YACV,KAAK,EAAE,UAAU;YACjB,QAAQ,EAAE,aAAa;YACvB,IAAI,EAAE,IAAI;YACV,KAAK,EAAE,MAAM,CAAC,KAAK;SACpB,CAAC,CAAC;QAEH,IAAA,aAAM,EAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -1 +0,0 @@
1
- export {};
@@ -1,137 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const node_child_process_1 = require("node:child_process");
4
- const node_fs_1 = require("node:fs");
5
- const node_os_1 = require("node:os");
6
- const node_path_1 = require("node:path");
7
- const node_util_1 = require("node:util");
8
- const chai_1 = require("chai");
9
- const PACKAGE_ROOT = (0, node_path_1.resolve)(__dirname, "..", "..", "..", "..");
10
- const SCRIPT = (0, node_path_1.join)(PACKAGE_ROOT, "skills", "dms-dev", "scripts", "dms-dev.sh");
11
- const SCRIPT_TIMEOUT_MS = 30_000;
12
- const SUITE_TIMEOUT_MS = 90_000;
13
- const STOP_GRACE_SECONDS = "1";
14
- const READY_TIMEOUT_SECONDS = "15";
15
- const PROJECT_PORTS = { first: 6110, second: 6120 };
16
- const FAKE_BACKEND = `#!/usr/bin/env bash
17
- mkdir -p .antelope
18
- printf '{"pid": %s, "servers": {"api": {"endpoints": [{"protocol": "http", "host": "0.0.0.0", "port": %s}]}}}' "$$" "$FAKE_PORT" > .antelope/dev.json
19
- sleep 300 &
20
- echo "Server started, listening on http://localhost:$FAKE_PORT"
21
- wait
22
- `;
23
- const FAKE_FRONTEND = `#!/usr/bin/env bash
24
- trap '' TERM
25
- sleep 300 &
26
- echo "Server ready on http://localhost:$((FAKE_PORT + 1))"
27
- wait
28
- `;
29
- const runProcess = (0, node_util_1.promisify)(node_child_process_1.execFile);
30
- function createProject(root, name, port) {
31
- const dir = (0, node_path_1.join)(root, name);
32
- (0, node_fs_1.mkdirSync)((0, node_path_1.join)(dir, "bin"), { recursive: true });
33
- (0, node_fs_1.writeFileSync)((0, node_path_1.join)(dir, "package.json"), "{}");
34
- (0, node_fs_1.writeFileSync)((0, node_path_1.join)(dir, "bin", "antelope-runner"), FAKE_BACKEND);
35
- (0, node_fs_1.writeFileSync)((0, node_path_1.join)(dir, "bin", "ajs-dms"), FAKE_FRONTEND);
36
- (0, node_fs_1.chmodSync)((0, node_path_1.join)(dir, "bin", "antelope-runner"), 0o755);
37
- (0, node_fs_1.chmodSync)((0, node_path_1.join)(dir, "bin", "ajs-dms"), 0o755);
38
- return { dir, port };
39
- }
40
- async function runScript(project, command) {
41
- const env = {
42
- ...process.env,
43
- FAKE_PORT: String(project.port),
44
- DMS_BACK_DIR: project.dir,
45
- DMS_BACK_CMD: (0, node_path_1.join)(project.dir, "bin", "antelope-runner"),
46
- DMS_FRONT_CMD: `${(0, node_path_1.join)(project.dir, "bin", "ajs-dms")} dev`,
47
- DMS_BACK_LOG: (0, node_path_1.join)(project.dir, "back.log"),
48
- DMS_FRONT_LOG: (0, node_path_1.join)(project.dir, "front.log"),
49
- DMS_DEV_STOP_GRACE: STOP_GRACE_SECONDS,
50
- DMS_DEV_TIMEOUT: READY_TIMEOUT_SECONDS,
51
- };
52
- try {
53
- const { stdout, stderr } = await runProcess("bash", [SCRIPT, command], {
54
- env,
55
- timeout: SCRIPT_TIMEOUT_MS,
56
- });
57
- return { code: 0, output: stdout + stderr };
58
- }
59
- catch (error) {
60
- const failure = error;
61
- return {
62
- code: failure.code ?? 1,
63
- output: `${failure.stdout ?? ""}${failure.stderr ?? ""}`,
64
- };
65
- }
66
- }
67
- function pidFile(project) {
68
- return (0, node_path_1.join)(project.dir, ".antelope", "dms-dev.pid");
69
- }
70
- function recordedPids(project) {
71
- return (0, node_fs_1.readFileSync)(pidFile(project), "utf8")
72
- .trim()
73
- .split("\n")
74
- .map((line) => Number(line.split(" ")[1]));
75
- }
76
- function isAlive(pid) {
77
- try {
78
- process.kill(pid, 0);
79
- return true;
80
- }
81
- catch {
82
- return false;
83
- }
84
- }
85
- describe("[unit] skills/dms-dev script", function () {
86
- this.timeout(SUITE_TIMEOUT_MS);
87
- let root;
88
- let first;
89
- let second;
90
- beforeEach(() => {
91
- root = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "dms-dev-script-"));
92
- first = createProject(root, "first", PROJECT_PORTS.first);
93
- second = createProject(root, "second", PROJECT_PORTS.second);
94
- });
95
- afterEach(async () => {
96
- await runScript(first, "stop");
97
- await runScript(second, "stop");
98
- (0, node_fs_1.rmSync)(root, { recursive: true, force: true });
99
- });
100
- it("reports the ports the servers announce", async () => {
101
- const started = await runScript(first, "start");
102
- (0, chai_1.expect)(started.code, started.output).to.equal(0);
103
- (0, chai_1.expect)(started.output).to.contain(`backend ready on http://localhost:${PROJECT_PORTS.first}.`);
104
- (0, chai_1.expect)(started.output).to.contain(`frontend ready on http://localhost:${PROJECT_PORTS.first + 1}.`);
105
- });
106
- it("stops only the processes of its own project", async () => {
107
- await runScript(first, "start");
108
- await runScript(second, "start");
109
- const firstPids = recordedPids(first);
110
- const secondPids = recordedPids(second);
111
- const stopped = await runScript(first, "stop");
112
- (0, chai_1.expect)(stopped.code, stopped.output).to.equal(0);
113
- (0, chai_1.expect)(firstPids.filter(isAlive)).to.deep.equal([]);
114
- (0, chai_1.expect)(secondPids.filter(isAlive)).to.deep.equal(secondPids);
115
- (0, chai_1.expect)((0, node_fs_1.existsSync)(pidFile(first))).to.equal(false);
116
- });
117
- it("falls back to the project's directory when the pid file is gone", async () => {
118
- await runScript(first, "start");
119
- await runScript(second, "start");
120
- const firstPids = recordedPids(first);
121
- const secondPids = recordedPids(second);
122
- (0, node_fs_1.rmSync)(pidFile(first));
123
- const stopped = await runScript(first, "stop");
124
- (0, chai_1.expect)(stopped.code, stopped.output).to.equal(0);
125
- (0, chai_1.expect)(firstPids.filter(isAlive)).to.deep.equal([]);
126
- (0, chai_1.expect)(secondPids.filter(isAlive)).to.deep.equal(secondPids);
127
- });
128
- it("fails fast when the server command dies right away", async () => {
129
- (0, node_fs_1.rmSync)((0, node_path_1.join)(first.dir, "bin", "antelope-runner"));
130
- const startedAt = Date.now();
131
- const started = await runScript(first, "start");
132
- (0, chai_1.expect)(started.code).to.equal(1);
133
- (0, chai_1.expect)(started.output).to.contain("exited before becoming ready");
134
- (0, chai_1.expect)(Date.now() - startedAt).to.be.below(SCRIPT_TIMEOUT_MS / 2);
135
- });
136
- });
137
- //# sourceMappingURL=dms-dev-script.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"dms-dev-script.test.js","sourceRoot":"","sources":["../../../../src/test/unit/skills/dms-dev-script.test.ts"],"names":[],"mappings":"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"}
@@ -1,20 +0,0 @@
1
- import { readFileSync } from "node:fs";
2
- import { expect, it } from "vitest";
3
-
4
- const formSource = readFileSync(
5
- new URL("../layers/dms-ui/app/components/form/Form.vue", import.meta.url),
6
- "utf8",
7
- );
8
-
9
- // The load of a form is cached under its component and page ids, which a
10
- // drawer or modal reopened on the same row shares: the second opening showed
11
- // the first one's values, stale if the row changed in between, and a save
12
- // then wrote them back.
13
- it("fetches its record again every time a form is mounted", () => {
14
- const loadBlock = formSource.slice(
15
- formSource.indexOf("if (props.fetchUrl) {"),
16
- );
17
- expect(loadBlock).toMatch(
18
- /const formLoad = await useDmsAsyncData\([\s\S]*?onMounted\(\(\) => \{\s*formLoad\.status\.value = "idle";\s*\}\);/,
19
- );
20
- });
@@ -1,29 +0,0 @@
1
- import { readFileSync, readdirSync, statSync } from "node:fs";
2
- import { join, relative } from "node:path";
3
- import { describe, expect, it } from "vitest";
4
-
5
- const ICON_TAG = /<(?:UIcon|Icon)\b[^>]*?>/gs;
6
- const STATIC_ARIA_HIDDEN = /(?<![:\w-])aria-hidden=/;
7
-
8
- function walk(directory: string): string[] {
9
- return readdirSync(directory).flatMap((name) => {
10
- const path = join(directory, name);
11
- return statSync(path).isDirectory() ? walk(path) : [path];
12
- });
13
- }
14
-
15
- describe("icon aria-hidden bindings", () => {
16
- // The icon hands its attributes to Iconify's component, whose `ariaHidden`
17
- // prop is a Boolean: a static attribute reaches it as the string "true".
18
- it("binds aria-hidden on icons as a boolean", () => {
19
- const offenders = walk(join(process.cwd(), "layers"))
20
- .filter((path) => path.endsWith(".vue"))
21
- .flatMap((path) =>
22
- [...readFileSync(path, "utf8").matchAll(ICON_TAG)]
23
- .filter(([tag]) => STATIC_ARIA_HIDDEN.test(tag))
24
- .map(() => relative(process.cwd(), path)),
25
- );
26
-
27
- expect(offenders).toEqual([]);
28
- });
29
- });
@@ -1,30 +0,0 @@
1
- import { readFileSync, readdirSync, statSync } from "node:fs";
2
- import { join, relative } from "node:path";
3
- import { describe, expect, it } from "vitest";
4
-
5
- const PARAGRAPH = /<p\b[^>]*>(.*?)<\/p>/gs;
6
- const SKELETON = /<USkeleton\b/;
7
-
8
- function walk(directory: string): string[] {
9
- return readdirSync(directory).flatMap((name) => {
10
- const path = join(directory, name);
11
- return statSync(path).isDirectory() ? walk(path) : [path];
12
- });
13
- }
14
-
15
- describe("skeleton placement", () => {
16
- // The skeleton renders a <div>. The browser's parser closes an open <p>
17
- // before a <div>, so the server markup no longer matches the client tree
18
- // and hydration reports a mismatch.
19
- it("keeps skeletons out of paragraphs", () => {
20
- const offenders = walk(join(process.cwd(), "layers"))
21
- .filter((path) => path.endsWith(".vue"))
22
- .flatMap((path) =>
23
- [...readFileSync(path, "utf8").matchAll(PARAGRAPH)]
24
- .filter(([, content]) => SKELETON.test(content ?? ""))
25
- .map(() => relative(process.cwd(), path)),
26
- );
27
-
28
- expect(offenders).toEqual([]);
29
- });
30
- });
@@ -1,29 +0,0 @@
1
- import { readFileSync } from "node:fs";
2
- import { expect, it } from "vitest";
3
-
4
- /** The room the page leaves between its blocks. */
5
- const BLOCK_SPACING = "space-y-6";
6
-
7
- const sourceOf = (file: string) =>
8
- readFileSync(new URL(`../layers/${file}`, import.meta.url), "utf8");
9
-
10
- // A tab holding two blocks stacked them edge to edge, while the page spaces
11
- // the same two blocks placed outside a tab.
12
- it("spaces the blocks of a tab the way the page spaces its own", () => {
13
- expect(sourceOf("dms-layout/app/pages/[...slug].vue")).toContain(
14
- `dms-page-stack ${BLOCK_SPACING}`,
15
- );
16
- expect(sourceOf("dms-ui/app/components/tab/Tab.vue")).toMatch(
17
- new RegExp(
18
- `<div class="[^"]*\\b${BLOCK_SPACING}\\b[^"]*"[^>]*>\\s*<slot :name="item.slot" />`,
19
- ),
20
- );
21
- });
22
-
23
- // A guard holding two blocks drew them edge to edge: the page spaces its own
24
- // wrapper, not the blocks inside it.
25
- it("spaces the blocks of a guard the way the page spaces its own", () => {
26
- expect(sourceOf("dms-ui/app/components/guard/Guard.vue")).toMatch(
27
- new RegExp(`<div class="[^"]*\\b${BLOCK_SPACING}\\b[^"]*" data-dms-guard>`),
28
- );
29
- });
@@ -1,25 +0,0 @@
1
- import { readFileSync } from "node:fs";
2
- import { resolve } from "node:path";
3
- import { describe, expect, it } from "vitest";
4
-
5
- const tableSource = readFileSync(
6
- resolve(__dirname, "../layers/dms-ui/app/build/components/table/Table.vue"),
7
- "utf8",
8
- );
9
-
10
- describe("table empty body", () => {
11
- it("centres on the visible part of a table wider than its card", () => {
12
- expect(tableSource).toMatch(
13
- /emptyBody:\s*"sticky start-0 w-\[var\(--dms-table-viewport,auto\)\]"/,
14
- );
15
- expect(tableSource).toMatch(
16
- /<div :class="uiTable\.emptyBody\(\)">\s*<TableEmpty/,
17
- );
18
- });
19
-
20
- it("knows the visible width of every table, not only expandable ones", () => {
21
- expect(tableSource).toMatch(
22
- /"--dms-table-viewport":\s*tableViewportWidth\.value > 0/,
23
- );
24
- });
25
- });
@@ -1,21 +0,0 @@
1
- import { readFileSync } from "node:fs";
2
- import { resolve } from "node:path";
3
- import { describe, expect, it } from "vitest";
4
-
5
- const tableSource = readFileSync(
6
- resolve(__dirname, "../layers/dms-ui/app/build/components/table/Table.vue"),
7
- "utf8",
8
- );
9
-
10
- describe("Table buttons placed in the page header", () => {
11
- it("leaves them out of the toolbar", () => {
12
- expect(tableSource).toMatch(
13
- /\(props\.customButtons \?\? \[\]\)\.filter\(\s*\(button\) => button\.placement !== HEADER_PLACEMENT,\s*\)/,
14
- );
15
- expect(tableSource).toMatch(
16
- /add\.isEnabled && add\.placement !== HEADER_PLACEMENT/,
17
- );
18
- expect(tableSource).toContain(':can-add-row="canAddFromToolbar"');
19
- expect(tableSource).not.toContain("button.hidden");
20
- });
21
- });
@@ -1,107 +0,0 @@
1
- import { readFileSync, readdirSync, statSync } from "node:fs";
2
- import { join, relative } from "node:path";
3
- import { describe, expect, it } from "vitest";
4
-
5
- const EXPECTED_VUE_FILES = 278;
6
-
7
- function walk(directory: string): string[] {
8
- return readdirSync(directory).flatMap((name) => {
9
- const path = join(directory, name);
10
- return statSync(path).isDirectory() ? walk(path) : [path];
11
- });
12
- }
13
-
14
- function ownership(path: string): string | undefined {
15
- const owners: Array<[RegExp, string]> = [
16
- [/\/app\/(?:components|build\/components)\/.*\.vue$/, "component"],
17
- [/\/app\/custom-pages\/.*\.vue$/, "custom-page"],
18
- [/\/app\/pages\/.*\.vue$/, "dynamic-page"],
19
- [/\/app\/custom-layouts\/.*\.vue$/, "layout"],
20
- [/\/app\/error\.vue$/, "inertia-error-page"],
21
- [/\/app\/emails\/.*\.vue$/, "server-email-template"],
22
- ];
23
- // Forward slashes on every OS, so the patterns also match Windows paths.
24
- const normalized = path.replaceAll("\\", "/");
25
- return owners.find(([pattern]) => pattern.test(normalized))?.[1];
26
- }
27
-
28
- describe("Vue source inventory", () => {
29
- it("contains only Vue frontend source files", () => {
30
- const files = walk(join(process.cwd(), "layers")).map((path) =>
31
- path.replaceAll("\\", "/"),
32
- );
33
- expect(files.filter((path) => path.includes("/server/"))).toEqual([]);
34
- });
35
-
36
- it("assigns every Vue file an explicit runtime owner", () => {
37
- const files = walk(join(process.cwd(), "layers"))
38
- .filter((path) => path.endsWith(".vue"))
39
- .map((path) => relative(process.cwd(), path));
40
- expect(files).toHaveLength(EXPECTED_VUE_FILES);
41
- expect(files.filter((path) => !ownership(path))).toEqual([]);
42
- expect(
43
- files.filter((path) => ownership(path) === "server-email-template"),
44
- ).toHaveLength(10);
45
- });
46
-
47
- it("exposes entries for the frontend adapter", () => {
48
- const root = process.cwd();
49
- const frontendModule = readFileSync(join(root, "dms.frontend.ts"), "utf8");
50
-
51
- expect(frontendModule).toContain(
52
- 'import "./layers/dms-layout/app/assets/css/main.css"',
53
- );
54
- expect(frontendModule).toContain('"./layers/**/app/custom-pages/**/*.vue"');
55
- expect(frontendModule).toContain(
56
- '"./layers/**/app/custom-layouts/**/*.vue"',
57
- );
58
- expect(frontendModule).toContain('"./layers/**/app/error.vue"');
59
- expect(frontendModule).toContain('componentPrefix: "Dms"');
60
- expect(frontendModule).toContain(
61
- "sdk.registerComponent(pascalCase(name), component)",
62
- );
63
- for (const [name, alias] of [
64
- ["ActivityFeed", "ActivityFeedBlock"],
65
- ["Section", "SectionBlock"],
66
- ["FieldRow", "FieldRowBlock"],
67
- ]) {
68
- expect(frontendModule).toContain(`${name}: "${alias}"`);
69
- }
70
- expect(frontendModule).toContain('.replace(/\\/index$/, "")');
71
- expect(frontendModule).toContain(
72
- "sdk.registerErrorPage(lazyComponent(loader), loader)",
73
- );
74
-
75
- const entries = walk(join(root, "layers"))
76
- .map((path) => path.replaceAll("\\", "/"))
77
- .filter(
78
- (path) =>
79
- path.includes("/app/custom-pages/") ||
80
- path.endsWith("/app/error.vue"),
81
- );
82
- expect(entries).not.toHaveLength(0);
83
- expect(
84
- entries.every((path) => path.endsWith(".vue") && statSync(path).isFile()),
85
- ).toBe(true);
86
- expect(
87
- statSync(
88
- join(root, "layers/dms-layout/app/custom-layouts/DefaultLayout.vue"),
89
- ).isFile(),
90
- ).toBe(true);
91
- });
92
-
93
- it("registers lazy components and reports deterministic name collisions", () => {
94
- const frontendModule = readFileSync(
95
- join(process.cwd(), "dms.frontend.ts"),
96
- "utf8",
97
- );
98
- expect(frontendModule).toContain("defineAsyncComponent");
99
- expect(frontendModule).toContain("sortedEntries(components)");
100
- expect(frontendModule).toContain(
101
- "Duplicate component name ${name}: ${previousPath}, ${path}",
102
- );
103
- expect(frontendModule).not.toMatch(
104
- /components\|build\/components}[\s\S]*eager: true/,
105
- );
106
- });
107
- });