adminforth 1.3.54-next.9 → 1.3.55-next.2

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 (224) hide show
  1. package/dist/auth.d.ts +31 -0
  2. package/dist/auth.d.ts.map +1 -0
  3. package/dist/auth.js +42 -56
  4. package/dist/auth.js.map +1 -0
  5. package/dist/basePlugin.d.ts +18 -0
  6. package/dist/basePlugin.d.ts.map +1 -0
  7. package/dist/basePlugin.js +1 -0
  8. package/dist/basePlugin.js.map +1 -0
  9. package/dist/dataConnectors/baseConnector.d.ts +94 -0
  10. package/dist/dataConnectors/baseConnector.d.ts.map +1 -0
  11. package/dist/dataConnectors/baseConnector.js +108 -122
  12. package/dist/dataConnectors/baseConnector.js.map +1 -0
  13. package/dist/dataConnectors/clickhouse.d.ts +92 -0
  14. package/dist/dataConnectors/clickhouse.d.ts.map +1 -0
  15. package/dist/dataConnectors/clickhouse.js +132 -149
  16. package/dist/dataConnectors/clickhouse.js.map +1 -0
  17. package/dist/dataConnectors/mongo.d.ts +93 -0
  18. package/dist/dataConnectors/mongo.d.ts.map +1 -0
  19. package/dist/dataConnectors/mongo.js +75 -101
  20. package/dist/dataConnectors/mongo.js.map +1 -0
  21. package/dist/dataConnectors/postgres.d.ts +71 -0
  22. package/dist/dataConnectors/postgres.d.ts.map +1 -0
  23. package/dist/dataConnectors/postgres.js +124 -143
  24. package/dist/dataConnectors/postgres.js.map +1 -0
  25. package/dist/dataConnectors/sqlite.d.ts +67 -0
  26. package/dist/dataConnectors/sqlite.d.ts.map +1 -0
  27. package/dist/dataConnectors/sqlite.js +113 -130
  28. package/dist/dataConnectors/sqlite.js.map +1 -0
  29. package/dist/index.d.ts +92 -0
  30. package/dist/index.d.ts.map +1 -0
  31. package/dist/index.js +197 -217
  32. package/dist/index.js.map +1 -0
  33. package/dist/modules/codeInjector.d.ts +35 -0
  34. package/dist/modules/codeInjector.d.ts.map +1 -0
  35. package/dist/modules/codeInjector.js +480 -486
  36. package/dist/modules/codeInjector.js.map +1 -0
  37. package/dist/modules/configValidator.d.ts +12 -0
  38. package/dist/modules/configValidator.d.ts.map +1 -0
  39. package/dist/modules/configValidator.js +31 -22
  40. package/dist/modules/configValidator.js.map +1 -0
  41. package/dist/modules/operationalResource.d.ts +17 -0
  42. package/dist/modules/operationalResource.d.ts.map +1 -0
  43. package/dist/modules/operationalResource.js +50 -70
  44. package/dist/modules/operationalResource.js.map +1 -0
  45. package/dist/modules/restApi.d.ts +10 -0
  46. package/dist/modules/restApi.d.ts.map +1 -0
  47. package/dist/modules/restApi.js +104 -116
  48. package/dist/modules/restApi.js.map +1 -0
  49. package/dist/modules/styleGenerator.d.ts +9 -0
  50. package/dist/modules/styleGenerator.d.ts.map +1 -0
  51. package/dist/modules/styleGenerator.js +1 -0
  52. package/dist/modules/styleGenerator.js.map +1 -0
  53. package/dist/modules/styles.d.ts +96 -0
  54. package/dist/modules/styles.d.ts.map +1 -0
  55. package/dist/modules/styles.js +1 -0
  56. package/dist/modules/styles.js.map +1 -0
  57. package/dist/modules/utils.d.ts +39 -0
  58. package/dist/modules/utils.d.ts.map +1 -0
  59. package/dist/modules/utils.js +1 -0
  60. package/dist/modules/utils.js.map +1 -0
  61. package/dist/plugins/audit-log/types.d.ts +35 -0
  62. package/dist/plugins/audit-log/types.d.ts.map +1 -0
  63. package/dist/plugins/audit-log/types.js +2 -0
  64. package/dist/plugins/audit-log/types.js.map +1 -0
  65. package/dist/plugins/chat-gpt/types.d.ts +82 -0
  66. package/dist/plugins/chat-gpt/types.d.ts.map +1 -0
  67. package/dist/plugins/chat-gpt/types.js +2 -0
  68. package/dist/plugins/chat-gpt/types.js.map +1 -0
  69. package/dist/plugins/email-password-reset/types.d.ts +28 -0
  70. package/dist/plugins/email-password-reset/types.d.ts.map +1 -0
  71. package/dist/plugins/email-password-reset/types.js +2 -0
  72. package/dist/plugins/email-password-reset/types.js.map +1 -0
  73. package/dist/plugins/foreign-inline-list/types.d.ts +19 -0
  74. package/dist/plugins/foreign-inline-list/types.d.ts.map +1 -0
  75. package/dist/plugins/foreign-inline-list/types.js +2 -0
  76. package/dist/plugins/foreign-inline-list/types.js.map +1 -0
  77. package/dist/plugins/import-export/types.d.ts +3 -0
  78. package/dist/plugins/import-export/types.d.ts.map +1 -0
  79. package/dist/plugins/import-export/types.js +2 -0
  80. package/dist/plugins/import-export/types.js.map +1 -0
  81. package/dist/plugins/rich-editor/custom/async-queue.d.ts +8 -0
  82. package/dist/plugins/rich-editor/custom/async-queue.d.ts.map +1 -0
  83. package/dist/plugins/rich-editor/custom/async-queue.js +29 -0
  84. package/dist/plugins/rich-editor/custom/async-queue.js.map +1 -0
  85. package/dist/plugins/rich-editor/dist/custom/async-queue.d.ts +8 -0
  86. package/dist/plugins/rich-editor/dist/custom/async-queue.d.ts.map +1 -0
  87. package/dist/plugins/rich-editor/dist/custom/async-queue.js +29 -0
  88. package/dist/plugins/rich-editor/dist/custom/async-queue.js.map +1 -0
  89. package/dist/plugins/rich-editor/types.d.ts +153 -0
  90. package/dist/plugins/rich-editor/types.d.ts.map +1 -0
  91. package/dist/plugins/rich-editor/types.js +16 -0
  92. package/dist/plugins/rich-editor/types.js.map +1 -0
  93. package/dist/plugins/two-factors-auth/types.d.ts +18 -0
  94. package/dist/plugins/two-factors-auth/types.d.ts.map +1 -0
  95. package/dist/plugins/two-factors-auth/types.js +2 -0
  96. package/dist/plugins/two-factors-auth/types.js.map +1 -0
  97. package/dist/plugins/upload/types.d.ts +132 -0
  98. package/dist/plugins/upload/types.d.ts.map +1 -0
  99. package/dist/plugins/upload/types.js +2 -0
  100. package/dist/plugins/upload/types.js.map +1 -0
  101. package/dist/servers/express.d.ts +18 -0
  102. package/dist/servers/express.d.ts.map +1 -0
  103. package/dist/servers/express.js +30 -42
  104. package/dist/servers/express.js.map +1 -0
  105. package/dist/spa/index.html +2 -2
  106. package/dist/spa/package-lock.json +87 -1
  107. package/dist/spa/package.json +4 -1
  108. package/dist/spa/src/App.vue +154 -50
  109. package/dist/spa/src/components/AcceptModal.vue +1 -1
  110. package/dist/spa/src/components/Breadcrumbs.vue +1 -1
  111. package/dist/spa/src/components/CustomDatePicker.vue +1 -1
  112. package/dist/spa/src/components/CustomDateRangePicker.vue +1 -1
  113. package/dist/spa/src/components/CustomRangePicker.vue +9 -5
  114. package/dist/spa/src/components/Dropdown.vue +4 -4
  115. package/dist/spa/src/components/Filters.vue +2 -2
  116. package/dist/spa/src/components/MenuLink.vue +3 -0
  117. package/dist/spa/src/components/ResourceForm.vue +67 -36
  118. package/dist/spa/src/components/ResourceListTable.vue +216 -144
  119. package/dist/spa/src/components/SkeleteLoader.vue +4 -4
  120. package/dist/spa/src/components/Toast.vue +3 -2
  121. package/dist/spa/src/components/ValueRenderer.vue +81 -6
  122. package/dist/spa/src/composables/useFrontendApi.ts +1 -1
  123. package/dist/spa/src/composables/useStores.ts +18 -14
  124. package/dist/spa/src/index.scss +4 -0
  125. package/{spa → dist/spa}/src/renderers/CompactUUID.vue +4 -4
  126. package/{spa → dist/spa}/src/renderers/CountryFlag.vue +2 -2
  127. package/dist/spa/src/router/index.ts +4 -8
  128. package/dist/spa/src/spa_types/core.ts +2 -0
  129. package/dist/spa/src/stores/core.ts +6 -2
  130. package/dist/spa/src/stores/filters.ts +15 -10
  131. package/dist/spa/src/stores/toast.ts +22 -6
  132. package/dist/spa/src/types/AdminForthConfig.ts +340 -55
  133. package/dist/spa/src/types/FrontendAPI.ts +52 -30
  134. package/dist/spa/src/utils.ts +59 -2
  135. package/dist/spa/src/views/CreateView.vue +15 -4
  136. package/dist/spa/src/views/EditView.vue +20 -7
  137. package/dist/spa/src/views/ListView.vue +132 -38
  138. package/dist/spa/src/views/LoginView.vue +50 -18
  139. package/dist/spa/src/views/ShowView.vue +25 -15
  140. package/dist/types/AdminForthConfig.d.ts +1619 -0
  141. package/dist/types/AdminForthConfig.d.ts.map +1 -0
  142. package/dist/types/AdminForthConfig.js +1 -0
  143. package/dist/types/AdminForthConfig.js.map +1 -0
  144. package/{types/FrontendAPI.ts → dist/types/FrontendAPI.d.ts} +27 -52
  145. package/dist/types/FrontendAPI.d.ts.map +1 -0
  146. package/dist/types/FrontendAPI.js +1 -0
  147. package/dist/types/FrontendAPI.js.map +1 -0
  148. package/package.json +16 -6
  149. package/auth.ts +0 -140
  150. package/basePlugin.ts +0 -70
  151. package/dataConnectors/baseConnector.ts +0 -216
  152. package/dataConnectors/clickhouse.ts +0 -338
  153. package/dataConnectors/mongo.ts +0 -202
  154. package/dataConnectors/postgres.ts +0 -306
  155. package/dataConnectors/sqlite.ts +0 -254
  156. package/index.ts +0 -428
  157. package/modules/codeInjector.ts +0 -736
  158. package/modules/configValidator.ts +0 -571
  159. package/modules/operationalResource.ts +0 -98
  160. package/modules/restApi.ts +0 -718
  161. package/modules/styleGenerator.ts +0 -55
  162. package/modules/styles.ts +0 -126
  163. package/modules/utils.ts +0 -472
  164. package/servers/express.ts +0 -259
  165. package/spa/.eslintrc.cjs +0 -14
  166. package/spa/README.md +0 -39
  167. package/spa/env.d.ts +0 -1
  168. package/spa/index.html +0 -23
  169. package/spa/package-lock.json +0 -4602
  170. package/spa/package.json +0 -51
  171. package/spa/postcss.config.js +0 -6
  172. package/spa/public/assets/favicon.png +0 -0
  173. package/spa/src/App.vue +0 -418
  174. package/spa/src/assets/base.css +0 -2
  175. package/spa/src/assets/logo.svg +0 -19
  176. package/spa/src/components/AcceptModal.vue +0 -45
  177. package/spa/src/components/Breadcrumbs.vue +0 -41
  178. package/spa/src/components/BreadcrumbsWithButtons.vue +0 -26
  179. package/spa/src/components/CustomDatePicker.vue +0 -176
  180. package/spa/src/components/CustomDateRangePicker.vue +0 -218
  181. package/spa/src/components/CustomRangePicker.vue +0 -156
  182. package/spa/src/components/Dropdown.vue +0 -168
  183. package/spa/src/components/Filters.vue +0 -222
  184. package/spa/src/components/HelloWorld.vue +0 -17
  185. package/spa/src/components/MenuLink.vue +0 -27
  186. package/spa/src/components/ResourceForm.vue +0 -290
  187. package/spa/src/components/ResourceListTable.vue +0 -466
  188. package/spa/src/components/SingleSkeletLoader.vue +0 -13
  189. package/spa/src/components/SkeleteLoader.vue +0 -23
  190. package/spa/src/components/Toast.vue +0 -78
  191. package/spa/src/components/ValueRenderer.vue +0 -114
  192. package/spa/src/components/icons/IconCalendar.vue +0 -5
  193. package/spa/src/components/icons/IconCommunity.vue +0 -7
  194. package/spa/src/components/icons/IconDocumentation.vue +0 -7
  195. package/spa/src/components/icons/IconEcosystem.vue +0 -7
  196. package/spa/src/components/icons/IconSupport.vue +0 -7
  197. package/spa/src/components/icons/IconTime.vue +0 -5
  198. package/spa/src/components/icons/IconTooling.vue +0 -19
  199. package/spa/src/composables/useFrontendApi.ts +0 -26
  200. package/spa/src/composables/useStores.ts +0 -131
  201. package/spa/src/index.scss +0 -31
  202. package/spa/src/main.ts +0 -18
  203. package/spa/src/router/index.ts +0 -59
  204. package/spa/src/spa_types/core.ts +0 -53
  205. package/spa/src/stores/core.ts +0 -148
  206. package/spa/src/stores/filters.ts +0 -27
  207. package/spa/src/stores/modal.ts +0 -48
  208. package/spa/src/stores/toast.ts +0 -31
  209. package/spa/src/stores/user.ts +0 -72
  210. package/spa/src/utils.ts +0 -160
  211. package/spa/src/views/CreateView.vue +0 -167
  212. package/spa/src/views/EditView.vue +0 -170
  213. package/spa/src/views/ListView.vue +0 -352
  214. package/spa/src/views/LoginView.vue +0 -192
  215. package/spa/src/views/ResourceParent.vue +0 -17
  216. package/spa/src/views/ShowView.vue +0 -186
  217. package/spa/tailwind.config.js +0 -17
  218. package/spa/tsconfig.app.json +0 -14
  219. package/spa/tsconfig.json +0 -11
  220. package/spa/tsconfig.node.json +0 -19
  221. package/spa/vite.config.ts +0 -56
  222. package/tsconfig.json +0 -112
  223. package/types/AdminForthConfig.ts +0 -1762
  224. /package/{spa → dist/spa}/src/components/ThreeDotsMenu.vue +0 -0
