@gnar-engine/cli 1.0.3 → 1.0.5

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 (259) hide show
  1. package/bootstrap/deploy.localdev.yml +44 -30
  2. package/bootstrap/secrets.localdev.yml +20 -14
  3. package/bootstrap/services/control/src/config.js +4 -0
  4. package/bootstrap/services/{agent → page}/Dockerfile +3 -3
  5. package/bootstrap/services/page/package.json +16 -0
  6. package/bootstrap/services/page/src/app.js +50 -0
  7. package/bootstrap/services/page/src/commands/block.handler.js +94 -0
  8. package/bootstrap/services/page/src/commands/page.handler.js +167 -0
  9. package/bootstrap/services/page/src/config.js +62 -0
  10. package/bootstrap/services/page/src/controllers/block.http.controller.js +87 -0
  11. package/bootstrap/services/page/src/controllers/message.controller.js +51 -0
  12. package/bootstrap/services/page/src/controllers/page.http.controller.js +89 -0
  13. package/bootstrap/services/page/src/policies/block.policy.js +50 -0
  14. package/bootstrap/services/page/src/policies/page.policy.js +49 -0
  15. package/bootstrap/services/page/src/schema/page.schema.js +139 -0
  16. package/bootstrap/services/page/src/services/block.service.js +83 -0
  17. package/bootstrap/services/page/src/services/page.service.js +83 -0
  18. package/bootstrap/services/portal/Dockerfile +7 -10
  19. package/bootstrap/services/portal/README.md +66 -15
  20. package/bootstrap/services/portal/index.html +13 -0
  21. package/bootstrap/services/portal/nginx.conf +5 -12
  22. package/bootstrap/services/portal/package.json +27 -53
  23. package/bootstrap/services/portal/public/vite.svg +1 -0
  24. package/bootstrap/services/portal/react-router.config.js +7 -0
  25. package/bootstrap/services/portal/src/App.jsx +16 -0
  26. package/bootstrap/services/portal/src/assets/gnar-engine-white-logo.svg +9 -0
  27. package/bootstrap/services/portal/src/assets/icon-agent.svg +6 -0
  28. package/bootstrap/services/portal/src/assets/icon-cog.svg +4 -0
  29. package/bootstrap/services/portal/src/assets/icon-delete.svg +3 -0
  30. package/bootstrap/services/portal/src/assets/icon-home.svg +3 -0
  31. package/bootstrap/services/portal/src/assets/icon-padlock.svg +3 -0
  32. package/bootstrap/services/portal/src/assets/icon-page.svg +6 -0
  33. package/bootstrap/services/portal/src/assets/icon-reports.svg +3 -0
  34. package/bootstrap/services/portal/src/assets/icon-user.svg +3 -0
  35. package/bootstrap/services/portal/src/assets/icon-users.svg +3 -0
  36. package/bootstrap/services/portal/src/assets/login-green-rad-back-1.jpg +0 -0
  37. package/bootstrap/services/portal/src/assets/react.svg +1 -0
  38. package/bootstrap/services/portal/src/components/CrudList/CrudList.jsx +85 -0
  39. package/bootstrap/services/portal/src/components/CrudList/CrudList.less +59 -0
  40. package/bootstrap/services/portal/src/{ui/customSelect → components/CustomSelect}/CustomSelect.jsx +21 -3
  41. package/bootstrap/services/portal/src/components/LoginForm/LoginForm.jsx +58 -0
  42. package/bootstrap/services/portal/src/components/PageBlockSwitch/PageBlockSwitch.jsx +129 -0
  43. package/bootstrap/services/portal/src/components/Sidebar/Sidebar.jsx +33 -0
  44. package/bootstrap/services/portal/src/components/Sidebar/Sidebar.less +37 -0
  45. package/bootstrap/services/portal/src/components/Topbar/Topbar.jsx +19 -0
  46. package/bootstrap/services/portal/src/components/Topbar/Topbar.less +22 -0
  47. package/bootstrap/services/portal/src/components/UserInfo/UserInfo.jsx +33 -0
  48. package/bootstrap/services/portal/src/components/UserInfo/UserInfo.less +21 -0
  49. package/bootstrap/services/portal/src/css/style.css +446 -742
  50. package/bootstrap/services/portal/src/data/pages.data.js +10 -0
  51. package/bootstrap/services/portal/src/elements/CustomSelect/CustomSelect.jsx +65 -0
  52. package/bootstrap/services/portal/src/{ui/customSelect/customSelect.less → elements/CustomSelect/CustomSelect.less} +17 -7
  53. package/bootstrap/services/portal/src/elements/ImageInput/ImageInput.jsx +115 -0
  54. package/bootstrap/services/portal/src/elements/ImageInput/ImageInput.less +43 -0
  55. package/bootstrap/services/portal/src/elements/ImageMultiInput/ImageMultiInput.jsx +124 -0
  56. package/bootstrap/services/portal/src/elements/ImageMultiInput/ImageMultiInput.less +0 -0
  57. package/bootstrap/services/portal/src/elements/Repeater/Repeater.jsx +52 -0
  58. package/bootstrap/services/portal/src/elements/Repeater/Repeater.less +70 -0
  59. package/bootstrap/services/portal/src/elements/RichTextInput/RichTextInput.jsx +18 -0
  60. package/bootstrap/services/portal/src/elements/RichTextInput/RichTextInput.less +37 -0
  61. package/bootstrap/services/portal/src/elements/SaveButton/SaveButton.jsx +45 -0
  62. package/bootstrap/services/portal/src/elements/SelectRepeater/SelectRepeater.jsx +63 -0
  63. package/bootstrap/services/portal/src/elements/SelectRepeater/SelectRepeater.less +23 -0
  64. package/bootstrap/services/portal/src/elements/TextInput/TextInput.jsx +17 -0
  65. package/bootstrap/services/portal/src/layouts/Card/Card.jsx +15 -0
  66. package/bootstrap/services/portal/src/layouts/PortalLayout/PortalLayout.jsx +29 -0
  67. package/bootstrap/services/portal/src/layouts/PortalLayout/PortalLayout.less +49 -0
  68. package/bootstrap/services/portal/src/main.jsx +51 -0
  69. package/bootstrap/services/portal/src/pages/BlockSinglePage/BlockSinglePage.jsx +277 -0
  70. package/bootstrap/services/portal/src/pages/BlocksPage/BlocksPage.jsx +23 -0
  71. package/bootstrap/services/portal/src/pages/DashboardPage/DashboardPage.jsx +11 -0
  72. package/bootstrap/services/portal/src/pages/DashboardPage/DashboardPage.less +0 -0
  73. package/bootstrap/services/portal/src/pages/LoginPage/LoginPage.jsx +21 -0
  74. package/bootstrap/services/portal/src/pages/LoginPage/LoginPage.less +51 -0
  75. package/bootstrap/services/portal/src/pages/PageSinglePage/PageSinglePage.jsx +338 -0
  76. package/bootstrap/services/portal/src/pages/PagesPage/PagesPage.jsx +23 -0
  77. package/bootstrap/services/portal/src/pages/UserSinglePage/UserSinglePage.jsx +9 -0
  78. package/bootstrap/services/portal/src/pages/UserSinglePage/UserSinglePage.less +0 -0
  79. package/bootstrap/services/portal/src/pages/UsersPage/UsersPage.jsx +25 -0
  80. package/bootstrap/services/portal/src/pages/UsersPage/UsersPage.less +0 -0
  81. package/bootstrap/services/portal/src/services/block.js +28 -0
  82. package/bootstrap/services/portal/src/services/client.js +67 -0
  83. package/bootstrap/services/portal/src/services/gravatar.js +14 -0
  84. package/bootstrap/services/portal/src/services/page.js +28 -0
  85. package/bootstrap/services/portal/src/services/storage.js +62 -0
  86. package/bootstrap/services/portal/src/services/user.js +41 -0
  87. package/bootstrap/services/portal/src/slices/authSlice.js +44 -14
  88. package/bootstrap/services/portal/src/store/configureStore.js +1 -3
  89. package/bootstrap/services/portal/src/style/cards.less +57 -0
  90. package/bootstrap/services/portal/src/{styles → style}/global.less +90 -45
  91. package/bootstrap/services/portal/src/style/icons.less +21 -0
  92. package/bootstrap/services/portal/src/style/inputs.less +52 -0
  93. package/bootstrap/services/portal/src/style/main.less +28 -0
  94. package/bootstrap/services/portal/src/utils/utils.js +9 -0
  95. package/bootstrap/services/portal/vite.config.js +12 -0
  96. package/bootstrap/services/user/Dockerfile +1 -1
  97. package/bootstrap/services/user/src/app.js +6 -1
  98. package/bootstrap/services/user/src/commands/user.handler.js +0 -3
  99. package/bootstrap/services/user/src/config.js +5 -1
  100. package/bootstrap/services/user/src/policies/user.policy.js +3 -1
  101. package/bootstrap/services/user/src/tests/commands/user.test.js +22 -0
  102. package/install-from-clone.sh +30 -0
  103. package/package.json +1 -1
  104. package/src/cli.js +8 -0
  105. package/src/config.js +2 -1
  106. package/src/dev/commands.js +10 -2
  107. package/src/dev/dev.service.js +167 -52
  108. package/src/provisioner/Dockerfile +27 -0
  109. package/src/provisioner/package.json +19 -0
  110. package/src/provisioner/src/app.js +56 -0
  111. package/src/provisioner/src/services/mongodb.js +58 -0
  112. package/src/provisioner/src/services/mysql.js +51 -0
  113. package/src/provisioner/src/services/secrets.js +84 -0
  114. package/src/scaffolder/commands.js +12 -5
  115. package/src/scaffolder/scaffolder.handler.js +256 -58
  116. package/templates/service/Dockerfile.hbs +4 -1
  117. package/templates/service/package.json.hbs +14 -16
  118. package/templates/service/src/app.js.hbs +53 -0
  119. package/templates/service/{commands → src/commands}/{{serviceName}}.handler.js.hbs +2 -3
  120. package/templates/service/src/mongodb.config.js.hbs +49 -0
  121. package/templates/service/{config.js.hbs → src/mysql.config.js.hbs} +10 -0
  122. package/{bootstrap/services/agent/src/schema/Agent.schema.js → templates/service/src/schema/{{serviceName}}.schema.js.hbs} +3 -3
  123. package/templates/service/src/services/mongodb.{{serviceName}}.service.js.hbs +70 -0
  124. package/bootstrap/services/agent/notes.md +0 -28
  125. package/bootstrap/services/agent/package.json +0 -16
  126. package/bootstrap/services/agent/src/app.js +0 -52
  127. package/bootstrap/services/agent/src/commands/agent.handler.js +0 -104
  128. package/bootstrap/services/agent/src/config.js +0 -52
  129. package/bootstrap/services/agent/src/controllers/http.controller.js +0 -44
  130. package/bootstrap/services/agent/src/controllers/message.controller.js +0 -51
  131. package/bootstrap/services/agent/src/db/migrations/01-init.js +0 -50
  132. package/bootstrap/services/agent/src/db/migrations/02-agent-service-init.js +0 -36
  133. package/bootstrap/services/agent/src/policies/agent.policy.js +0 -13
  134. package/bootstrap/services/agent/src/services/agent.service.js +0 -259
  135. package/bootstrap/services/agent/src/services/chatgpt.service.js +0 -46
  136. package/bootstrap/services/agent/src/services/manifest.service.js +0 -21
  137. package/bootstrap/services/portal/Dockerfile.remote +0 -40
  138. package/bootstrap/services/portal/public/favicon.ico +0 -0
  139. package/bootstrap/services/portal/public/gnar-white.png +0 -0
  140. package/bootstrap/services/portal/public/gnarengine-logo-black.png +0 -0
  141. package/bootstrap/services/portal/public/index.html +0 -43
  142. package/bootstrap/services/portal/public/logo192.png +0 -0
  143. package/bootstrap/services/portal/public/logo512.png +0 -0
  144. package/bootstrap/services/portal/public/manifest.json +0 -25
  145. package/bootstrap/services/portal/public/robots.txt +0 -3
  146. package/bootstrap/services/portal/src/App.js +0 -56
  147. package/bootstrap/services/portal/src/assets/Logo_Anchord_Black.svg +0 -1
  148. package/bootstrap/services/portal/src/assets/Logo_Anchord_Black_Green.svg +0 -1
  149. package/bootstrap/services/portal/src/assets/Logo_Anchord_White_Green.svg +0 -1
  150. package/bootstrap/services/portal/src/assets/activity.svg +0 -3
  151. package/bootstrap/services/portal/src/assets/arrow.svg +0 -3
  152. package/bootstrap/services/portal/src/assets/bin-white.svg +0 -3
  153. package/bootstrap/services/portal/src/assets/bin.svg +0 -3
  154. package/bootstrap/services/portal/src/assets/check.svg +0 -3
  155. package/bootstrap/services/portal/src/assets/chevron.svg +0 -3
  156. package/bootstrap/services/portal/src/assets/contact.svg +0 -3
  157. package/bootstrap/services/portal/src/assets/dots-vertical.svg +0 -5
  158. package/bootstrap/services/portal/src/assets/eye-off.svg +0 -3
  159. package/bootstrap/services/portal/src/assets/eye.svg +0 -4
  160. package/bootstrap/services/portal/src/assets/gnar-engine-black.svg +0 -47
  161. package/bootstrap/services/portal/src/assets/gnar-engine-white.svg +0 -47
  162. package/bootstrap/services/portal/src/assets/gnar_engine.svg +0 -3
  163. package/bootstrap/services/portal/src/assets/gnarengine-logo-black.png +0 -0
  164. package/bootstrap/services/portal/src/assets/home.svg +0 -3
  165. package/bootstrap/services/portal/src/assets/link.svg +0 -3
  166. package/bootstrap/services/portal/src/assets/lock.svg +0 -3
  167. package/bootstrap/services/portal/src/assets/package.svg +0 -4
  168. package/bootstrap/services/portal/src/assets/raffle.svg +0 -3
  169. package/bootstrap/services/portal/src/assets/settings.svg +0 -4
  170. package/bootstrap/services/portal/src/assets/shopping-bag.svg +0 -3
  171. package/bootstrap/services/portal/src/assets/user-black.svg +0 -3
  172. package/bootstrap/services/portal/src/assets/user.svg +0 -3
  173. package/bootstrap/services/portal/src/assets/users.svg +0 -3
  174. package/bootstrap/services/portal/src/assets/wallet.svg +0 -3
  175. package/bootstrap/services/portal/src/data/data.js +0 -70
  176. package/bootstrap/services/portal/src/features/attributeFormRow/AttributeFormRow.jsx +0 -32
  177. package/bootstrap/services/portal/src/features/billingShipping/BillingShipping.jsx +0 -160
  178. package/bootstrap/services/portal/src/features/crud/crudEdit.less +0 -230
  179. package/bootstrap/services/portal/src/features/crud/crudList.less +0 -134
  180. package/bootstrap/services/portal/src/features/crud/crudPage.less +0 -31
  181. package/bootstrap/services/portal/src/features/crudContact/CrudContactList.jsx +0 -108
  182. package/bootstrap/services/portal/src/features/crudContact/CrudContactSingle.jsx +0 -243
  183. package/bootstrap/services/portal/src/features/crudOrder/CrudOrderList.jsx +0 -109
  184. package/bootstrap/services/portal/src/features/crudOrder/CrudOrderSingle.jsx +0 -315
  185. package/bootstrap/services/portal/src/features/crudProducts/CrudProductList.jsx +0 -104
  186. package/bootstrap/services/portal/src/features/crudProducts/CrudProductSingle.jsx +0 -388
  187. package/bootstrap/services/portal/src/features/crudRaffles/CrudRafflesList.jsx +0 -104
  188. package/bootstrap/services/portal/src/features/crudRaffles/CrudRafflesSingle.jsx +0 -208
  189. package/bootstrap/services/portal/src/features/crudSubscription/CrudSubscriptionList.jsx +0 -110
  190. package/bootstrap/services/portal/src/features/crudSubscription/CrudSubscriptionSingle.jsx +0 -261
  191. package/bootstrap/services/portal/src/features/crudUser/CrudUserList.jsx +0 -107
  192. package/bootstrap/services/portal/src/features/crudUser/CrudUserSingle.jsx +0 -402
  193. package/bootstrap/services/portal/src/features/inventoryFormRow/InventoryFormRow.jsx +0 -30
  194. package/bootstrap/services/portal/src/features/lineItems/LineItems.jsx +0 -113
  195. package/bootstrap/services/portal/src/features/loginForm/LoginForm.jsx +0 -56
  196. package/bootstrap/services/portal/src/features/loginForm/loginForm.less +0 -56
  197. package/bootstrap/services/portal/src/features/notes/Notes.jsx +0 -18
  198. package/bootstrap/services/portal/src/features/passwordReset/PasswordResetForm.jsx +0 -96
  199. package/bootstrap/services/portal/src/features/passwordReset/PasswordResetRequestForm.jsx +0 -74
  200. package/bootstrap/services/portal/src/features/priceFormRow/PriceFormRow.jsx +0 -102
  201. package/bootstrap/services/portal/src/features/priceFormRow/priceFormRow.less +0 -24
  202. package/bootstrap/services/portal/src/features/raffleEntriesList/RaffleEntriesList.jsx +0 -99
  203. package/bootstrap/services/portal/src/features/raffleProductFormRow/RaffleProductFormRow.jsx +0 -46
  204. package/bootstrap/services/portal/src/features/sidebar/Sidebar.jsx +0 -64
  205. package/bootstrap/services/portal/src/features/sidebar/sidebar.less +0 -49
  206. package/bootstrap/services/portal/src/features/skus/Skus.jsx +0 -109
  207. package/bootstrap/services/portal/src/features/subscriptionSchedule/SubscriptionSchedule.jsx +0 -44
  208. package/bootstrap/services/portal/src/features/taxonomyFormRow/TaxonomyFormRow.jsx +0 -32
  209. package/bootstrap/services/portal/src/features/user/User.jsx +0 -54
  210. package/bootstrap/services/portal/src/features/user/user.less +0 -57
  211. package/bootstrap/services/portal/src/includes/utilities.js +0 -259
  212. package/bootstrap/services/portal/src/index.js +0 -14
  213. package/bootstrap/services/portal/src/layouts/CrudLayout.jsx +0 -50
  214. package/bootstrap/services/portal/src/layouts/LoginLayout.jsx +0 -17
  215. package/bootstrap/services/portal/src/layouts/PortalLayout.jsx +0 -48
  216. package/bootstrap/services/portal/src/layouts/loginLayout.less +0 -33
  217. package/bootstrap/services/portal/src/layouts/portalLayout.less +0 -67
  218. package/bootstrap/services/portal/src/pages/contacts/Contacts.jsx +0 -199
  219. package/bootstrap/services/portal/src/pages/dashboard/Dashboard.jsx +0 -17
  220. package/bootstrap/services/portal/src/pages/integrations/Integrations.jsx +0 -10
  221. package/bootstrap/services/portal/src/pages/login/Login.jsx +0 -15
  222. package/bootstrap/services/portal/src/pages/login/login.less +0 -10
  223. package/bootstrap/services/portal/src/pages/orders/Orders.jsx +0 -199
  224. package/bootstrap/services/portal/src/pages/passwordReset/PasswordResetPage.jsx +0 -15
  225. package/bootstrap/services/portal/src/pages/passwordResetRequest/PasswordResetRequestPage.jsx +0 -15
  226. package/bootstrap/services/portal/src/pages/payments/Payments.jsx +0 -10
  227. package/bootstrap/services/portal/src/pages/portal/Portal.jsx +0 -43
  228. package/bootstrap/services/portal/src/pages/products/Products.jsx +0 -212
  229. package/bootstrap/services/portal/src/pages/raffleEntries/RaffleEntries.jsx +0 -124
  230. package/bootstrap/services/portal/src/pages/raffles/Raffles.jsx +0 -186
  231. package/bootstrap/services/portal/src/pages/reports/Reports.jsx +0 -10
  232. package/bootstrap/services/portal/src/pages/settings/Settings.jsx +0 -10
  233. package/bootstrap/services/portal/src/pages/subscriptions/Subscriptions.jsx +0 -199
  234. package/bootstrap/services/portal/src/pages/users/Users.jsx +0 -193
  235. package/bootstrap/services/portal/src/pages/users/users.less +0 -25
  236. package/bootstrap/services/portal/src/styles/inputs.less +0 -157
  237. package/bootstrap/services/portal/src/styles/main.less +0 -26
  238. package/bootstrap/services/portal/src/ui/collapsible/Collapsible.jsx +0 -97
  239. package/bootstrap/services/portal/src/ui/collapsible/collapsible.less +0 -23
  240. package/bootstrap/services/portal/src/ui/customCheckbox/CustomCheckbox.jsx +0 -17
  241. package/bootstrap/services/portal/src/ui/customCheckbox/customCheckbox.less +0 -42
  242. package/bootstrap/services/portal/src/ui/customMultiSelect/CustomMultiSelect.jsx +0 -63
  243. package/bootstrap/services/portal/src/ui/customMultiSelect/CustomMultiSelectPeriod.jsx +0 -63
  244. package/bootstrap/services/portal/src/ui/goBack/GoBack.jsx +0 -19
  245. package/bootstrap/services/portal/src/ui/loader/Loader.jsx +0 -12
  246. package/bootstrap/services/portal/src/ui/pagination/Pagination.jsx +0 -23
  247. package/bootstrap/services/portal/src/ui/repeater/Repeater.jsx +0 -29
  248. package/bootstrap/services/portal/src/ui/saveButton/SaveButton.jsx +0 -69
  249. package/bootstrap/services/user/src/db/seeders/development/02-portal-admin-user.js +0 -27
  250. package/bootstrap/services/user/src/tests/user.test.js +0 -126
  251. package/templates/service/app.js.hbs +0 -38
  252. package/templates/service/schema/{{serviceName}}.schema.js.hbs +0 -14
  253. /package/bootstrap/services/portal/src/{ui/saveButton/saveButton.less → components/CustomSelect/CustomSelect.less} +0 -0
  254. /package/templates/service/{controllers → src/controllers}/http.controller.js.hbs +0 -0
  255. /package/templates/service/{controllers → src/controllers}/message.controller.js.hbs +0 -0
  256. /package/templates/service/{db → src/mysql.db}/migrations/01-init.js.hbs +0 -0
  257. /package/templates/service/{db → src/mysql.db}/migrations/02-{{lowerCase serviceName}}-service-init.js.hbs +0 -0
  258. /package/templates/service/{policies → src/policies}/{{serviceName}}.policy.js.hbs +0 -0
  259. /package/templates/service/{services/{{serviceName}}.service.js.hbs → src/services/mysql.{{serviceName}}.service.js.hbs} +0 -0
