adminforth 2.27.0-next.7 → 2.27.0-next.71

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 (110) hide show
  1. package/commands/callTsProxy.js +10 -5
  2. package/commands/createApp/templates/api.ts.hbs +28 -9
  3. package/commands/createApp/templates/package.json.hbs +2 -1
  4. package/commands/proxy.ts +18 -10
  5. package/dist/basePlugin.js +1 -1
  6. package/dist/basePlugin.js.map +1 -1
  7. package/dist/commands/proxy.js +14 -10
  8. package/dist/commands/proxy.js.map +1 -1
  9. package/dist/dataConnectors/baseConnector.d.ts +10 -4
  10. package/dist/dataConnectors/baseConnector.d.ts.map +1 -1
  11. package/dist/dataConnectors/baseConnector.js +76 -54
  12. package/dist/dataConnectors/baseConnector.js.map +1 -1
  13. package/dist/dataConnectors/clickhouse.d.ts +5 -2
  14. package/dist/dataConnectors/clickhouse.d.ts.map +1 -1
  15. package/dist/dataConnectors/clickhouse.js +76 -10
  16. package/dist/dataConnectors/clickhouse.js.map +1 -1
  17. package/dist/dataConnectors/mongo.d.ts.map +1 -1
  18. package/dist/dataConnectors/mongo.js +3 -1
  19. package/dist/dataConnectors/mongo.js.map +1 -1
  20. package/dist/dataConnectors/mysql.d.ts.map +1 -1
  21. package/dist/dataConnectors/mysql.js +3 -1
  22. package/dist/dataConnectors/mysql.js.map +1 -1
  23. package/dist/dataConnectors/postgres.d.ts.map +1 -1
  24. package/dist/dataConnectors/postgres.js +3 -1
  25. package/dist/dataConnectors/postgres.js.map +1 -1
  26. package/dist/dataConnectors/sqlite.d.ts.map +1 -1
  27. package/dist/dataConnectors/sqlite.js +4 -2
  28. package/dist/dataConnectors/sqlite.js.map +1 -1
  29. package/dist/index.d.ts +4 -1
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +17 -0
  32. package/dist/index.js.map +1 -1
  33. package/dist/modules/configValidator.d.ts.map +1 -1
  34. package/dist/modules/configValidator.js +16 -9
  35. package/dist/modules/configValidator.js.map +1 -1
  36. package/dist/modules/restApi.d.ts.map +1 -1
  37. package/dist/modules/restApi.js +598 -15
  38. package/dist/modules/restApi.js.map +1 -1
  39. package/dist/modules/styles.js +1 -1
  40. package/dist/modules/utils.d.ts +1 -1
  41. package/dist/modules/utils.d.ts.map +1 -1
  42. package/dist/modules/utils.js +3 -5
  43. package/dist/modules/utils.js.map +1 -1
  44. package/dist/servers/express.d.ts +18 -7
  45. package/dist/servers/express.d.ts.map +1 -1
  46. package/dist/servers/express.js +141 -1
  47. package/dist/servers/express.js.map +1 -1
  48. package/dist/servers/openapi.d.ts +25 -0
  49. package/dist/servers/openapi.d.ts.map +1 -0
  50. package/dist/servers/openapi.js +92 -0
  51. package/dist/servers/openapi.js.map +1 -0
  52. package/dist/servers/openapiDocument.d.ts +12 -0
  53. package/dist/servers/openapiDocument.d.ts.map +1 -0
  54. package/dist/servers/openapiDocument.js +313 -0
  55. package/dist/servers/openapiDocument.js.map +1 -0
  56. package/dist/spa/package-lock.json +41 -0
  57. package/dist/spa/package.json +4 -0
  58. package/dist/spa/pnpm-lock.yaml +384 -310
  59. package/dist/spa/pnpm-workspace.yaml +4 -0
  60. package/dist/spa/src/App.vue +78 -76
  61. package/dist/spa/src/afcl/Button.vue +2 -3
  62. package/dist/spa/src/afcl/Dialog.vue +1 -1
  63. package/dist/spa/src/afcl/Input.vue +1 -1
  64. package/dist/spa/src/afcl/Select.vue +8 -2
  65. package/dist/spa/src/afcl/Skeleton.vue +5 -0
  66. package/dist/spa/src/afcl/Spinner.vue +1 -1
  67. package/dist/spa/src/components/CallActionWrapper.vue +1 -1
  68. package/dist/spa/src/components/ColumnValueInput.vue +16 -3
  69. package/dist/spa/src/components/ColumnValueInputWrapper.vue +25 -2
  70. package/dist/spa/src/components/CustomRangePicker.vue +10 -14
  71. package/dist/spa/src/components/Filters.vue +95 -63
  72. package/dist/spa/src/components/GroupsTable.vue +9 -6
  73. package/dist/spa/src/components/MenuLink.vue +2 -2
  74. package/dist/spa/src/components/ResourceForm.vue +103 -9
  75. package/dist/spa/src/components/ResourceListTable.vue +16 -10
  76. package/dist/spa/src/components/ShowTable.vue +3 -3
  77. package/dist/spa/src/components/Sidebar.vue +29 -8
  78. package/dist/spa/src/components/ThreeDotsMenu.vue +25 -9
  79. package/dist/spa/src/components/ValueRenderer.vue +1 -0
  80. package/dist/spa/src/controls/BoolToggle.vue +2 -2
  81. package/dist/spa/src/renderers/RichText.vue +2 -2
  82. package/dist/spa/src/renderers/ZeroStylesRichText.vue +2 -2
  83. package/dist/spa/src/spa_types/core.ts +32 -0
  84. package/dist/spa/src/stores/core.ts +16 -2
  85. package/dist/spa/src/stores/filters.ts +16 -12
  86. package/dist/spa/src/types/Back.ts +137 -26
  87. package/dist/spa/src/types/Common.ts +25 -6
  88. package/dist/spa/src/types/adapters/CompletionAdapter.ts +27 -5
  89. package/dist/spa/src/types/adapters/index.ts +2 -2
  90. package/dist/spa/src/utils/createEditUtils.ts +65 -0
  91. package/dist/spa/src/utils/index.ts +2 -1
  92. package/dist/spa/src/utils/listUtils.ts +3 -3
  93. package/dist/spa/src/utils/utils.ts +42 -7
  94. package/dist/spa/src/utils.ts +2 -1
  95. package/dist/spa/src/views/CreateEditSkeleton.vue +74 -0
  96. package/dist/spa/src/views/CreateView.vue +24 -50
  97. package/dist/spa/src/views/EditView.vue +23 -40
  98. package/dist/spa/src/views/ListView.vue +22 -32
  99. package/dist/spa/src/views/ShowView.vue +66 -24
  100. package/dist/types/Back.d.ts +140 -32
  101. package/dist/types/Back.d.ts.map +1 -1
  102. package/dist/types/Back.js.map +1 -1
  103. package/dist/types/Common.d.ts +32 -6
  104. package/dist/types/Common.d.ts.map +1 -1
  105. package/dist/types/Common.js.map +1 -1
  106. package/dist/types/adapters/CompletionAdapter.d.ts +18 -3
  107. package/dist/types/adapters/CompletionAdapter.d.ts.map +1 -1
  108. package/dist/types/adapters/index.d.ts +1 -1
  109. package/dist/types/adapters/index.d.ts.map +1 -1
  110. package/package.json +11 -6