@@ -1,11 +1,15 @@
1
1
  <template>
2
2
  <!-- table -->
3
- <div class="relative overflow-x-auto shadow-listTableShadow dark:shadow-darkListTableShadow overflow-y-hidden rounded-default">
4
-
3
+ <div class="relative overflow-x-auto shadow-listTableShadow dark:shadow-darkListTableShadow overflow-y-hidden"
4
+ :class="{'rounded-default': !noRoundings}"
5
+ >
5
6
  <!-- skelet loader -->
6
7
  <div role="status" v-if="!resource || !resource.columns"
7
8
  class="max-w p-4 space-y-4 divide-y divide-gray-200 rounded shadow animate-pulse dark:divide-gray-700 md:p-6 dark:border-gray-700">
8
-
9
+
10
+ <div role="status" class="max-w-sm animate-pulse">
11
+ <div class="h-2 bg-gray-200 rounded-full dark:bg-gray-700 max-w-[360px]"></div>
12
+ </div>
9
13
  </div>
10
14
 
11
15
  <table v-else class="w-full text-sm text-left rtl:text-right text-gray-500 dark:text-gray-400 rounded-default">
@@ -19,11 +23,11 @@
19
23
  </div>
20
24
  </th>
21
25
 
22
- <th v-for="c in columnsListed" scope="col" class="px-6 py-3">
26
+ <th v-for="c in columnsListed" scope="col" class="px-2 md:px-3 lg:px-6 py-3">
23
27
 
