adminforth 1.4.3-next.8 → 1.5.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 (142) hide show
  1. package/dist/basePlugin.d.ts.map +1 -1
  2. package/dist/basePlugin.js +2 -3
  3. package/dist/basePlugin.js.map +1 -1
  4. package/dist/dataConnectors/postgres.d.ts.map +1 -1
  5. package/dist/dataConnectors/postgres.js +29 -9
  6. package/dist/dataConnectors/postgres.js.map +1 -1
  7. package/dist/dataConnectors/sqlite.d.ts.map +1 -1
  8. package/dist/dataConnectors/sqlite.js +12 -5
  9. package/dist/dataConnectors/sqlite.js.map +1 -1
  10. package/dist/index.d.ts +4 -3
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +18 -5
  13. package/dist/index.js.map +1 -1
  14. package/dist/modules/codeInjector.d.ts +4 -2
  15. package/dist/modules/codeInjector.d.ts.map +1 -1
  16. package/dist/modules/codeInjector.js +98 -79
  17. package/dist/modules/codeInjector.js.map +1 -1
  18. package/dist/modules/configValidator.d.ts.map +1 -1
  19. package/dist/modules/configValidator.js +5 -4
  20. package/dist/modules/configValidator.js.map +1 -1
  21. package/dist/modules/operationalResource.d.ts.map +1 -1
  22. package/dist/modules/operationalResource.js.map +1 -1
  23. package/dist/modules/restApi.d.ts +8 -3
  24. package/dist/modules/restApi.d.ts.map +1 -1
  25. package/dist/modules/restApi.js +112 -39
  26. package/dist/modules/restApi.js.map +1 -1
  27. package/dist/modules/socketBroker.d.ts +16 -0
  28. package/dist/modules/socketBroker.d.ts.map +1 -0
  29. package/dist/modules/socketBroker.js +99 -0
  30. package/dist/modules/socketBroker.js.map +1 -0
  31. package/dist/modules/utils.d.ts +2 -1
  32. package/dist/modules/utils.d.ts.map +1 -1
  33. package/dist/modules/utils.js +5 -2
  34. package/dist/modules/utils.js.map +1 -1
  35. package/dist/servers/common.d.ts +21 -0
  36. package/dist/servers/common.d.ts.map +1 -0
  37. package/dist/servers/common.js +13 -0
  38. package/dist/servers/common.js.map +1 -0
  39. package/dist/servers/express.d.ts +5 -0
  40. package/dist/servers/express.d.ts.map +1 -1
  41. package/dist/servers/express.js +54 -7
  42. package/dist/servers/express.js.map +1 -1
  43. package/dist/spa/package-lock.json +59 -0
  44. package/dist/spa/package.json +1 -0
  45. package/dist/spa/src/App.vue +58 -36
  46. package/dist/spa/src/afcl/Button.vue +8 -1
  47. package/dist/spa/src/afcl/Input.vue +41 -0
  48. package/dist/spa/src/afcl/LinkButton.vue +23 -0
  49. package/dist/spa/src/afcl/Select.vue +8 -7
  50. package/dist/spa/src/afcl/index.ts +3 -0
  51. package/dist/spa/src/components/Filters.vue +0 -1
  52. package/dist/spa/src/components/GroupsTable.vue +4 -4
  53. package/dist/spa/src/components/ResourceListTable.vue +21 -21
  54. package/dist/spa/src/components/ValueRenderer.vue +3 -1
  55. package/dist/spa/src/composables/useStores.ts +4 -1
  56. package/dist/spa/src/renderers/CompactField.vue +4 -4
  57. package/dist/spa/src/renderers/CompactUUID.vue +4 -4
  58. package/dist/spa/src/renderers/CountryFlag.vue +3 -3
  59. package/dist/spa/src/renderers/HumanNumber.vue +5 -4
  60. package/dist/spa/src/renderers/RelativeTime.vue +5 -4
  61. package/dist/spa/src/router/index.ts +2 -0
  62. package/dist/spa/src/stores/core.ts +39 -6
  63. package/dist/spa/src/types/Back.ts +102 -9
  64. package/dist/spa/src/types/Common.ts +6 -1
  65. package/dist/spa/src/types/FrontendAPI.ts +7 -0
  66. package/dist/spa/src/views/EditView.vue +1 -0
  67. package/dist/spa/src/views/ListView.vue +2 -2
  68. package/dist/spa/src/views/LoginView.vue +7 -7
  69. package/dist/spa/src/views/PageNotFound.vue +20 -0
  70. package/dist/spa/src/views/ResourceParent.vue +0 -1
  71. package/dist/spa/src/views/ShowView.vue +1 -0
  72. package/dist/spa/src/websocket.ts +84 -0
  73. package/dist/spa/vite.config.ts +16 -34
  74. package/dist/types/Back.d.ts +70 -4
  75. package/dist/types/Back.d.ts.map +1 -1
  76. package/dist/types/Back.js.map +1 -1
  77. package/dist/types/Common.d.ts +4 -0
  78. package/dist/types/Common.d.ts.map +1 -1
  79. package/dist/types/FrontendAPI.d.ts +6 -0
  80. package/dist/types/FrontendAPI.d.ts.map +1 -1
  81. package/dist/types/FrontendAPI.js.map +1 -1
  82. package/package.json +5 -3
  83. package/dist/plugins/audit-log/types.d.ts +0 -35
  84. package/dist/plugins/audit-log/types.d.ts.map +0 -1
  85. package/dist/plugins/audit-log/types.js +0 -2
  86. package/dist/plugins/audit-log/types.js.map +0 -1
  87. package/dist/plugins/chat-gpt/types.d.ts +0 -82
  88. package/dist/plugins/chat-gpt/types.d.ts.map +0 -1
  89. package/dist/plugins/chat-gpt/types.js +0 -2
  90. package/dist/plugins/chat-gpt/types.js.map +0 -1
  91. package/dist/plugins/email-password-reset/types.d.ts +0 -28
  92. package/dist/plugins/email-password-reset/types.d.ts.map +0 -1
  93. package/dist/plugins/email-password-reset/types.js +0 -2
  94. package/dist/plugins/email-password-reset/types.js.map +0 -1
  95. package/dist/plugins/foreign-inline-list/types.d.ts +0 -19
  96. package/dist/plugins/foreign-inline-list/types.d.ts.map +0 -1
  97. package/dist/plugins/foreign-inline-list/types.js +0 -2
  98. package/dist/plugins/foreign-inline-list/types.js.map +0 -1
  99. package/dist/plugins/import-export/types.d.ts +0 -3
  100. package/dist/plugins/import-export/types.d.ts.map +0 -1
  101. package/dist/plugins/import-export/types.js +0 -2
  102. package/dist/plugins/import-export/types.js.map +0 -1
  103. package/dist/plugins/rich-editor/custom/async-queue.d.ts +0 -8
  104. package/dist/plugins/rich-editor/custom/async-queue.d.ts.map +0 -1
  105. package/dist/plugins/rich-editor/custom/async-queue.js +0 -29
  106. package/dist/plugins/rich-editor/custom/async-queue.js.map +0 -1
  107. package/dist/plugins/rich-editor/dist/custom/async-queue.d.ts +0 -8
  108. package/dist/plugins/rich-editor/dist/custom/async-queue.d.ts.map +0 -1
  109. package/dist/plugins/rich-editor/dist/custom/async-queue.js +0 -29
  110. package/dist/plugins/rich-editor/dist/custom/async-queue.js.map +0 -1
  111. package/dist/plugins/rich-editor/types.d.ts +0 -153
  112. package/dist/plugins/rich-editor/types.d.ts.map +0 -1
  113. package/dist/plugins/rich-editor/types.js +0 -16
  114. package/dist/plugins/rich-editor/types.js.map +0 -1
  115. package/dist/plugins/two-factors-auth/types.d.ts +0 -18
  116. package/dist/plugins/two-factors-auth/types.d.ts.map +0 -1
  117. package/dist/plugins/two-factors-auth/types.js +0 -2
  118. package/dist/plugins/two-factors-auth/types.js.map +0 -1
  119. package/dist/plugins/upload/types.d.ts +0 -132
  120. package/dist/plugins/upload/types.d.ts.map +0 -1
  121. package/dist/plugins/upload/types.js +0 -2
  122. package/dist/plugins/upload/types.js.map +0 -1
  123. package/dist/spa/src/acl/Button.vue +0 -21
  124. package/dist/spa/src/acl/Link.vue +0 -9
  125. package/dist/spa/src/components/Dropdown.vue +0 -167
  126. package/dist/spa/src/types/AdminForthConfig.js +0 -150
  127. package/dist/spa/src/types/AdminForthConfig.ts +0 -1816
  128. package/dist/spa/src/types/Commons.ts +0 -702
  129. package/dist/spa/src/types/FrontAndBack.ts +0 -698
  130. package/dist/types/AdminForthConfig.d.ts +0 -1665
  131. package/dist/types/AdminForthConfig.d.ts.map +0 -1
  132. package/dist/types/AdminForthConfig.js +0 -146
  133. package/dist/types/AdminForthConfig.js.map +0 -1
  134. package/dist/types/Commons.d.ts +0 -616
  135. package/dist/types/Commons.d.ts.map +0 -1
  136. package/dist/types/Commons.js +0 -65
  137. package/dist/types/Commons.js.map +0 -1
  138. package/dist/types/FrontAndBack.d.ts +0 -613
  139. package/dist/types/FrontAndBack.d.ts.map +0 -1
  140. package/dist/types/FrontAndBack.js +0 -62
  141. package/dist/types/FrontAndBack.js.map +0 -1
  142. /package/dist/spa/src/{components/AfTooltip.vue → afcl/Tooltip.vue} +0 -0