@@ -200,7 +200,7 @@
200
200
  :key="action.id"
201
201
  >
202
202
  <component
203
- v-if="action.customComponent"
203
+ v-if="action"
204
204
  :is="action.customComponent ? getCustomComponent(formatComponent(action.customComponent)) : CallActionWrapper"
205
205
  :meta="formatComponent(action.customComponent).meta"
206
206
  :row="row"
@@ -211,12 +211,18 @@
211
211
  <button
212
212
  type="button"
213
213
  class="border border-gray-300 dark:border-gray-700 dark:border-opacity-0 border-opacity-0 hover:border-opacity-100 dark:hover:border-opacity-100 rounded-md hover:bg-gray-100 dark:hover:bg-gray-800 cursor-pointer"
214
+ :disabled="!!actionLoadingStates[`${action.id}_${row._primaryKeyValue}`]"
214
215
  >
215
216
  <component
216
- v-if="action.icon"
217
+ v-if="action.icon && !actionLoadingStates[`${action.id}_${row._primaryKeyValue}`]"
217
218
  :is="getIcon(action.icon)"
218
219
  class="w-6 h-6 text-lightPrimary dark:text-darkPrimary"
219
220
  />
221
+ <Spinner
222
+ v-if="actionLoadingStates[`${action.id}_${row._primaryKeyValue}`]"
223
+ class="w-5 h-5 text-gray-200 dark:text-gray-500 fill-gray-500 dark:fill-gray-300"
224
+ />
225
+ <span v-if="actionLoadingStates[`${action.id}_${row._primaryKeyValue}`]" class="sr-only">Loading...</span>
220
226
  </button>