@@ -0,0 +1,51 @@
1
+ import { commands } from '@gnar-engine/core';
2
+
3
+ export const messageHandlers = {
4
+
5
+ getPage: async (payload) => {
6
+ let result;
7
+ if (payload.data?.id) {
8
+ result = await commands.execute('getSinglePage', {
9
+ id: payload.data.id
10
+ });
11
+ } else if (payload.data?.email) {
12
+ result = await commands.execute('getSinglePage', {
13
+ email: payload.data.email
14
+ });
15
+ } else {
16
+ throw new Error('No page ID or email provided');
17
+ }
18
+ if (!result) {
19
+ throw new Error('Page not found');
20
+ }
21
+ return { page: result };
22
+ },
23
+
24
+ getManyPages: async (payload) => {
25
+ const results = await commands.execute('getManyPages', {});
26
+ return { pages: results };
27
+ },
28
+
29
+ createPage: async (payload) => {
30
+ const results = await commands.execute('createPages', {
31
+ pages: [payload.data.page]
32
+ });
33
+ return { pages: results };
34
+ },
35
+
36
+ updatePage: async (payload) => {
37
+ const result = await commands.execute('updatePage', {
38
+ id: payload.data.id,
39
+ newPageData: payload.data
40
+ });
41
+ return { page: result };
42
+ },
43
+
44
+ deletePage: async (payload) => {
45
+ await commands.execute('deletePage', {
46
+ id: payload.data.id
47
+ });
48
+ return { message: 'Page deleted' };
49
+ },
50
+
51
+ };
@@ -0,0 +1,89 @@
1
+ import { commands } from '@gnar-engine/core';
2
+ import { authorise } from '../policies/page.policy.js';
3
+
4
+ /**
5
+ * HTTP controller
6
+ */
7
+ export const httpController = {
8
+
9
+ /**
10
+ * Get single page
11
+ */
12
+ getSingle: {
13
+ method: 'GET',
14
+ url: '/pages/:id',
15
+ preHandler: async (request, reply) => authorise.getSingle(request, reply),
16
+ handler: async (request, reply) => {
17
+ const params = {
18
+ id: request.params.id
19
+ };
20
+ const result = await commands.execute('getSinglePage', params);
21
+ reply.code(200).send({ page: result });
22
+ }
23
+ },
24
+
25
+ /**
26
+ * Get multiple pages
27
+ */
28
+ getMany: {
29
+ method: 'GET',
30
+ url: '/pages/',
31
+ preHandler: async (request, reply) => authorise.getMany(request, reply),
32
+ handler: async (request, reply) => {
33
+ const params = {};
34
+ const results = await commands.execute('getManyPages', params);
35
+ reply.code(200).send({ pages: results });
36
+ }
37
+ },
38
+
39
+ /**
40
+ * Create new page
41
+ */
42
+ create: {
43
+ method: 'POST',
44
+ url: '/pages/',
45
+ preHandler: async (request, reply) => authorise.create(request, reply),
46
+ handler: async (request, reply) => {
47
+ const params = {
48
+ pages: [request.body.page],
49
+ requestUser: request.user
50
+ };
51
+ const results = await commands.execute('createPages', params);
52
+ reply.code(200).send({ pages: results });
53
+ },
54
+ },
55
+
56
+ /**
57
+ * Update page
58
+ */
59
+ update: {
60
+ method: 'POST',
61
+ url: '/pages/:id',
62
+ preHandler: async (request, reply) => authorise.update(request, reply),
63
+ handler: async (request, reply) => {
64
+ const params = {
65
+ id: request.params.id,
66
+ newPageData: request.body.page,
67
+ requestUser: request.user
68
+ };
69
+ const result = await commands.execute('updatePage', params);
70
+ reply.code(200).send({ page: result });
71
+ },
72
+ },
73
+
74
+ /**
75
+ * Delete page
76
+ */
77
+ delete: {
78
+ method: 'DELETE',
79
+ url: '/pages/:id',
80
+ preHandler: async (request, reply) => authorise.delete(request, reply),
81
+ handler: async (request, reply) => {
82
+ const params = {
83
+ id: request.params.id
84
+ };
85
+ await commands.execute('deletePage', params);
86
+ reply.code(200).send({ message: 'Page deleted' });
87
+ },
88
+ },
89
+ }
@@ -0,0 +1,50 @@
1
+ import { config } from '../config.js';
2
+
3
+ export const authorise = {
4
+
5
+ /**
6
+ * Authorise get single block
7
+ */
8
+ getSingle: async (request, reply) => {
9
+ if (!request.user || request.user.role !== 'service_admin') {
10
+ reply.code(403).send({error: 'not authorised'});
11
+ }
12
+ },
13
+
14
+ /**
15
+ * Authorise get many blocks
16
+ */
17
+ getMany: async (request, reply) => {
18
+ if (!request.user || request.user.role !== 'service_admin') {
19
+ reply.code(403).send({error: 'not authorised'});
20
+ }
21
+ },
22
+
23
+ /**
24
+ * Authorise create blocks
25
+ */
26
+ create: async (request, reply) => {
27
+ console.log('request user', request.user);
28
+ if (!request.user || request.user.role !== 'service_admin') {
29
+ reply.code(403).send({error: 'not authorised'});
30
+ }
31
+ },
32
+
33
+ /**
34
+ * Authorise update block
35
+ */
36
+ update: async (request, reply) => {
37
+ if (!request.user || request.user.role !== 'service_admin') {
38
+ reply.code(403).send({error: 'not authorised'});
39
+ }
40
+ },
41
+
42
+ /**
43
+ * Authorise delete block
44
+ */
45
+ delete: async (request, reply) => {
46
+ if (!request.user || request.user.role !== 'service_admin') {
47
+ reply.code(403).send({error: 'not authorised'});
48
+ }
49
+ }
50
+ }
@@ -0,0 +1,49 @@
1
+ import { config } from '../config.js';
2
+
3
+ export const authorise = {
4
+
5
+ /**
6
+ * Authorise get single page
7
+ */
8
+ getSingle: async (request, reply) => {
9
+ if (!request.user || request.user.role !== 'service_admin') {
10
+ reply.code(403).send({error: 'not authorised'});
11
+ }
12
+ },
13
+
14
+ /**
15
+ * Authorise get many pages
16
+ */
17
+ getMany: async (request, reply) => {
18
+ if (!request.user || request.user.role !== 'service_admin') {
19
+ reply.code(403).send({error: 'not authorised'});
20
+ }
21
+ },
22
+
23
+ /**
24
+ * Authorise create pages
25
+ */
26
+ create: async (request, reply) => {
27
+ if (!request.user || request.user.role !== 'service_admin') {
28
+ reply.code(403).send({error: 'not authorised'});
29
+ }
30
+ },
31
+
32
+ /**
33
+ * Authorise update page
34
+ */
35
+ update: async (request, reply) => {
36
+ if (!request.user || request.user.role !== 'service_admin') {
37
+ reply.code(403).send({error: 'not authorised'});
38
+ }
39
+ },
40
+
41
+ /**
42
+ * Authorise delete page
43
+ */
44
+ delete: async (request, reply) => {
45
+ if (!request.user || request.user.role !== 'service_admin') {
46
+ reply.code(403).send({error: 'not authorised'});
47
+ }
48
+ }
49
+ }
@@ -0,0 +1,139 @@
1
+ import { schema } from '@gnar-engine/core';
2
+ import { config } from '../config.js';
3
+
4
+ export const pageSchema = {
5
+ schemaName: 'pageService.pageSchema',
6
+ schema: {
7
+ type: 'object',
8
+ properties: {
9
+ name: { type: 'string' },
10
+ key: { type: 'string' },
11
+ blocks: {
12
+ type: 'array',
13
+ items: { $ref: 'pageService.blockSchema' }
14
+ }
15
+ },
16
+ required: ['name', 'key'],
17
+ additionalProperties: false
18
+ }
19
+ };
20
+
21
+ export const blockSchema = {
22
+ $id: 'pageService.blockSchema',
23
+ schemaName: 'pageService.blockSchema',
24
+ schema: {
25
+ type: 'object',
26
+ properties: {
27
+ name: { type: 'string' },
28
+ key: { type: 'string' },
29
+ blocks: {
30
+ type: 'array',
31
+ items: { $ref: 'pageService.blockSchema' }
32
+ },
33
+ fields: {
34
+ type: 'array',
35
+ items: {
36
+ oneOf: [
37
+ { $ref: 'pageService.textInputSchema' },
38
+ { $ref: 'pageService.richTextSchema' },
39
+ { $ref: 'pageService.imageSchema' },
40
+ { $ref: 'pageService.blockSchema' },
41
+ { $ref: 'pageService.repeaterSchema' }
42
+ ]
43
+ }
44
+ },
45
+ type: { type: 'string', enum: ['block'] },
46
+ instanceId: { type: 'string' }
47
+ },
48
+ required: ['name', 'key'],
49
+ additionalProperties: false
50
+ }
51
+ }
52
+
53
+ export const textInputSchema = {
54
+ $id: 'pageService.textInputSchema',
55
+ schemaName: 'pageService.textInputSchema',
56
+ schema: {
57
+ type: 'object',
58
+ properties: {
59
+ key: { type: 'string' },
60
+ name: { type: 'string' },
61
+ type: { type: 'string', enum: ['text'] },
62
+ value: { type: 'string' }
63
+ },
64
+ required: ['key', 'type'],
65
+ additionalProperties: false
66
+ }
67
+ }
68
+
69
+ export const richTextSchema = {
70
+ $id: 'pageService.richTextSchema',
71
+ schemaName: 'pageService.richTextSchema',
72
+ schema: {
73
+ type: 'object',
74
+ properties: {
75
+ key: { type: 'string' },
76
+ name: { type: 'string' },
77
+ type: { type: 'string', enum: ['richtext'] },
78
+ value: { type: 'string' }
79
+ },
80
+ required: ['key', 'type'],
81
+ additionalProperties: false
82
+ }
83
+ }
84
+
85
+ export const imageSchema = {
86
+ $id: 'pageService.imageSchema',
87
+ schemaName: 'pageService.imageSchema',
88
+ schema: {
89
+ type: 'object',
90
+ properties: {
91
+ key: { type: 'string' },
92
+ name: { type: 'string' },
93
+ type: { type: 'string', enum: ['image'] },
94
+ value: {
95
+ type: 'object',
96
+ properties: {
97
+ file: { type: 'string' },
98
+ mimeType: { type: 'string' },
99
+ fileName: { type: 'string' },
100
+ url: { type: 'string' }
101
+ }
102
+ },
103
+ altText: { type: 'string' }
104
+ },
105
+ required: ['key', 'type'],
106
+ additionalProperties: false
107
+ }
108
+ }
109
+
110
+ export const repeaterSchema = {
111
+ $id: 'pageService.repeaterSchema',
112
+ schemaName: 'pageService.repeaterSchema',
113
+ schema: {
114
+ type: 'object',
115
+ properties: {
116
+ key: { type: 'string' },
117
+ name: { type: 'string' },
118
+ type: { type: 'string', enum: ['repeater'] },
119
+ repeaterType: { type: 'string' },
120
+ value: {
121
+ type: 'array',
122
+ items: {
123
+ $ref: 'pageService.blockSchema'
124
+ },
125
+ }
126
+ },
127
+ required: ['key', 'type', 'repeaterType'],
128
+ additionalProperties: false
129
+ }
130
+ }
131
+
132
+ schema.addSchema(blockSchema);
133
+ schema.addSchema(textInputSchema);
134
+ schema.addSchema(richTextSchema);
135
+ schema.addSchema(imageSchema);
136
+ schema.addSchema(repeaterSchema);
137
+
138
+ export const validatePage = schema.compile(pageSchema);
139
+ export const validateBlock = schema.compile(blockSchema);
@@ -0,0 +1,83 @@
1
+ import { db, logger } from '@gnar-engine/core';
2
+ import { ObjectId } from 'mongodb';
3
+
4
+ export const block = {
5
+
6
+ // Get all blocks
7
+ getAll: async () => {
8
+ try {
9
+ const items = await db.collection('blocks').find().toArray();
10
+ return items.map(mappings);
11
+ } catch (error) {
12
+ logger.error("Error fetching blocks:", error);
13
+ throw error;
14
+ }
15
+ },
16
+
17
+ // Create a block
18
+ create: async (data) => {
19
+ try {
20
+ const collection = db.collection('blocks');
21
+ const result = await collection.insertOne(data);
22
+ const insterted = await collection.findOne({ _id: result.insertedId });
23
+ return mappings(insterted);
24
+ } catch (error) {
25
+ logger.error("Error creating block:", error);
26
+ throw error;
27
+ }
28
+ },
29
+
30
+ // Get a block by ID
31
+ getById: async ({ id }) => {
32
+ try {
33
+ const collection = db.collection('blocks');
34
+ const objectId = new ObjectId(id);
35
+ const item = await collection.findOne({ _id: objectId });
36
+ return mappings(item);
37
+ } catch (error) {
38
+ logger.error("Error fetching block:", error);
39
+ throw error;
40
+ }
41
+ },
42
+
43
+ // Update a block
44
+ update: async ({ id, updatedData }) => {
45
+ try {
46
+ const collection = db.collection('blocks');
47
+ const objectId = new ObjectId(id);
48
+ const result = await collection.updateOne(
49
+ { _id: objectId },
50
+ { $set: updatedData }
51
+ );
52
+ return result.modifiedCount > 0;
53
+ } catch (error) {
54
+ logger.error("Error updating block:", error);
55
+ throw error;
56
+ }
57
+ },
58
+
59
+ // Delete a block
60
+ delete: async ({ id }) => {
61
+ try {
62
+ const collection = db.collection('blocks');
63
+ const objectId = new ObjectId(id);
64
+ const result = await collection.deleteOne({ _id: objectId });
65
+ return result.deletedCount > 0;
66
+ } catch (error) {
67
+ logger.error("Error deleting block:", error);
68
+ throw error;
69
+ }
70
+ }
71
+ };
72
+
73
+ const mappings = (item) => {
74
+ if (!item) {
75
+ return item;
76
+ }
77
+
78
+ // _id -> id
79
+ const { _id, ...rest } = item;
80
+ item = { id: _id.toString(), ...rest };
81
+
82
+ return item;
83
+ }
@@ -0,0 +1,83 @@
1
+ import { db, logger } from '@gnar-engine/core';
2
+ import { ObjectId } from 'mongodb';
3
+
4
+ export const page = {
5
+
6
+ // Get all pages
7
+ getAll: async () => {
8
+ try {
9
+ const items = await db.collection('pages').find().toArray();
10
+ return items.map(mappings);
11
+ } catch (error) {
12
+ logger.error("Error fetching pages:", error);
13
+ throw error;
14
+ }
15
+ },
16
+
17
+ // Create a page
18
+ create: async (data) => {
19
+ try {
20
+ const collection = db.collection('pages');
21
+ const result = await collection.insertOne(data);
22
+ const insterted = await collection.findOne({ _id: result.insertedId });
23
+ return mappings(insterted);
24
+ } catch (error) {
25
+ logger.error("Error creating page:", error);
26
+ throw error;
27
+ }
28
+ },
29
+
30
+ // Get a page by ID
31
+ getById: async ({ id }) => {
32
+ try {
33
+ const collection = db.collection('pages');
34
+ const objectId = new ObjectId(id);
35
+ const item = await collection.findOne({ _id: objectId });
36
+ return mappings(item);
37
+ } catch (error) {
38
+ logger.error("Error fetching page:", error);
39
+ throw error;
40
+ }
41
+ },
42
+
43
+ // Update a page
44
+ update: async ({ id, updatedData }) => {
45
+ try {
46
+ const collection = db.collection('pages');
47
+ const objectId = new ObjectId(id);
48
+ const result = await collection.updateOne(
49
+ { _id: objectId },
50
+ { $set: updatedData }
51
+ );
52
+ return result.modifiedCount > 0;
53
+ } catch (error) {
54
+ logger.error("Error updating page:", error);
55
+ throw error;
56
+ }
57
+ },
58
+
59
+ // Delete a page
60
+ delete: async ({ id }) => {
61
+ try {
62
+ const collection = db.collection('pages');
63
+ const objectId = new ObjectId(id);
64
+ const result = await collection.deleteOne({ _id: objectId });
65
+ return result.deletedCount > 0;
66
+ } catch (error) {
67
+ logger.error("Error deleting page:", error);
68
+ throw error;
69
+ }
70
+ }
71
+ };
72
+
73
+ const mappings = (item) => {
74
+ if (!item) {
75
+ return item;
76
+ }
77
+
78
+ // _id -> id
79
+ const { _id, ...rest } = item;
80
+ item = { id: _id.toString(), ...rest };
81
+
82
+ return item;
83
+ }
@@ -1,23 +1,20 @@
1
- # Dockerfile for Portal Service
1
+ # Dockerfile for Control Service
2
2
  FROM node:20-alpine