@@ -0,0 +1,23 @@
1
+ <template>
2
+ <router-link
3
+ v-bind="$attrs"
4
+ type="submit"
5
+ class="flex items-center justify-center gap-1 text-lightPrimaryContrast bg-lightPrimary dark:bg-darkPrimary hover:brightness-110
6
+ focus:ring-4 focus:outline-none focus:ring-lightPrimary focus:ring-opacity-50 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:focus:ring-darkPrimary dark:focus:ring-opacity-50"
7
+ :class="{
8
+ 'cursor-default': props.disabled,
9
+ 'opacity-50': props.disabled,
10
+ 'pointer-events-none': props.disabled,
11
+ }"
12
+ >
13
+ <slot></slot>
14
+ </router-link>
15
+ </template>
16
+
17
+ <script setup lang="ts">
18
+
19
+ const props = defineProps({
20
+ disabled: Boolean,
21
+ });
22
+
23
+ </script>
@@ -6,7 +6,7 @@
6
6
  v-model="search"
7
7
  @click="inputClick"
8
8
  @input="inputInput"
9
- class="block w-full pl-3 pr-10 py-2 border border-gray-300 rounded-md leading-5 bg-white placeholder-gray-500 sm:text-sm transition duration-150 ease-in-out dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white focus:ring-lightPrimary focus:border-lightPrimary dark:focus:ring-darkPrimary dark:focus:border-darkPrimary"
9
+ class="block w-full pl-3 pr-10 py-2.5 border border-gray-300 rounded-md leading-5 bg-gray-50 placeholder-gray-500 sm:text-sm transition duration-150 ease-in-out dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white focus:ring-lightPrimary focus:border-lightPrimary dark:focus:ring-darkPrimary dark:focus:border-darkPrimary"
10
10
  :placeholder="