24
- <div @click="() => c.sortable && onSortButtonClick(c.name)" class="flex items-center " :class="{'cursor-pointer':c.sortable}">
28
+ <div @click="(evt) => c.sortable && onSortButtonClick(evt, c.name)"
29
+ class="flex items-center " :class="{'cursor-pointer':c.sortable}">
25
30
  {{ c.label }}
26
-
27
31
 
28
32
  <div v-if="c.sortable"
29
33
  :style="{ 'color':ascArr.includes(c.name)?'green':descArr.includes(c.name)?'red':'currentColor'}">
@@ -54,122 +58,142 @@
54
58
  </tr>
55
59
  </thead>
56
60
  <tbody>
57
- <SkeleteLoader v-if="!rows" :columns="3" :rows="resource?.columns.length + 2"/>
58
- <tr v-else-if="rows.length === 0" class="bg-lightListTable dark:bg-darkListTable dark:border-darkListTableBorder">
59
- <td :colspan="resource?.columns.length + 2">
60
-
61
- <div id="toast-simple"
62
- class=" mx-auto my-5 flex items-center w-full max-w-xs p-4 space-x-4 rtl:space-x-reverse text-gray-500 divide-x rtl:divide-x-reverse divide-gray-200 dark:text-gray-400 dark:divide-gray-700 space-x dark:bg-gray-800"
63
- role="alert">
64
- <IconInboxOutline class="w-6 h-6 text-gray-500 dark:text-gray-400"/>
65
- <div class="ps-4 text-sm font-normal">No items here yet</div>
66
- </div>
67
-
68
- </td>
69
- </tr>
70
-
71
- <tr @click="onClick($event,row)" v-else v-for="(row, rowI) in rows" :key="row.id"
72
- class="bg-lightListTable dark:bg-darkListTable border-lightListBorder dark:border-gray-700 hover:bg-lightListTableRowHover dark:hover:bg-darkListTableRowHover cursor-pointer"
73
- :class="{'border-b': rowI !== rows.length - 1}"
74
- >
75
- <td class="w-4 p-4 cursor-default" @click="(e)=>{e.stopPropagation()}">
76
- <div class="flex items center ">
77
- <input
78
- @click="(e)=>{e.stopPropagation()}"
79
- id="checkbox-table-search-1"
80
- type="checkbox"
81
- :checked="checkboxesInternal.includes(row.id)"
82
- @change="(e)=>{addToCheckedValues(row.id)}"
83
- class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 dark:focus:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600 cursor-pointer">
84
- <label for="checkbox-table-search-1" class="sr-only">checkbox</label>
85
- </div>
86
- </td>
87
- <td v-for="c in columnsListed" class="px-6 py-4">
88
- <!-- if c.name in listComponentsPerColumn, render it. If not, render ValueRenderer -->
89
- <component
90
- :is="c?.components?.list ? getCustomComponent(c.components.list) : ValueRenderer"
91
- :meta="c?.components?.list?.meta"
92
- :column="c"
93
- :record="row"
94
- :adminUser="coreStore.adminUser"
95
- :resource="resource"
96
- />
97
- </td>
98
- <td class=" items-center px-6 py-4 cursor-default" @click="(e)=>{e.stopPropagation()}">
99
- <div class="flex">
100
- <RouterLink
101
- v-if="resource.options?.allowedActions.show"
102
- :to="{
103
- name: 'resource-show',
104
- params: {
105
- resourceId: resource.resourceId,
106
- primaryKey: row._primaryKeyValue,
107
- }
108
- }"
109
- class="font-medium text-blue-600 dark:text-blue-500 hover:underline"
110
- :data-tooltip-target="`tooltip-show-${rowI}`"
111
- >
112
- <IconEyeSolid class="w-5 h-5 me-2"/>
113
- </RouterLink>
114
-
115
- <div :id="`tooltip-show-${rowI}`"
116
- role="tooltip"
117
- class="absolute z-10 invisible inline-block px-3 py-2 text-sm font-medium text-white transition-opacity duration-300 bg-gray-900 rounded-lg shadow-sm opacity-0 tooltip dark:bg-gray-700">
118
- Show item
119
- <div class="tooltip-arrow" data-popper-arrow></div>
120
- </div>
121
-
122
- <RouterLink v-if="resource.options?.allowedActions.edit"
123
- :to="{
124
- name: 'resource-edit',
125
- params: {
126
- resourceId: resource.resourceId,
127
- primaryKey: row._primaryKeyValue
128
- }
129
- }"
130
- class="font-medium text-blue-600 dark:text-blue-500 hover:underline ms-3"
131
- :data-tooltip-target="`tooltip-edit-${rowI}`"
132
- >
133
- <IconPenSolid class="w-5 h-5 me-2"/>
134
- </RouterLink>
135
-
136
- <div :id="`tooltip-edit-${rowI}`"
137
- role="tooltip"
138
- class="absolute z-10 invisible inline-block px-3 py-2 text-sm font-medium text-white transition-opacity duration-300 bg-gray-900 rounded-lg shadow-sm opacity-0 tooltip dark:bg-gray-700">
139
- Edit
140
- <div class="tooltip-arrow" data-popper-arrow></div>
141
- </div>
61
+ <SkeleteLoader
62
+ v-if="!rows"
63
+ :columns="resource?.columns.filter(c => c.showIn.includes('list')).length + 2"
64
+ :rows="3"
65
+ />
66
+ <tr v-else-if="rows.length === 0" class="bg-lightListTable dark:bg-darkListTable dark:border-darkListTableBorder">
67
+ <td :colspan="resource?.columns.length + 2">
68
+
69
+ <div id="toast-simple"
70
+ class=" mx-auto my-5 flex items-center w-full max-w-xs p-4 space-x-4 rtl:space-x-reverse text-gray-500 divide-x rtl:divide-x-reverse divide-gray-200 dark:text-gray-400 dark:divide-gray-700 space-x dark:bg-gray-800"
71
+ role="alert">
72
+ <IconInboxOutline class="w-6 h-6 text-gray-500 dark:text-gray-400"/>
73
+ <div class="ps-4 text-sm font-normal">No items here yet</div>
74
+ </div>
142
75
 