221
227
  </component>
222
228
 
@@ -356,8 +362,8 @@ import {
356
362
  IconInboxOutline
357
363
  } from '@iconify-prerendered/vue-flowbite';
358
364
  import router from '@/router';
359
- import { Tooltip } from '@/afcl';
360
- import type { AdminForthResourceCommon, AdminForthResourceColumnCommon, AdminForthComponentDeclarationFull, AdminForthComponentDeclaration } from '@/types/Common';
365
+ import { Tooltip, Spinner } from '@/afcl';
366
+ import type { AdminForthResourceFrontend, AdminForthResourceColumnCommon, AdminForthComponentDeclarationFull, AdminForthComponentDeclaration } from '@/types/Common';
361
367
  import { useAdminforth } from '@/adminforth';
362
368
  import Checkbox from '@/afcl/Checkbox.vue';
363
369
  import ListActionsThreeDots from '@/components/ListActionsThreeDots.vue';
@@ -368,7 +374,7 @@ const { t } = useI18n();
368
374
  const { alert, confirm } = useAdminforth();
369
375
  const props = defineProps<{
370
376
  page: number,
371
- resource: AdminForthResourceCommon | null,
377
+ resource: AdminForthResourceFrontend | null,
372
378
  rows: any[] | null,
373
379
  totalRows: number,
374
380
  pageSize: number,
@@ -613,7 +619,7 @@ async function startCustomAction(actionId: string | number, row: any, extraData:
613
619
  recordId: row._primaryKeyValue,
614
620
  extra: extraData,
615
621
  setLoadingState: (loading: boolean) => {
616
- actionLoadingStates.value[actionId] = loading;
622
+ actionLoadingStates.value[`${actionId}_${row._primaryKeyValue}`] = loading;
617
623
  },
618
624
  onSuccess: async (data: any) => {
619
625
  emits('update:records', true);
@@ -638,10 +644,10 @@ function validatePageInput() {
638
644
  pageInput.value = validPage.toString();
639
645
  }
640
646
  /*
641
- *___________________________________________________________________
642
- * |
643
- * Virtual Scroll Implementation |
644
- *___________________________________________________________________|
647
+ * ___________________________________________________________________
648
+ *| |
649
+ *| Virtual Scroll Implementation |
650
+ *|___________________________________________________________________|
645
651
  */
646
652
  // Add throttle utility
647
653
  const throttle = (fn: Function, delay: number) => {
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div class="overflow-x-auto shadow-resourseFormShadow dark:shadow-darkResourseFormShadow"
2
+ <div class="overflow-x-auto shadow-resourseFormShadow dark:shadow-darkResourseFormShadow border dark:border-gray-700"
3
3
  :class="{'rounded-default' : isRounded}"
4
4
  >
5
5
  <div v-if="groupName && !noTitle" class="text-md font-semibold px-6 py-3 flex flex-1 items-center text-lightShowTableHeadingText bg-lightShowTableHeadingBackground dark:bg-darkShowTableHeadingBackground dark:text-darkShowTableHeadingText rounded-t-lg">
@@ -64,7 +64,7 @@
64
64
  import { getCustomComponent, checkShowIf } from '@/utils';
65
65
  import { useCoreStore } from '@/stores/core';
66
66
  import { computed } from 'vue';
67
- import type { AdminForthResourceCommon, AdminForthResourceColumnInputCommon } from '@/types/Common';
67
+ import type { AdminForthResourceFrontend, AdminForthResourceColumnInputCommon } from '@/types/Common';
68
68
  const props = withDefaults(defineProps<{
69
69
  columns: Array<{
70
70
  name: string;
@@ -83,7 +83,7 @@
83
83
  }>;
84
84
  groupName?: string | null;
85
85
  noTitle?: boolean;
86
- resource: AdminForthResourceCommon | null;
86
+ resource: AdminForthResourceFrontend | null;
87
87
  record: Record<string, any>;
88
88
  isRounded?: boolean;
89
89
  }>(), {
@@ -71,7 +71,7 @@
71
71
  >
72
72
  <component v-if="item.icon" :is="getIcon(item.icon)" class="w-5 h-5 text-lightSidebarIcons group-hover:text-lightSidebarIconsHover transition duration-75 dark:group-hover:text-darkSidebarIconsHover dark:text-darkSidebarIcons" ></component>
73
73
  <span class="overflow-hidden flex-1 ms-3 text-left rtl:text-right whitespace-nowrap">{{ item.label }}
74
- <span v-if="item.badge" class="inline-flex items-center justify-center w-3 h-3 p-3 ms-3 text-sm font-medium rounded-full bg-lightAnnouncementBG dark:bg-darkAnnouncementBG
74
+ <span v-if="item.badge || item.badge === 0" class="inline-flex items-center justify-center w-3 h-3 p-3 ms-3 text-sm font-medium rounded-full bg-lightAnnouncementBG dark:bg-darkAnnouncementBG
75
75
  fill-lightAnnouncementText dark:fill-darkAccent text-lightAnnouncementText dark:text-darkAccent">
76
76
  <Tooltip v-if="item.badgeTooltip">
77
77
  {{ item.badge }}
@@ -90,13 +90,15 @@
90
90
  </svg>
91
91
  </button>
92
92
 
93
- <ul :id="`dropdown-example${i}`" role="none" class="af-sidebar-dropdown pt-1 space-y-1" :class="{ 'hidden': !opened.includes(i) }">
94
- <template v-for="(child, j) in item.children" :key="`menu-${i}-${j}`">
95
- <li class="af-sidebar-menu-link">
96
- <MenuLink :item="child" isChild="true" @click="$emit('hideSidebar')"/>
93
+ <transition name="slow-drop">
94
+ <ul v-show="opened.includes(i)" :id="`dropdown-example${i}`" role="none" class="af-sidebar-dropdown pt-1 space-y-1 overflow-hidden">
95
+ <template v-for="(child, j) in item.children" :key="`menu-${i}-${j}`">
96
+ <li class="af-sidebar-menu-link">
97
+ <MenuLink :item="child" isChild="true" @click="$emit('hideSidebar')"/>
97
98
  </li>
98
- </template>
99
- </ul>
99
+ </template>
100
+ </ul>
101
+ </transition>
100
102
  </li>
101
103
  <li v-else class="af-sidebar-menu-link">
102
104
  <MenuLink :item="item" @click="$emit('hideSidebar')"/>
@@ -129,7 +131,7 @@
129
131
  } : {}"
130
132
  >{{ item.label }}
131
133
 
132
- <span v-if="item.badge" class="inline-flex items-center justify-center w-3 h-3 p-3 ms-3 text-sm font-medium rounded-full bg-lightAnnouncementBG dark:bg-darkAnnouncementBG
134
+ <span v-if="item.badge || item.badge === 0" class="inline-flex items-center justify-center w-3 h-3 p-3 ms-3 text-sm font-medium rounded-full bg-lightAnnouncementBG dark:bg-darkAnnouncementBG
133
135
  fill-lightAnnouncementText dark:fill-darkAccent text-lightAnnouncementText dark:text-darkAccent">
134
136
  <Tooltip v-if="item.badgeTooltip">
135
137
  {{ item.badge }}
@@ -292,6 +294,25 @@
292
294
  background-color: rgba(75, 85, 99, 0.4);
293
295
  }
294
296
 
297
+ /* Custom animation for dropdown */
298
+ .slow-drop-enter-active,
299
+ .slow-drop-leave-active {
300
+ overflow: hidden;
301
+ transition: opacity 0.2s ease, transform 0.2s ease;
302
+ }
303
+
304
+ .slow-drop-enter-from,
305
+ .slow-drop-leave-to {
306
+ opacity: 0;
307
+ transform: translateY(-4px);
308
+ }
309
+
310
+ .slow-drop-enter-to,
311
+ .slow-drop-leave-from {
312
+ opacity: 1;
313
+ transform: translateY(0);
314
+ }
315
+
295
316
  /* For browsers that support overlay scrollbars natively */
296
317
  @supports (overflow: overlay) {
297
318
  .sidebar-scroll {
@@ -43,20 +43,28 @@
43
43
  </div>
44
44
  </div>
45
45
  </li>
46
- <li v-for="action in customActions" :key="action.id">
47
- <div class="wrapper">
46
+ <li v-for="(action, i) in customActions" :key="action.id">
47
+ <div
48
+ class="wrapper"
49
+ @click="injectedComponentClick(threeDotsDropdownItems ? threeDotsDropdownItems.length + i : i)"
50
+ >
48
51
  <component
52
+ :ref="(el: any) => setComponentRef(el, threeDotsDropdownItems ? threeDotsDropdownItems.length + i : i)"
49
53
  :is="(action.customComponent && getCustomComponent(formatComponent(action.customComponent))) || CallActionWrapper"
50
- :meta="formatComponent(action.customComponent as AdminForthComponentDeclarationFull).meta || {}"
54
+ :meta="formatComponent(action.customComponent).meta"
51
55
  @callAction="(payload? : Object) => handleActionClick(action, payload)"
52
56
  >
53
- <a @click.prevent class="block px-4 py-2 hover:text-lightThreeDotsMenuBodyTextHover hover:bg-lightThreeDotsMenuBodyBackgroundHover dark:hover:bg-darkThreeDotsMenuBodyBackgroundHover dark:hover:text-darkThreeDotsMenuBodyTextHover">
54
- <div class="flex items-center gap-2">
57
+ <a @click.prevent class="block">
58
+ <div class="flex items-center gap-2 hover:text-lightThreeDotsMenuBodyTextHover hover:bg-lightThreeDotsMenuBodyBackgroundHover dark:hover:bg-darkThreeDotsMenuBodyBackgroundHover dark:hover:text-darkThreeDotsMenuBodyTextHover">
55
59
  <component
56
- v-if="action.icon"
60
+ v-if="action.icon && !actionLoadingStates[action.id!]"
57
61
  :is="getIcon(action.icon)"
58
62
  class="w-4 h-4 text-lightPrimary dark:text-darkPrimary"
59
63
  />
64
+ <Spinner
65
+ v-if="actionLoadingStates[action.id!]"
66
+ class="w-5 h-5 text-gray-200 dark:text-gray-500 fill-gray-500 dark:fill-gray-300"
67
+ />
60
68
  {{ action.name }}
61
69
  </div>
62
70
  </a>
@@ -91,12 +99,12 @@
91
99
  import { getCustomComponent, getIcon, formatComponent, executeCustomAction } from '@/utils';
92
100
  import { useCoreStore } from '@/stores/core';
93
101
  import { useAdminforth } from '@/adminforth';
94
- import { callAdminForthApi } from '@/utils';
95
102
  import { useRoute, useRouter } from 'vue-router';
96
103
  import CallActionWrapper from '@/components/CallActionWrapper.vue'
97
104
  import { ref, type ComponentPublicInstance, onMounted, onUnmounted } from 'vue';
98
105
  import type { AdminForthActionFront, AdminForthBulkActionFront, AdminForthComponentDeclarationFull } from '@/types/Common';
99
106
  import type { AdminForthActionInput } from '@/types/Back';
107
+ import { Spinner } from '@/afcl';
100
108
 
101
109
  const { list, alert} = useAdminforth();
102
110
  const route = useRoute();
@@ -104,6 +112,7 @@ const coreStore = useCoreStore();
104
112
  const router = useRouter();
105
113
  const threeDotsDropdownItemsRefs = ref<Array<ComponentPublicInstance | null>>([]);
106
114
  const showDropdown = ref(false);
115
+ const actionLoadingStates = ref<Record<string, boolean>>({});
107
116
  const dropdownRef = ref<HTMLElement | null>(null);
108
117
  const buttonTriggerRef = ref<HTMLElement | null>(null);
109
118
 
@@ -135,6 +144,9 @@ async function handleActionClick(action: AdminForthActionInput, payload: any) {
135
144
  resourceId: route.params.resourceId as string,
136
145
  recordId: route.params.primaryKey as string,
137
146
  extra: payload || {},
147
+ setLoadingState: (loading: boolean) => {
148
+ actionLoadingStates.value[action.id!] = loading;
149
+ },
138
150
  onSuccess: async (data: any) => {
139
151
  await coreStore.fetchRecord({
140
152
  resourceId: route.params.resourceId as string,
@@ -165,6 +177,7 @@ function startBulkAction(actionId: string) {
165
177
  }
166
178
 
167
179
  async function injectedComponentClick(index: number) {
180
+ console.log('Injected component click triggered for index:', index);
168
181
  const componentRef = threeDotsDropdownItemsRefs.value[index];
169
182
  if (componentRef && 'click' in componentRef) {
170
183
  (componentRef as any).click?.();
@@ -195,8 +208,11 @@ onUnmounted(() => {
195
208
  </script>
196
209
 
197
210
  <style lang="scss" scoped>
198
- .wrapper > * {
199
- @apply px-4 py-2;
211
+ .wrapper {
212
+ @apply px-4 py-2
213
+ hover:text-lightThreeDotsMenuBodyTextHover hover:bg-lightThreeDotsMenuBodyBackgroundHover
214
+ dark:hover:bg-darkThreeDotsMenuBodyBackgroundHover dark:hover:text-darkThreeDotsMenuBodyTextHover
215
+ cursor-pointer;
200
216
  }
201
217
  </style>
202
218
 
@@ -11,6 +11,7 @@
11
11
  class="rounded-md m-0.5 bg-lightAnnouncementBG dark:bg-darkAnnouncementBG text-lightAnnouncementText dark:text-darkAnnouncementText py-0.5 px-2.5 text-sm"
12
12
  >
13
13
  <RouterLink
14
+ v-if="foreignResource && foreignResource?.pk"
14
15
  class="font-medium text-lightSidebarText dark:text-darkSidebarText hover:brightness-110 whitespace-nowrap"
15
16
  :to="{
16
17
  name: 'resource-show',
@@ -12,7 +12,7 @@
12
12
  import Toggle from '@/afcl/Toggle.vue';
13
13
  import type {
14
14
  AdminForthResourceColumnCommon,
15
- AdminForthResourceCommon,
15
+ AdminForthResourceFrontend,
16
16
  AdminUser,
17
17
  } from "@/types/Common";
18
18
 
@@ -22,7 +22,7 @@ import type {
22
22
  column: AdminForthResourceColumnCommon,
23
23
  record: any,
24
24
  meta: any,
25
- resource: AdminForthResourceCommon,
25
+ resource: AdminForthResourceFrontend,
26
26
  adminUser: AdminUser,
27
27
  readonly: boolean
28
28
  }>();
@@ -3,14 +3,14 @@
3
3
  </template>
4
4
 
5
5
  <script setup lang="ts">
6
- import type { AdminForthResourceColumnCommon, AdminForthResourceCommon, AdminUser } from '@/types/Common'
6
+ import type { AdminForthResourceColumnCommon, AdminForthResourceFrontend, AdminUser } from '@/types/Common'
7
7
  import { protectAgainstXSS } from '@/utils'
8
8
 
9
9
  const props = defineProps<{
10
10
  column: AdminForthResourceColumnCommon
11
11
  record: any
12
12
  meta: any
13
- resource: AdminForthResourceCommon
13
+ resource: AdminForthResourceFrontend
14
14
  adminUser: AdminUser
15
15
  }>()
16
16
  const htmlContent = protectAgainstXSS(props.record[props.column.name])
@@ -4,14 +4,14 @@
4
4
 
5
5
  <script setup lang="ts">
6
6
  import { nextTick, onMounted, ref, watch } from 'vue'
7
- import type { AdminForthResourceColumnCommon, AdminForthResourceCommon, AdminUser } from '@/types/Common'
7
+ import type { AdminForthResourceColumnCommon, AdminForthResourceFrontend, AdminUser } from '@/types/Common'
8
8
  import { protectAgainstXSS } from '@/utils'
9
9
 
10
10
  const props = defineProps<{
11
11
  column: AdminForthResourceColumnCommon
12
12
  record: any
13
13
  meta: any
14
- resource: AdminForthResourceCommon
14
+ resource: AdminForthResourceFrontend
15
15
  adminUser: AdminUser
16
16
  }>()
17
17
 
@@ -1,4 +1,6 @@
1
1
  import type { AdminForthResource, AdminForthResourceColumn } from '../types/Back.js';
2
+ import type { FilterParams } from '@/types/Common';
3
+ import type { Ref, ComputedRef } from 'vue';
2
4
 
3
5
  export type resourceById = {
4
6
  [key: string]: AdminForthResource;
@@ -61,3 +63,33 @@ export type AllowedActions = {
61
63
  delete: boolean,
62
64
  }
63
65
 
66
+
67
+ export type sortType = {
68
+ field: string,
69
+ direction: 'ask' | 'desc'
70
+ } | null;
71
+
72
+ export type AdminforthFilterStore = {
73
+ filters: Ref<FilterParams[]>,
74
+
75
+ setSort: (sort: sortType) => void,
76
+ getSort: () => sortType,
77
+
78
+ setFilter: (filters: FilterParams) => void,
79
+ setFilters: (filters: FilterParams[]) => void,
80
+
81
+ getFilters: () => FilterParams[],
82
+
83
+ clearFilter: (fieldName: string) => void,
84
+ clearFilters: () => void,
85
+
86
+ shouldFilterBeHidden: (fieldName: string) => boolean,
87
+
88
+ visibleFiltersCount: ComputedRef<number>,
89
+ }
90
+
91
+ export interface AdminforthFilterStoreUnwrapped extends Omit<AdminforthFilterStore, 'filters' | 'visibleFiltersCount'> {
92
+ filters: FilterParams[],
93
+ visibleFiltersCount: number,
94
+ }
95
+
@@ -1,4 +1,4 @@
1
- import { ref, computed } from 'vue'
1
+ import { ref, computed, onMounted, onUnmounted } from 'vue'
2
2
  import { defineStore } from 'pinia'
3
3
  import { callAdminForthApi } from '@/utils';
4
4
  import websocket from '@/websocket';
@@ -21,6 +21,19 @@ export const useCoreStore = defineStore('core', () => {
21
21
  const userData: Ref<UserData | null> = ref(null);
22
22
  const isResourceFetching = ref(false);
23
23
  const isInternetError = ref(false);
24
+ const screenWidth = ref(window.innerWidth);
25
+
26
+ onMounted(() => {
27
+ window.addEventListener('resize', updateWidth);
28
+ });
29
+ onUnmounted(() => {
30
+ window.removeEventListener('resize', updateWidth);
31
+ });
32
+
33
+ const isMobile = computed(() => screenWidth.value <= 768);
34
+ const updateWidth = () => {
35
+ screenWidth.value = window.innerWidth
36
+ }
24
37
 
25
38
  const resourceColumnsWithFilters = computed(() => {
26
39
  if (!resource.value) {
@@ -29,7 +42,7 @@ export const useCoreStore = defineStore('core', () => {
29
42
  return resource.value.columns.filter((col: AdminForthResourceColumnCommon) => col.showIn?.filter);
30
43
  })
31
44
 
32
- const resourceOptions: Ref<AdminForthResourceCommon['options'] | null> = ref(null);
45
+ const resourceOptions: Ref<AdminForthResourceFrontend['options'] | null> = ref(null);
33
46
  const resourceColumnsError: Ref<string> = ref('');
34
47
  const resourceColumnsId: Ref<string | null> = ref(null);
35
48
  const adminUser: Ref<null | AdminUser> = ref(null);
@@ -261,5 +274,6 @@ export const useCoreStore = defineStore('core', () => {
261
274
  isResourceFetching,
262
275
  isIos,
263
276
  isInternetError,
277
+ isMobile,
264
278
  }
265
279
  })
@@ -1,40 +1,42 @@
1
1
  import { ref, computed, type Ref } from 'vue';
2
2
  import { defineStore } from 'pinia';
3
3
  import { useCoreStore } from './core';
4
+ import type { FilterParams } from '@/types/Common';
5
+ import type { AdminforthFilterStore, sortType } from '../spa_types/core';
4
6
 
5
7
  export const useFiltersStore = defineStore('filters', () => {
6
- const filters: Ref<any[]> = ref([]);
7
- const sort: Ref<any> = ref({});
8
+ const filters: Ref<FilterParams[]> = ref([]);
9
+ const sort: Ref<sortType> = ref(null);
8
10
  const coreStore = useCoreStore();
9
11
 
10
- const setSort = (s: any) => {
12
+ const setSort = (s: sortType): void => {
11
13
  sort.value = s;
12
14
  }
13
- const getSort = () => {
15
+ const getSort = (): sortType => {
14
16
  return sort.value;
15
17
  }
16
- const setFilter = (filter: any) => {
18
+ const setFilter = (filter: FilterParams) => {
17
19
  const index = filters.value.findIndex(f => f.field === filter.field);
18
- if (filters.value[index] && filters.value[index].operator === filter.value.operator) {
20
+ if (filters.value[index] && filters.value[index].operator === filter.operator) {
19
21
  filters.value[index] = filter;
20
22
  return;
21
23
  }
22
24
  filters.value.push(filter);
23
25
  }
24
- const setFilters = (f: any) => {
26
+ const setFilters = (f: FilterParams[]) => {
25
27
  filters.value = f;
26
28
  }
27
- const getFilters = () => {
29
+ const getFilters = (): FilterParams[] => {
28
30
  return filters.value;
29
31
  }
30
- const clearFilter = (fieldName: string) => {
32
+ const clearFilter = (fieldName: string): void => {
31
33
  filters.value = filters.value.filter(f => f.field !== fieldName);
32
34
  }
33
- const clearFilters = () => {
35
+ const clearFilters = (): void => {
34
36
  filters.value = [];
35
37
  }
36
38
 
37
- const shouldFilterBeHidden = (fieldName: string) => {
39
+ const shouldFilterBeHidden = (fieldName: string): boolean => {
38
40
  if (coreStore.resource?.columns) {
39
41
  const column = coreStore.resource.columns.find((col: any) => col.name === fieldName);
40
42
  if (column?.showIn?.filter !== true) {
@@ -48,7 +50,7 @@ export const useFiltersStore = defineStore('filters', () => {
48
50
  return filters.value.filter(f => !shouldFilterBeHidden(f.field)).length;
49
51
  });
50
52
 
51
- return {
53
+ const store = {
52
54
  setFilter,
53
55
  getFilters,
54
56
  clearFilters,
@@ -60,4 +62,6 @@ export const useFiltersStore = defineStore('filters', () => {
60
62
  shouldFilterBeHidden,
61
63
  clearFilter
62
64
  }
65
+
66
+ return store as AdminforthFilterStore;
63
67
  })