11
11
  selectedItems.length && !multiple ? '' : (showDropdown ? 'Search' : placeholder || 'Select...')
12
12
  "
@@ -24,11 +24,12 @@
24
24
 
25
25
  <div class="absolute inset-y-0 right-2 flex items-center pointer-events-none">
26
26
  <!-- triangle icon -->
27
- <IconCaretDownSolid v-if="!showDropdown" class="h-5 w-5 text-lightPrimary dark:text-gray-400 opacity-50" />
28
- <IconCaretUpSolid v-else class="h-5 w-5 text-lightPrimary dark:text-gray-400 opacity-50" />
27
+ <IconCaretDownSolid class="h-5 w-5 text-lightPrimary dark:text-gray-400 opacity-50 transition duration-150 ease-in"
28
+ :class="{ 'transform rotate-180': showDropdown }"
29
+ />
29
30
  </div>
30
31
  </div>
31
- <div v-if="showDropdown" class="absolute z-10 mt-1 w-full bg-white shadow-lg dark:shadow-black dark:bg-gray-700 dark:border-gray-600 rounded-md py-1 text-base ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm">
32
+ <div v-if="showDropdown" class="absolute z-10 mt-1 w-full bg-white shadow-lg dark:shadow-black dark:bg-gray-700 dark:border-gray-600 rounded-md py-1 text-base ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm max-h-96">
32
33
  <div