143
- <button v-if="resource.options?.allowedActions.delete"
144
- class="font-medium text-red-600 dark:text-red-500 hover:underline ms-3"
145
- :data-tooltip-target="`tooltip-delete-${rowI}`"
146
- @click="deleteRecord(row)"
147
- >
148
- <IconTrashBinSolid class="w-5 h-5 me-2"/>
149
- </button>
150
-
151
- <div :id="`tooltip-delete-${rowI}`"
152
- role="tooltip"
153
- class="absolute z-10 invisible inline-block px-3 py-2 text-sm font-medium text-white transition-opacity duration-300 bg-gray-900 rounded-lg shadow-sm opacity-0 tooltip dark:bg-gray-700">
154
- Delete
155
- <div class="tooltip-arrow" data-popper-arrow></div>
156
- </div>
157
- </div>
158
- </td>
159
- </tr>
76
+ </td>
77
+ </tr>
78
+
79
+ <tr @click="onClick($event,row)"
80
+ v-else v-for="(row, rowI) in rows" :key="`row_${row._primaryKeyValue}`"
81
+ class="bg-lightListTable dark:bg-darkListTable border-lightListBorder dark:border-gray-700 hover:bg-lightListTableRowHover dark:hover:bg-darkListTableRowHover"
82
+
83
+ :class="{'border-b': rowI !== rows.length - 1, 'cursor-pointer': row._clickUrl !== null}"
84
+ >
85
+ <td class="w-4 p-4 cursor-default" @click="(e)=>{e.stopPropagation()}">
86
+ <div class="flex items center ">
87
+ <input
88
+ @click="(e)=>{e.stopPropagation()}"
89
+ id="checkbox-table-search-1"
90
+ type="checkbox"
91
+ :checked="checkboxesInternal.includes(row._primaryKeyValue)"
92
+ @change="(e)=>{addToCheckedValues(row._primaryKeyValue)}"
93
+ class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 dark:focus:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600 cursor-pointer">
94
+ <label for="checkbox-table-search-1" class="sr-only">checkbox</label>
95
+ </div>
96
+ </td>
97
+ <td v-for="c in columnsListed" class="px-2 md:px-3 lg:px-6 py-4">
98
+ <!-- if c.name in listComponentsPerColumn, render it. If not, render ValueRenderer -->
99
+ <component
100
+ :is="c?.components?.list ? getCustomComponent(c.components.list) : ValueRenderer"
101
+ :meta="c?.components?.list?.meta"
102
+ :column="c"
103
+ :record="row"
104
+ :adminUser="coreStore.adminUser"
105
+ :resource="resource"
106
+ />
107
+ </td>
108
+ <td class=" items-center px-2 md:px-3 lg:px-6 py-4 cursor-default" @click="(e)=>{e.stopPropagation()}">
109
+ <div class="flex">
110
+ <RouterLink
111
+ v-if="resource.options?.allowedActions.show"
112
+ :to="{
113
+ name: 'resource-show',
114
+ params: {
115
+ resourceId: resource.resourceId,
116
+ primaryKey: row._primaryKeyValue,
117
+ }
118
+ }"
119
+ class="font-medium text-lightPrimary dark:text-darkPrimary hover:underline"
120
+ :data-tooltip-target="`tooltip-show-${rowI}`"
121
+ >
122
+ <IconEyeSolid class="w-5 h-5 me-2"/>
123
+ </RouterLink>
124
+
125
+ <div :id="`tooltip-show-${rowI}`"
126
+ role="tooltip"
127
+ class="absolute z-10 invisible inline-block px-3 py-2 text-sm font-medium text-white transition-opacity duration-300 bg-gray-900 rounded-lg shadow-sm opacity-0 tooltip dark:bg-gray-700">
128
+ Show item
129
+ <div class="tooltip-arrow" data-popper-arrow></div>
130
+ </div>
131
+
132
+ <RouterLink v-if="resource.options?.allowedActions.edit"
133
+ :to="{
134
+ name: 'resource-edit',
135
+ params: {
136
+ resourceId: resource.resourceId,
137
+ primaryKey: row._primaryKeyValue
138
+ }
139
+ }"
140
+ class="font-medium text-lightPrimary dark:text-darkPrimary hover:underline ms-3"
141
+ :data-tooltip-target="`tooltip-edit-${rowI}`"
142
+ >
143
+ <IconPenSolid class="w-5 h-5 me-2"/>
144
+ </RouterLink>
145
+
146
+ <div :id="`tooltip-edit-${rowI}`"
147
+ role="tooltip"
148
+ class="absolute z-10 invisible inline-block px-3 py-2 text-sm font-medium text-white transition-opacity duration-300 bg-gray-900 rounded-lg shadow-sm opacity-0 tooltip dark:bg-gray-700">
149
+ Edit
150
+ <div class="tooltip-arrow" data-popper-arrow></div>
151
+ </div>
152
+
153
+ <button v-if="resource.options?.allowedActions.delete"
154
+ class="font-medium text-lightPrimary dark:text-darkPrimary hover:underline ms-3"
155
+ :data-tooltip-target="`tooltip-delete-${rowI}`"
156
+ @click="deleteRecord(row)"
157
+ >
158
+ <IconTrashBinSolid class="w-5 h-5 me-2"/>
159
+ </button>
160
+
161
+ <div :id="`tooltip-delete-${rowI}`"
162
+ role="tooltip"
163
+ class="absolute z-10 invisible inline-block px-3 py-2 text-sm font-medium text-white transition-opacity duration-300 bg-gray-900 rounded-lg shadow-sm opacity-0 tooltip dark:bg-gray-700">
164
+ Delete
165
+ <div class="tooltip-arrow" data-popper-arrow></div>
166
+ </div>
167
+
168
+
169
+ <template v-if="coreStore.resourceOptions?.pageInjections?.list?.customActionIcons">
170
+ <component
171
+ v-for="c in coreStore.resourceOptions?.pageInjections?.list?.customActionIcons"
172
+ :is="getCustomComponent(c)"
173
+ :meta="c.meta"
174
+ :resource="coreStore.resource"
175
+ :adminUser="coreStore.adminUser"
176
+ :record="row"
177
+ />
178
+ </template>
179
+ </div>
180
+ </td>
181
+ </tr>
160
182
  </tbody>