3
3
 
4
4
  # Set the working directory
5
5
  WORKDIR /usr/gnar_engine/app
6
6
 
7
- # Copy package.json and package-lock.json
8
- COPY ./services/portal/package*.json ./
9
-
10
- # Copy public directory
11
- COPY ./services/portal/public ./public
7
+ # Define a global env var
8
+ ENV GLOBAL_SERVICE_BASE_DIR=/usr/gnar_engine/app/src/
12
9
 
13
- # Copy local Lib packages
14
- COPY ./Lib ./Lib
10
+ # Copy package.json and package-lock.json
11
+ COPY ./services/portal/ ./
15
12
 
16
13
  # Install app dependencies
17
14
  RUN npm install
18
15
 
19
16
  # Expose the port the service will run on
20
- EXPOSE 3000
17
+ EXPOSE 5173
21
18
 
22
19
  # Start the application
23
- CMD ["npm", "run", "start"]
20
+ CMD ["npm", "run", "start:dev"]
@@ -1,22 +1,73 @@
1
- # School Consultancy Programme - Front End
1
+ # React + TypeScript + Vite
2
2
 
3
- React application for student tracking.
3
+ This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
4
4
 
5
- ### Deploy
5
+ Currently, two official plugins are available:
6
6
 
7
- Build application locally and deploy with scp. Production server SSH access required.
7
+ - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) (or [oxc](https://oxc.rs) when used in [rolldown-vite](https://vite.dev/guide/rolldown)) for Fast Refresh
8
+ - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
8
9
 
9
- ``` bash
10
- # Checkout local production branch
11
- git branch checkout production
10
+ ## React Compiler
12
11
 
13
- # Build
14
- npm run build-style
15
- npm run build
12
+ The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation).
16
13
 
17
- # Deploy
18
- npm run deploy
14
+ ## Expanding the ESLint configuration
19
15
 
20
- # Clear production caches
21
-
22
- ```
16
+ If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:
17
+
18
+ ```js
19
+ export default defineConfig([
20
+ globalIgnores(['dist']),
21
+ {
22
+ files: ['**/*.{ts,tsx}'],
23
+ extends: [
24
+ // Other configs...
25
+
26
+ // Remove tseslint.configs.recommended and replace with this
27
+ tseslint.configs.recommendedTypeChecked,
28
+ // Alternatively, use this for stricter rules
29
+ tseslint.configs.strictTypeChecked,
30
+ // Optionally, add this for stylistic rules
31
+ tseslint.configs.stylisticTypeChecked,
32
+
33
+ // Other configs...
34
+ ],
35
+ languageOptions: {
36
+ parserOptions: {
37
+ project: ['./tsconfig.node.json', './tsconfig.app.json'],
38
+ tsconfigRootDir: import.meta.dirname,
39
+ },
40
+ // other options...
41
+ },
42
+ },
43
+ ])
44
+ ```
45
+
46
+ You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:
47
+
48
+ ```js
49
+ // eslint.config.js
50
+ import reactX from 'eslint-plugin-react-x'
51
+ import reactDom from 'eslint-plugin-react-dom'
52
+
53
+ export default defineConfig([
54
+ globalIgnores(['dist']),
55
+ {
56
+ files: ['**/*.{ts,tsx}'],
57
+ extends: [
58
+ // Other configs...
59
+ // Enable lint rules for React
60
+ reactX.configs['recommended-typescript'],
61
+ // Enable lint rules for React DOM
62
+ reactDom.configs.recommended,
63
+ ],
64
+ languageOptions: {
65
+ parserOptions: {
66
+ project: ['./tsconfig.node.json', './tsconfig.app.json'],
67
+ tsconfigRootDir: import.meta.dirname,
68
+ },
69
+ // other options...
70
+ },
71
+ },
72
+ ])
73
+ ```
@@ -0,0 +1,13 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>portal</title>
8
+ </head>
9
+ <body>
10
+ <div id="root"></div>
11
+ <script type="module" src="/src/main.jsx"></script>
12
+ </body>
13
+ </html>