33
34
  v-for="item in filteredItems"
34
35
  :key="item.value"
@@ -74,8 +75,8 @@
74
75
  </template>
75
76
 
76
77
  <script setup lang="ts">
77
- import { ref, computed, onMounted, onUnmounted, watch } from 'vue';
78
- import { IconCaretDownSolid, IconCaretUpSolid } from '@iconify-prerendered/vue-flowbite';
78
+ import { ref, computed, onMounted, onUnmounted, watch, type Ref } from 'vue';
79
+ import { IconCaretDownSolid } from '@iconify-prerendered/vue-flowbite';
79
80
 
80
81
 
81
82
  const props = defineProps({
@@ -98,7 +99,7 @@ const emit = defineEmits(['update:modelValue']);
98
99
  const search = ref('');
99
100
  const showDropdown = ref(false);
100
101
 
101
- const selectedItems = ref([]);
102
+ const selectedItems: Ref<any[]> = ref([]);
102
103
 
103
104
  function inputInput() {
104
105
  if (!props.multiple && selectedItems.value.length) {
@@ -3,3 +3,6 @@
3
3
  export { default as Select } from './Select.vue';
4
4
  export { default as Link } from './Link.vue';
5
5
  export { default as Button } from './Button.vue';
6
+ export { default as Input } from './Input.vue';
7
+ export { default as Tooltip } from './Tooltip.vue';
8
+ export { default as LinkButton } from './LinkButton.vue';
@@ -121,7 +121,6 @@
121
121
 
122
122
  <script setup>
123
123
  import { watch, computed } from 'vue'
124
- import Dropdown from '@/components/Dropdown.vue';
125
124
  import CustomDateRangePicker from '@/components/CustomDateRangePicker.vue';
126
125
  import { callAdminForthApi } from '@/utils';
127
126
  import { useRouter } from 'vue-router';
@@ -20,13 +20,13 @@
20
20
  :key="column.name"
21
21
  v-if="currentValues !== null"
22
22
  class="bg-ligftForm dark:bg-gray-800 dark:border-gray-700 block md:table-row"
23
- :class="{ 'border-b': i !== group.columns.length - 1 }"
23
+ :class="{ 'border-b': i !== group.columns.length - 1, 'opacity-50 pointer-events-none': column.editReadonly && source === 'edit'}"
24
24
  >
25
25
  <td class="px-6 py-4 flex items-center block md:table-cell pb-0 md:pb-4"
26
26
  :class="{'rounded-bl-lg border-b-none': i === group.columns.length - 1}"> <!--align-top-->
27
27
  <span class="flex items-center gap-1">
28
28
  {{ column.label }}
29
- <AfTooltip v-if="column.required[mode]">
29
+ <Tooltip v-if="column.required[mode]">
30
30
 
31
31
  <IconExclamationCircleSolid v-if="column.required[mode]" class="w-4 h-4"
32
32
  :class="(columnError(column) && validating) ? 'text-red-500 dark:text-red-400' : 'text-gray-400 dark:text-gray-500'"
@@ -35,7 +35,7 @@
35
35
  <template #tooltip>
36
36
  Required field
37
37
  </template>
38
- </AfTooltip>
38
+ </Tooltip>
39
39
  </span>
40
40
 
41
41
 
@@ -154,8 +154,8 @@
154
154
  import { IconExclamationCircleSolid, IconEyeSlashSolid, IconEyeSolid } from '@iconify-prerendered/vue-flowbite';
155
155
  import CustomDatePicker from "@/components/CustomDatePicker.vue";
156
156
  import Select from '@/afcl/Select.vue';
157
- import AfTooltip from "./AfTooltip.vue";
158
157
  import { getCustomComponent } from '@/utils';
158
+ import { Tooltip } from '@/afcl';
159
159
 
160
160
 
161
161
  const props = defineProps({
@@ -109,7 +109,7 @@
109
109
  </td>
110
110
  <td class=" items-center px-2 md:px-3 lg:px-6 py-4 cursor-default" @click="(e)=>{e.stopPropagation()}">
111
111
  <div class="flex text-lightPrimary dark:text-darkPrimary items-center">
112
- <AfTooltip>
112
+ <Tooltip>
113
113
  <RouterLink
114
114
  v-if="resource.options?.allowedActions.show"
115
115
  :to="{
@@ -127,9 +127,9 @@
127
127
  <template v-slot:tooltip>
128
128
  Show item
129
129
  </template>
130
- </AfTooltip>
130
+ </Tooltip>
131
131
 
132
- <AfTooltip>
132
+ <Tooltip>
133
133
  <RouterLink
134
134
  v-if="resource.options?.allowedActions.edit"
135
135
  :to="{
@@ -145,9 +145,9 @@
145
145
  <template v-slot:tooltip>
146
146
  Edit item
147
147
  </template>
148
- </AfTooltip>
148
+ </Tooltip>
149
149
 
150
- <AfTooltip>
150
+ <Tooltip>
151
151
  <button
152
152
  v-if="resource.options?.allowedActions.delete"
153
153
  @click="deleteRecord(row)"
@@ -158,11 +158,11 @@
158
158
  <template v-slot:tooltip>
159
159
  Delete item
160
160
  </template>
161
- </AfTooltip>
161
+ </Tooltip>
162
162
 
163
- <template v-if="coreStore.resourceOptions?.pageInjections?.list?.customActionIcons">
163
+ <template v-if="customActionsInjection">
164
164
  <component
165
- v-for="c in coreStore.resourceOptions?.pageInjections?.list?.customActionIcons"
165
+ v-for="c in customActionsInjection"
166
166
  :is="getCustomComponent(c)"
167
167
  :meta="c.meta"
168
168
  :resource="coreStore.resource"
@@ -244,7 +244,7 @@
244
244
  </div>
245
245
  </template>
246
246
 
247
- <script setup>
247
+ <script setup lang="ts">
248
248
 
249
249
 
250
250
  import { computed, onMounted, ref, watch } from 'vue';
@@ -266,21 +266,21 @@ import {
266
266
  IconTrashBinSolid
267
267
  } from '@iconify-prerendered/vue-flowbite';
268
268
  import router from '@/router';
269
- import AfTooltip from './AfTooltip.vue';
269
+ import { Tooltip } from '@/afcl';
270
270
 
271
271
  const coreStore = useCoreStore();
272
272
 
273
-
274
- const props = defineProps([
275
- 'page',
276
- 'resource',
277
- 'rows',
278
- 'totalRows',
279
- 'pageSize',
280
- 'checkboxes',
281
- 'sort',
282
- 'noRoundings'
283
- ])
273
+ const props = defineProps<{
274
+ page: number,
275
+ resource: any,
276
+ rows: any[] | null,
277
+ totalRows: number,
278
+ pageSize: number,
279
+ checkboxes: any[],
280
+ sort: any[],
281
+ noRoundings?: boolean,
282
+ customActionsInjection?: any[],
283
+ }>();
284
284
 
285
285
  // emits, update page
286
286
  const emits = defineEmits([
@@ -29,9 +29,11 @@
29
29
  <span v-else-if="column.type === 'richtext'">
30
30
  <div v-html="protectAgainstXSS(record[column.name])" class="allow-lists"></div>
31
31
  </span>
32
+ <span v-else-if="column.type === 'decimal'">
33
+ {{ checkEmptyValues(record[column.name] && parseFloat(record[column.name]), route.meta.type) }}
34
+ </span>
32
35
  <span v-else-if="column.type === 'json'">
33
36
  <JsonViewer :value="record[column.name]" :expandDepth="column.extra?.jsonCollapsedLevel" copyable sort :theme="coreStore.theme" />
34
-
35
37
  </span>
36
38
  <span v-else>
37
39
  {{ checkEmptyValues(record[column.name],route.meta.type) }}
@@ -50,7 +50,10 @@ export class FrontendAPI {
50
50
  setFilter: () => this.setListFilter.bind(this),
51
51
  updateFilter: () => this.updateListFilter.bind(this),
52
52
  clearFilters: () => this.clearListFilters.bind(this),
53
- }
53
+ },
54
+ menu: {
55
+ refreshMenuBadges: () => {/* will be redefined */}
56
+ },
54
57
  };
55
58
  }
56
59
 
@@ -1,19 +1,19 @@
1
1
  <template>
2
- <AfTooltip>
2
+ <Tooltip>
3
3
  <span class="flex items-center">
4
4
  {{ visualValue }} <IconFileCopyAltSolid @click.stop="copyToCB" class="w-5 h-5 text-lightPrimary dark:text-darkPrimary" v-if="visualValue"/>
5
5
  </span>
6
6
  <template #tooltip v-if="visualValue">
7
7
  {{ props.record[props.column.name] }}
8
8
  </template>
9
- </AfTooltip>
9
+ </Tooltip>
10
10
 
11
11
  </template>
12
12
 
13
13
  <script setup>
14
14
  import { computed, ref, onMounted, nextTick } from 'vue';
15
15
  import { IconFileCopyAltSolid } from '@iconify-prerendered/vue-flowbite';
16
- import AfTooltip from '@/components/AfTooltip.vue';
16
+ import Tooltip from '@/afcl/Tooltip.vue';
17
17
 
18
18
 
19
19
  const visualValue = computed(() => {
@@ -25,7 +25,7 @@ const visualValue = computed(() => {
25
25
  return val;
26
26
  });
27
27
 
28
- const props = defineProps(['column', 'record', 'meta']);
28
+ const props = defineProps(['column', 'record', 'meta', 'resource', 'adminUser']);
29
29
 
30
30
  const id = ref();
31
31
 
@@ -1,19 +1,19 @@
1
1
  <template>
2
- <AfTooltip>
2
+ <Tooltip>
3
3
  <span class="flex items-center">
4
4
  {{ visualValue }} <IconFileCopyAltSolid @click.stop="copyToCB" class="w-5 h-5 text-lightPrimary dark:text-darkPrimary" v-if="visualValue"/>
5
5
  </span>
6
6
  <template #tooltip v-if="visualValue">
7
7
  {{ props.record[props.column.name] }}
8
8
  </template>
9
- </AfTooltip>
9
+ </Tooltip>
10
10
 
11
11
  </template>
12
12
 
13
13
  <script setup>
14
14
  import { computed, ref, onMounted, nextTick } from 'vue';
15
15
  import { IconFileCopyAltSolid } from '@iconify-prerendered/vue-flowbite';
16
- import AfTooltip from '@/components/AfTooltip.vue';
16
+ import Tooltip from '@/afcl/Tooltip.vue';
17
17
 
18
18
 
19
19
  const visualValue = computed(() => {
@@ -25,7 +25,7 @@ const visualValue = computed(() => {
25
25
  return val;
26
26
  });
27
27
 
28
- const props = defineProps(['column', 'record', 'meta']);
28
+ const props = defineProps(['column', 'record', 'meta', 'resource', 'adminUser']);
29
29
 
30
30
  const id = ref();
31
31
 
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <AfTooltip>
2
+ <Tooltip>
3
3
  <span class="flex items-center">
4
4
  <span
5
5
  :class="{[`fi-${countryIsoLow}`]: true, 'flag-icon': countryName}"
@@ -10,7 +10,7 @@
10
10
  <template v-if="shouldShowTooltip" #tooltip>
11
11
  {{ countryName }}
12
12
  </template>
13
- </AfTooltip>
13
+ </Tooltip>
14
14
  </template>
15
15
 
16
16
  <script setup>
@@ -19,7 +19,7 @@ import { computed, ref, onMounted } from 'vue';
19
19
  import 'flag-icons/css/flag-icons.min.css';
20
20
  import isoCountries from 'i18n-iso-countries';
21
21
  import enLocal from 'i18n-iso-countries/langs/en.json';
22
- import AfTooltip from '@/components/AfTooltip.vue';
22
+ import Tooltip from '@/afcl/Tooltip.vue';
23
23
 
24
24
  isoCountries.registerLocale(enLocal);
25
25
 
@@ -1,17 +1,18 @@
1
1
  <template>
2
- <AfTooltip class="flex items-center" >
2
+ <Tooltip>
3
3
  {{ formattedValue }}
4
4
  <template #tooltip v-if="formattedValue">
5
5
  {{ formattedTooltipValue }}
6
6
  </template>
7
- </AfTooltip>
7
+ </Tooltip>
8
8
  </template>
9
9
 
10
10
  <script setup>
11
11
  import { computed, ref, onMounted, nextTick } from 'vue';
12
- import AfTooltip from '@/components/AfTooltip.vue';
12
+ import Tooltip from '@/afcl/Tooltip.vue';
13
13
 
14
- const props = defineProps(['column', 'record']);
14
+ const props = defineProps(['column', 'record', 'meta', 'resource', 'adminUser']);
15
+
15
16
  const id = ref();
16
17
  const userLocale = ref(navigator.language || 'en-US');
17
18
 
@@ -1,24 +1,25 @@
1
1
  <template>
2
- <AfTooltip class="flex items-center">
2
+ <Tooltip>
3
3
  {{ relativeTime }}
4
4
  <template #tooltip v-if="relativeTime">
5
5
  {{ fullTime }}
6
6
  </template>
7
- </AfTooltip>
7
+ </Tooltip>
8
8
  </template>
9
9
 
10
10
  <script setup>
11
11
  import { computed, ref, onMounted } from 'vue';
12
- import AfTooltip from '@/components/AfTooltip.vue';
12
+ import Tooltip from '@/afcl/Tooltip.vue';
13
13
  import en from 'javascript-time-ago/locale/en';
14
14
  import TimeAgo from 'javascript-time-ago';
15
15
  import dayjs from 'dayjs';
16
16
 
17
+
17
18
  const id = ref();
18
19
 
19
20
  TimeAgo.addLocale(en);
20
21
 
21
- const props = defineProps(['column', 'record']);
22
+ const props = defineProps(['column', 'record', 'meta', 'resource', 'adminUser']);
22
23
 
23
24
  const userLocale = ref(navigator.language || 'en-US');
24
25
  const timeAgoFormatter = new TimeAgo(userLocale.value);
@@ -1,5 +1,6 @@
1
1
  import { createRouter, createWebHistory } from 'vue-router';
2
2
  import ResourceParent from '@/views/ResourceParent.vue';
3
+ import PageNotFound from '@/views/PageNotFound.vue';
3
4
 
4
5
  /* IMPORTANT:ADMINFORTH ROUTES IMPORTS */
5
6
 
@@ -53,6 +54,7 @@ const router = createRouter({
53
54
  ]
54
55
  },
55
56
  /* IMPORTANT:ADMINFORTH ROUTES */
57
+ { path: "/:pathMatch(.*)*", component: PageNotFound },
56
58
  ]
57
59
  })
58
60
 
@@ -3,6 +3,7 @@ import { defineStore } from 'pinia'
3
3
  import { callAdminForthApi } from '@/utils';
4
4
  import type { AdminForthResourceCommon, AdminForthResourceColumnCommon } from '@/types/Common';
5
5
  import type { Ref } from 'vue'
6
+ import type { AdminForthConfigMenuItem } from '@/types/Back';
6
7
 
7
8
  export const useCoreStore = defineStore('core', () => {
8
9
  const resourceById: Ref<Object> = ref({});
@@ -12,6 +13,7 @@ export const useCoreStore = defineStore('core', () => {
12
13
  const config = ref({});
13
14
  const record: Ref<any | null> = ref({});
14
15
  const resource: Ref<AdminForthResourceCommon | null> = ref(null);
16
+ const userData = ref(null);
15
17
 
16
18
  const resourceColumnsWithFilters = computed(() => {
17
19
  if (!resource.value) {
@@ -52,11 +54,42 @@ export const useCoreStore = defineStore('core', () => {
52
54
  return acc;
53
55
  }, {});
54
56
  config.value = resp.config;
55
- adminUser.value = resp.user;
57
+ adminUser.value = resp.adminUser;
58
+ userData.value = resp.user;
56
59
  console.log('🌍 AdminForth v', resp.version);
57
60
  }
58
61
 
59
- async function fetchRecord({ resourceId, primaryKey }) {
62
+ function findItemWithId(items: AdminForthConfigMenuItem[], _itemId: string): AdminForthConfigMenuItem | undefined {
63
+ for (const item of items) {
64
+ if (item._itemId === _itemId) {
65
+ return item;
66
+ }
67
+ if (item.children) {
68
+ const found = findItemWithId(item.children, _itemId);
69
+ if (found) {
70
+ return found;
71
+ }
72
+ }
73
+ }
74
+ }
75
+ async function fetchMenuBadges() {
76
+ const resp: Record<string, string> = await callAdminForthApi({
77
+ path: '/get_menu_badges',
78
+ method: 'GET',
79
+ });
80
+ if (!resp) {
81
+ return;
82
+ }
83
+ Object.entries(resp).forEach(([_itemId, badge]: [string, string]) => {
84
+ const item: AdminForthConfigMenuItem | undefined = findItemWithId(menu.value, _itemId);
85
+ if (item) {
86
+ item.badge = badge;
87
+ }
88
+ });
89
+ }
90
+
91
+
92
+ async function fetchRecord({ resourceId, primaryKey, source }: { resourceId: string, primaryKey: string, source: string }) {
60
93
  record.value = null;
61
94
 
62
95
  if (!resource.value) {
@@ -71,7 +104,7 @@ export const useCoreStore = defineStore('core', () => {
71
104
  path: '/get_resource_data',
72
105
  method: 'POST',
73
106
  body: {
74
- source: 'show',
107
+ source: source,
75
108
  resourceId: resourceId,
76
109
  filters: [
77
110
  {
@@ -130,16 +163,15 @@ export const useCoreStore = defineStore('core', () => {
130
163
  config.value = {...config.value, ...res};
131
164
  }
132
165
 
133
-
134
166
 
135
167
  const username = computed(() => {
136
168
  const usernameField = config.value.usernameField;
137
- return adminUser.value && adminUser.value[usernameField];
169
+ return userData.value && userData.value[usernameField];
138
170
  });
139
171
 
140
172
  const userFullname = computed(() => {
141
173
  const userFullnameField = config.value.userFullnameField;
142
- return adminUser.value && adminUser.value[userFullnameField];
174
+ return userData.value && userData.value[userFullnameField];
143
175
  })
144
176
 
145
177
 
@@ -161,5 +193,6 @@ export const useCoreStore = defineStore('core', () => {
161
193
  resourceColumnsWithFilters,
162
194
  toggleTheme,
163
195
  theme,
196
+ fetchMenuBadges,
164
197
  }
165
198
  })