161
183
  </table>
162
184
  </div>
163
- <!-- pagination -->
185
+ <!-- pagination
186
+ totalRows in v-if is used to not hide page input during loading when user puts cursor into it and edit directly (rows gets null there during edit)
187
+ -->
164
188
  <div class="flex flex-col items-center mt-4 mb-4 xs:flex-row xs:justify-between xs:items-center"
165
- v-if="rows && totalRows >= pageSize && totalRows > 0"
189
+ v-if="(rows || totalRows) && totalRows >= pageSize && totalRows > 0"
166
190
  >
167
191
  <!-- Help text -->
168
192
  <span class="text-sm text-gray-700 dark:text-gray-400">
169
193
  Showing <span class="font-semibold text-gray-900 dark:text-white">
170
- {{ (page - 1) * pageSize + 1 }}
194
+ {{ ((page || 1) - 1) * pageSize + 1 }}
171
195
  </span> to <span class="font-semibold text-gray-900 dark:text-white">
172
- {{ Math.min(page * pageSize, totalRows) }}
196
+ {{ Math.min((page || 1) * pageSize, totalRows) }}
173
197
  </span> of <span class="font-semibold text-gray-900 dark:text-white">{{
174
198
  totalRows
175
199
  }}</span> Entries
@@ -177,7 +201,7 @@
177
201
  <div class="inline-flex mt-2 xs:mt-0">
178
202
  <!-- Buttons -->
179
203
  <button
180
- class="flex items-center py-1 px-3 text-sm font-medium text-gray-900 focus:outline-none bg-white border-r-0 rounded-s border border-gray-300 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700 disabled:opacity-50"
204
+ class="flex items-center py-1 px-3 text-sm font-medium text-gray-900 focus:outline-none bg-white border-r-0 rounded-s border border-gray-300 hover:bg-gray-100 hover:text-lightPrimary focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700 disabled:opacity-50"
181
205
  @click="page--" :disabled="page <= 1">
182
206
  <svg class="w-3.5 h-3.5 me-2 rtl:rotate-180" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none"
183
207
  viewBox="0 0 14 10">
@@ -187,24 +211,28 @@
187
211
  Prev
188
212
  </button>
189
213
  <button
190
- class="flex items-center py-1 px-3 text-sm font-medium text-gray-900 focus:outline-none bg-white border-r-0 border border-gray-300 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700 disabled:opacity-50"
214
+ class="flex items-center py-1 px-3 text-sm font-medium text-gray-900 focus:outline-none bg-white border-r-0 border border-gray-300 hover:bg-gray-100 hover:text-lightPrimary focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700 disabled:opacity-50"
191
215
  @click="page = 1" :disabled="page <= 1">
192
216
  <!-- <IconChevronDoubleLeftOutline class="w-4 h-4" /> -->
193
217
  1
194
218
  </button>
195
- <input type="text"
196
- class="w-10 py-1.5 px-3 text-sm text-center text-gray-700 border border-gray-300 dark:border-gray-700 dark:text-gray-400 dark:bg-gray-800 z-10"
197
- v-model="page"/>
219
+ <div
220
+ contenteditable="true"
221
+ class="min-w-10 outline-none inline-block w-auto min-w-10 py-1.5 px-3 text-sm text-center text-gray-700 border border-gray-300 dark:border-gray-700 dark:text-gray-400 dark:bg-gray-800 z-10"
222
+ @input="page = parseInt($event.target.innerText) || ''"
223
+ >
224
+ {{ page }}
225
+ </div>
198
226
 
199
227
  <button
200
- class="flex items-center py-1 px-3 text-sm font-medium text-gray-900 focus:outline-none bg-white border-l-0 border border-gray-300 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700 disabled:opacity-50"
228
+ class="flex items-center py-1 px-3 text-sm font-medium text-gray-900 focus:outline-none bg-white border-l-0 border border-gray-300 hover:bg-gray-100 hover:text-lightPrimary focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700 disabled:opacity-50"
201
229
  @click="page = totalPages" :disabled="page >= totalPages">
202
230
  {{ totalPages }}
203
231
 
204
232
  <!-- <IconChevronDoubleRightOutline class="w-4 h-4" /> -->
205
233
  </button>
206
234
  <button
207
- class="flex items-center py-1 px-3 text-sm font-medium text-gray-900 focus:outline-none bg-white border-l-0 rounded-e border border-gray-300 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700 disabled:opacity-50"
235
+ class="flex items-center py-1 px-3 text-sm font-medium text-gray-900 focus:outline-none bg-white border-l-0 rounded-e border border-gray-300 hover:bg-gray-100 hover:text-lightPrimary focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700 disabled:opacity-50"
208
236
 
209
237
  @click="page++" :disabled="page >= totalPages">
210
238
  Next
@@ -222,10 +250,8 @@
222
250
  <script setup>
223
251
 
224
252
 
225
- import { initFlowbite } from 'flowbite';
226
253
  import { computed, onMounted, ref, watch } from 'vue';
227
- import { useRoute } from 'vue-router';
228
- import { callAdminForthApi, getIcon } from '@/utils';
254
+ import { callAdminForthApi } from '@/utils';
229
255
 
230
256
  import ValueRenderer from '@/components/ValueRenderer.vue';
231
257
  import { getCustomComponent } from '@/utils';
@@ -234,28 +260,27 @@ import { showSuccesTost, showErrorTost } from '@/composables/useFrontendApi';
234
260
  import SkeleteLoader from '@/components/SkeleteLoader.vue';
235
261
 
236
262
  import {
237
- IconInboxOutline,
238
- IconPlusOutline
263
+ IconInboxOutline,
239
264
  } from '@iconify-prerendered/vue-flowbite';
240
265
 
241
266
  import {
242
- IconBanOutline,
243
- IconEyeSolid,
244
- IconFilterOutline,
245
- IconPenSolid,
246
- IconTrashBinSolid
267
+ IconEyeSolid,
268
+ IconPenSolid,
269
+ IconTrashBinSolid
247
270
  } from '@iconify-prerendered/vue-flowbite';
248
271
  import router from '@/router';
249
272
 
250
273
  const coreStore = useCoreStore();
251
274
 
252
275
  const props = defineProps([
276
+ 'page',
253
277
  'resource',
254
278
  'rows',
255
279
  'totalRows',
256
280
  'pageSize',
257
281
  'checkboxes',
258
- 'sort'
282
+ 'sort',
283
+ 'noRoundings'
259
284
  ])
260
285
 
261
286
  // emits, update page
@@ -272,6 +297,7 @@ const page = ref(1);
272
297
  const sort = ref([]);
273
298
 
274
299
 
300
+
275
301
  watch(() => page.value, (newPage) => {
276
302
  emits('update:page', newPage);
277
303
  });
@@ -295,7 +321,12 @@ watch(() => props.sort, (newSort) => {
295
321
  sort.value = newSort;
296
322
  });
297
323
 
324
+ watch(() => props.page, (newPage) => {
325
+ page.value = newPage;
326
+ });
327
+
298
328
  function addToCheckedValues(id) {
329
+ console.log('checking', checkboxesInternal.value, 'id', id)
299
330
  if (checkboxesInternal.value.includes(id)) {
300
331
  checkboxesInternal.value = checkboxesInternal.value.filter((item) => item !== id);
301
332
  } else {
@@ -309,13 +340,13 @@ const columnsListed = computed(() => props.resource?.columns?.filter(c => c.show
309
340
  async function selectAll(value) {
310
341
  if (!allFromThisPageChecked.value) {
311
342
  props.rows.forEach((r) => {
312
- if (!checkboxesInternal.value.includes(r.id)) {
313
- checkboxesInternal.value.push(r.id)
343
+ if (!checkboxesInternal.value.includes(r._primaryKeyValue)) {
344
+ checkboxesInternal.value.push(r._primaryKeyValue)
314
345
  }
315
346
  });
316
347
  } else {
317
348
  props.rows.forEach((r) => {
318
- checkboxesInternal.value = checkboxesInternal.value.filter((item) => item !== r.id);
349
+ checkboxesInternal.value = checkboxesInternal.value.filter((item) => item !== r._primaryKeyValue);
319
350
  });
320
351
  }
321
352
  checkboxesInternal.value = [ ...checkboxesInternal.value ];
@@ -325,16 +356,24 @@ const totalPages = computed(() => Math.ceil(props.totalRows / props.pageSize));
325
356
 
326
357
  const allFromThisPageChecked = computed(() => {
327
358
  if (!props.rows) return false;
328
- return props.rows.every((r) => checkboxesInternal.value.includes(r.id));
359
+ return props.rows.every((r) => checkboxesInternal.value.includes(r._primaryKeyValue));
329
360
  });
330
361
  const ascArr = computed(() => sort.value.filter((s) => s.direction === 'asc').map((s) => s.field));
331
362
  const descArr = computed(() => sort.value.filter((s) => s.direction === 'desc').map((s) => s.field));
332
363
 
333
364
 
334
- function onSortButtonClick(field) {
365
+ function onSortButtonClick(event, field) {
366
+ // if ctrl key is pressed, add to sort otherwise sort by this field
367
+ // in any case if field is already in sort, toggle direction
368
+
335
369
  const sortIndex = sort.value.findIndex((s) => s.field === field);
336
370
  if (sortIndex === -1) {
337
- sort.value = [...sort.value,{field, direction: 'asc'}];
371
+ // field is not in sort, add it
372
+ if (event.ctrlKey) {
373
+ sort.value = [...sort.value,{field, direction: 'asc'}];
374
+ } else {
375
+ sort.value = [{field, direction: 'asc'}];
376
+ }
338
377
  } else {
339
378
  const sortField = sort.value[sortIndex];
340
379
  if (sortField.direction === 'asc') {
@@ -347,18 +386,51 @@ function onSortButtonClick(field) {
347
386
 
348
387
 
349
388
  const clickTarget = ref(null);
389
+
350
390
  async function onClick(e,row) {
351
391
  if(clickTarget.value === e.target) return;
352
392
  clickTarget.value = e.target;
353
- await new Promise((resolve) => setTimeout(resolve, 300));
393
+ await new Promise((resolve) => setTimeout(resolve, 100));
354
394
  if (window.getSelection().toString()) return;
355
- else {router.push({
356
- name: 'resource-show',
357
- params: {
358
- resourceId: props.resource.resourceId,
359
- primaryKey: row._primaryKeyValue,
360
- },
361
- })}
395
+ else {
396
+ if (row._clickUrl === null) {
397
+ // user asked to nothing on click
398
+ return;
399
+ }
400
+ if (e.ctrlKey || e.metaKey || row._clickUrl?.includes('target=_blank')) {
401
+
402
+ if (row._clickUrl) {
403
+ window.open(row._clickUrl, '_blank');
404
+ } else {
405
+ window.open(
406
+ router.resolve({
407
+ name: 'resource-show',
408
+ params: {
409
+ resourceId: props.resource.resourceId,
410
+ primaryKey: row._primaryKeyValue,
411
+ },
412
+ }).fullPath,
413
+ '_blank'
414
+ );
415
+ }
416
+ } else {
417
+ if (row._clickUrl) {
418
+ if (row._clickUrl.startsWith('http')) {
419
+ document.location.href = row._clickUrl;
420
+ } else {
421
+ router.push(row._clickUrl);
422
+ }
423
+ } else {
424
+ router.push({
425
+ name: 'resource-show',
426
+ params: {
427
+ resourceId: props.resource.resourceId,
428
+ primaryKey: row._primaryKeyValue,
429
+ },
430
+ });
431
+ }
432
+ }
433
+ }
362
434
  }
363
435
 
364
436
  async function deleteRecord(row) {
@@ -1,6 +1,6 @@
1
1
  <template>
2
- <tr v-for="c in new Array(props.columns)" class="bg-lightListTable border-b dark:bg-darkListTable dark:border-darkListBorder">
3
- <td v-for="r in new Array(props.rows)" class="items-center px-6 py-8 cursor-default" >
2
+ <tr v-for="c in new Array(props.rows)" class="bg-lightListTable border-b dark:bg-darkListTable dark:border-darkListBorder">
3
+ <td v-for="r in new Array(props.columns)" class="items-center px-6 py-8 cursor-default" >
4
4
  <div role="status" class="max-w-sm animate-pulse">
5
5
  <div class="h-2 bg-gray-200 rounded-full dark:bg-gray-700 max-w-[360px]"></div>
6
6
  </div>
@@ -11,8 +11,8 @@
11
11
  <script setup>
12
12
 
13
13
  const props = defineProps({
14
- columns:Number,
15
- rows:Number
14
+ columns: Number,
15
+ rows: Number
16
16
  });
17
17
 
18
18
 
@@ -1,14 +1,15 @@
1
1
  <template>
2
2
 
3
3
 
4
- <div id="toast-default" class="flex items-center w-full p-4 text-gray-500 rounded-lg shadow dark:text-gray-400 dark:bg-gray-800" role="alert"
4
+ <div class="flex items-center w-full p-4 text-gray-500 rounded-lg shadow-lg dark:text-gray-400 dark:bg-gray-800 bg-white"
5
+ role="alert"
5
6
  :class="
6
7
  {
7
8
  'danger': 'bg-red-100',
8
9
  }[toast.variant]
9
10
  "
10
11
  >
11
- <div v-if="toast.variant == 'info'" class="inline-flex items-center justify-center flex-shrink-0 w-8 h-8 text-blue-500 bg-blue-100 rounded-lg dark:bg-blue-800 dark:text-blue-200">
12
+ <div v-if="toast.variant == 'info'" class="inline-flex items-center justify-center flex-shrink-0 w-8 h-8 text-lightPrimary dark:text-darkPrimary bg-lightPrimaryOpacity rounded-lg dark:bg-blue-800 dark:text-blue-200">
12
13
  <svg class="w-4 h-4" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 18 20">
13
14
  <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.147 15.085a7.159 7.159 0 0 1-6.189 3.307A6.713 6.713 0 0 1 3.1 15.444c-2.679-4.513.287-8.737.888-9.548A4.373 4.373 0 0 0 5 1.608c1.287.953 6.445 3.218 5.537 10.5 1.5-1.122 2.706-3.01 2.853-6.14 1.433 1.049 3.993 5.395 1.757 9.117Z"/>
14
15
  </svg>