adminforth 1.1.29 → 1.1.30

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 (41) hide show
  1. package/dist/index.js +0 -1
  2. package/dist/plugins/AccessControl/index.js +3 -56
  3. package/dist/plugins/ForeignInlineListPlugin/custom/InlineList.vue +2 -2
  4. package/dist/plugins/ForeignInlineListPlugin/index.js +0 -1
  5. package/dist/plugins/plugins/ForeignInlineListPlugin/custom/InlineList.vue +248 -0
  6. package/dist/spa/index.html +2 -2
  7. package/dist/spa/package-lock.json +1 -189
  8. package/dist/spa/package.json +1 -6
  9. package/dist/spa/spa/src/components/ResourceListTable.vue +2 -2
  10. package/dist/spa/spa/src/components/ShowTableItem.vue +14 -0
  11. package/dist/spa/spa/src/views/HomeView.vue +8 -0
  12. package/dist/spa/spa/src/views/ListView.vue +2 -2
  13. package/dist/spa/spa/src/views/ShowView.vue +2 -2
  14. package/dist/spa/src/App.vue +57 -76
  15. package/dist/spa/src/components/AcceptModal.vue +1 -1
  16. package/dist/spa/src/components/CustomDatePicker.vue +3 -3
  17. package/dist/spa/src/components/CustomDateRangePicker.vue +3 -3
  18. package/dist/spa/src/components/Dropdown.vue +4 -13
  19. package/dist/spa/src/components/Filters.vue +22 -55
  20. package/dist/spa/src/components/MenuLink.vue +2 -2
  21. package/dist/spa/src/components/ResourceForm.vue +99 -157
  22. package/dist/spa/src/components/ValueRenderer.vue +1 -11
  23. package/dist/spa/src/router/index.ts +2 -3
  24. package/dist/spa/src/stores/core.ts +33 -22
  25. package/dist/spa/src/utils.ts +3 -5
  26. package/dist/spa/src/views/CreateView.vue +7 -15
  27. package/dist/spa/src/views/EditView.vue +8 -36
  28. package/dist/spa/src/views/HomeView.vue +8 -0
  29. package/dist/spa/src/views/ListView.vue +23 -35
  30. package/dist/spa/src/views/LoginView.vue +1 -1
  31. package/dist/spa/src/views/ResourceParent.vue +1 -1
  32. package/dist/spa/src/views/ShowView.vue +9 -20
  33. package/dist/spa/tailwind.config.js +2 -5
  34. package/index.ts +0 -1
  35. package/package.json +1 -1
  36. package/plugins/ForeignInlineListPlugin/custom/InlineList.vue +2 -2
  37. package/plugins/ForeignInlineListPlugin/index.ts +0 -1
  38. package/spa/src/components/ResourceListTable.vue +2 -2
  39. package/spa/src/views/ListView.vue +2 -2
  40. package/spa/src/views/ShowView.vue +2 -2
  41. package/dist/spa/src/components/CustomRangePicker.vue +0 -148
@@ -0,0 +1,14 @@
1
+ <template>
2
+ <td class="px-6 py-4 whitespace-nowrap">
3
+ {{ column.label }}
4
+ </td>
5
+ <td class="px-6 py-4 whitespace-nowrap whitespace-pre-wrap">
6
+ <ValueRenderer :column="column" :row="row" />
7
+ </td>
8
+ </template>
9
+
10
+ <script setup>
11
+ import ValueRenderer from '@/components/ValueRenderer.vue';
12
+
13
+ defineProps(['column', 'row']);
14
+ </script>
@@ -0,0 +1,8 @@
1
+ <script setup lang="ts">
2
+ </script>
3
+
4
+ <template>
5
+ <main>
6
+ 123
7
+ </main>
8
+ </template>
@@ -22,7 +22,7 @@
22
22
  v-if="checkboxes.length"
23
23
  data-tooltip-target="tooltip-remove-all"
24
24
  data-tooltip-placement="bottom"
25
- class="flex gap-1 items-center py-1 px-3 me-2 text-sm font-medium text-gray-900 focus:outline-none bg-white rounded 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"
25
+ class="flex gap-1 items-center py-1 px-3 me-2 text-sm font-medium text-gray-900 focus:outline-none bg-white rounded 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 rounded-default"
26
26
  >
27
27
  <IconBanOutline class="w-5 h-5 "/>
28
28
 
@@ -38,7 +38,7 @@
38
38
  v-for="(action,i) in coreStore.resource?.options?.bulkActions"
39
39
  :key="action.id"
40
40
  @click="startBulkAction(action.id)"
41
- class="flex gap-1 items-center py-1 px-3 text-sm font-medium text-gray-900 focus:outline-none bg-white rounded 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"
41
+ class="flex gap-1 items-center py-1 px-3 text-sm font-medium text-gray-900 focus:outline-none bg-white rounded-default 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"
42
42
  :class="{'bg-red-100 text-red-800 border-red-400 dark:bg-red-700 dark:text-red-400 dark:border-red-400':action.state==='danger', 'bg-green-100 text-green-800 border-green-400 dark:bg-green-700 dark:text-green-400 dark:border-green-400':action.state==='success',
43
43
  'bg-blue-100 text-blue-800 border-blue-400 dark:bg-blue-700 dark:text-blue-400 dark:border-blue-400':action.state==='active',
44
44
  }"
@@ -10,14 +10,14 @@
10
10
  />
11
11
  <BreadcrumbsWithButtons>
12
12
  <RouterLink v-if="coreStore?.resourceOptions?.allowedActions?.edit" :to="{ name: 'resource-edit', params: { resourceId: $route.params.resourceId, primaryKey: $route.params.primaryKey } }"
13
- class="flex items-center py-1 px-3 text-sm font-medium text-gray-900 focus:outline-none bg-white rounded 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"
13
+ class="flex items-center py-1 px-3 text-sm font-medium text-gray-900 focus:outline-none bg-white rounded-default 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"
14
14
  >
15
15
  <IconPenSolid class="w-4 h-4" />
16
16
  Edit
17
17
  </RouterLink>
18
18
 
19
19
  <button v-if="coreStore?.resourceOptions?.allowedActions?.delete" @click="deleteRecord"
20
- class="flex items-center py-1 px-3 text-sm font-medium rounded-default text-red-600 focus:outline-none bg-white rounded border border-gray-300 hover:bg-gray-100 hover:text-red-700 focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-red-500 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700"
20
+ class="flex items-center py-1 px-3 text-sm font-medium rounded-default text-red-600 focus:outline-none bg-white border border-gray-300 hover:bg-gray-100 hover:text-red-700 focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-red-500 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700"
21
21
  >
22
22
  <IconTrashBinSolid class="w-4 h-4" />
23
23
  Delete
@@ -1,84 +1,88 @@
1
1
  <template>
2
2
  <nav
3
3
  v-if="loggedIn"
4
- class="fixed h-14 top-0 z-40 w-full border-b shadow-sm bg-header-bg shadow-header-shadow dark:bg-header-bg-hover dark:border-nav-menu-devider">
4
+
5
+ class="fixed h-14 top-0 z-50 w-full bg-white border-b border-gray-200 dark:bg-gray-800 dark:border-gray-700">
5
6
  <div class="px-3 py-3 lg:px-5 lg:pl-3">
6
7
  <div class="flex items-center justify-between">
7
8
  <div class="flex items-center justify-start rtl:justify-end">
8
- <button data-drawer-target="logo-sidebar" data-drawer-toggle="logo-sidebar" aria-controls="logo-sidebar" type="button" class="inline-flex items-center p-2 text-sm rounded-lg sm:hidden hover:bg-nav-menu-bg-hover focus:outline-none focus:ring-2 focus:ring-nav-menu-devider dark:text-nav-menu-icons dark:hover:bg-nav-menu-bg-hover dark:focus:ring-nav-menu-devider">
9
+ <button data-drawer-target="logo-sidebar" data-drawer-toggle="logo-sidebar" aria-controls="logo-sidebar" type="button" class="inline-flex items-center p-2 text-sm text-gray-500 rounded-lg sm:hidden hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-200 dark:text-gray-400 dark:hover:bg-gray-700 dark:focus:ring-gray-600">
9
10
  <span class="sr-only">Open sidebar</span>
10
11
  <svg class="w-6 h-6" aria-hidden="true" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
11
12
  <path clip-rule="evenodd" fill-rule="evenodd" d="M2 4.75A.75.75 0 012.75 4h14.5a.75.75 0 010 1.5H2.75A.75.75 0 012 4.75zm0 10.5a.75.75 0 01.75-.75h7.5a.75.75 0 010 1.5h-7.5a.75.75 0 01-.75-.75zM2 10a.75.75 0 01.75-.75h14.5a.75.75 0 010 1.5H2.75A.75.75 0 012 10z"></path>
12
13
  </svg>
13
14
  </button>
14
-
15
+ <div class="flex ms-2 md:me-24">
16
+ <img src="https://flowbite.com/docs/images/logo.svg" class="h-8 me-3" alt="FlowBite Logo" />
17
+ <span class="self-center text-xl font-semibold sm:text-2xl whitespace-nowrap dark:text-white">
18
+ {{ coreStore.config?.brandName }}
19
+ </span>
20
+ </div>
15
21
  </div>
16
22
  <div class="flex items-center">
17
- <div class="flex items-center ms-3 ">
18
- <div>
19
- <button type="button" class="flex text-sm bg-header-bg-hover rounded-full focus:ring-4 focus:ring-nav-menu-devider dark:focus:ring-nav-menu-devider dark:bg-header-bg-hover" aria-expanded="false" data-dropdown-toggle="dropdown-user">
20
- <span class="sr-only">Open user menu</span>
21
- <svg class="w-8 h-8 text-nav-menu-icons dark:text-header-icons" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 24 24">
22
- <path fill-rule="evenodd" d="M12 20a7.966 7.966 0 0 1-5.002-1.756l.002.001v-.683c0-1.794 1.492-3.25 3.333-3.25h3.334c1.84 0 3.333 1.456 3.333 3.25v.683A7.966 7.966 0 0 1 12 20ZM2 12C2 6.477 6.477 2 12 2s10 4.477 10 10c0 5.5-4.44 9.963-9.932 10h-.138C6.438 21.962 2 17.5 2 12Zm10-5c-1.84 0-3.333 1.455-3.333 3.25S10.159 13.5 12 13.5c1.84 0 3.333-1.455 3.333-3.25S13.841 7 12 7Z" clip-rule="evenodd"/>
23
- </svg>
24
- </button>
25
- </div>
26
- <div class="z-50 hidden my-4 text-base list-none bg-white divide-y divide-gray-100 rounded shadow dark:shadow-black dark:bg-nav-menu-bg dark:divide-nav-menu-devider dark:shadow-black" id="dropdown-user">
27
- <div class="px-4 py-3" role="none">
28
- <p class="text-sm text-gray-900 dark:text-header-text" role="none" v-if="coreStore.userFullname">
29
- {{ coreStore.userFullname }}
30
- </p>
31
- <p class="text-sm font-medium text-gray-900 truncate dark:text-nav-menu-text" role="none">
32
- {{ coreStore.username }}
33
- </p>
23
+
24
+
25
+ <div class="flex items-center ms-3">
26
+ <div>
27
+ <button type="button" class="flex text-sm bg-gray-100 rounded-full focus:ring-4 focus:ring-gray-300 dark:focus:ring-gray-600 dark:bg-gray-700" aria-expanded="false" data-dropdown-toggle="dropdown-user">
28
+ <span class="sr-only">Open user menu</span>
29
+ <svg class="w-8 h-8 text-gray-400 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 24 24">
30
+ <path fill-rule="evenodd" d="M12 20a7.966 7.966 0 0 1-5.002-1.756l.002.001v-.683c0-1.794 1.492-3.25 3.333-3.25h3.334c1.84 0 3.333 1.456 3.333 3.25v.683A7.966 7.966 0 0 1 12 20ZM2 12C2 6.477 6.477 2 12 2s10 4.477 10 10c0 5.5-4.44 9.963-9.932 10h-.138C6.438 21.962 2 17.5 2 12Zm10-5c-1.84 0-3.333 1.455-3.333 3.25S10.159 13.5 12 13.5c1.84 0 3.333-1.455 3.333-3.25S13.841 7 12 7Z" clip-rule="evenodd"/>
31
+ </svg>
32
+
33
+ </button>
34
34
  </div>
35
- <ul class="py-1" role="none">
36
- <li>
37
- <span @click="toggleTheme" class="cursor-pointer flex items-center gap-1 block px-4 py-2 text-sm text-black hover:bg-html-bg dark:text-nav-menu-text-hover dark:hover:bg-nav-menu-hover dark:hover:text-nav-menu-text-active" role="menuitem">
38
- {{ theme === 'dark' ? 'Light' : 'Dark' }}
39
- <IconMoonSolid class="w-5 h-5 text-blue-300" v-if="theme !== 'dark'" />
40
- <IconSunSolid class="w-5 h-5 text-yellow-300" v-else />
41
- mode
42
- </span>
43
- </li>
44
- <li>
45
- <button @click="logout" class="cursor-pointer flex items-center gap-1 block px-4 py-2 text-sm text-black hover:bg-html-bg dark:text-nav-menu-text-hover dark:hover:bg-nav-menu-hover dark:hover:text-nav-menu-text-active w-full" role="menuitem">Sign out</button>
35
+ <div class="z-50 hidden my-4 text-base list-none bg-white divide-y divide-gray-100 rounded shadow dark:bg-gray-700 dark:divide-gray-600 dark:shadow-xl" id="dropdown-user">
36
+ <div class="px-4 py-3" role="none">
37
+ <p class="text-sm text-gray-900 dark:text-white" role="none" v-if="coreStore.userFullname">
38
+ {{ coreStore.userFullname }}
39
+ </p>
40
+ <p class="text-sm font-medium text-gray-900 truncate dark:text-gray-300" role="none">
41
+ {{ coreStore.username }}
42
+ </p>
43
+ </div>
44
+ <ul class="py-1" role="none">
45
+ <li>
46
+ <a href="#" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-600 dark:hover:text-white" role="menuitem">Dashboard</a>
47
+ </li>
48
+ <li >
49
+ <span @click="toggleTheme" class=" cursor-pointer flex items-center gap-1 block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-600 dark:hover:text-white" role="menuitem">
50
+ {{ theme === 'dark' ? 'Light' : 'Dark' }}
51
+ <IconMoonSolid class="w-5 h-5 text-blue-300
52
+ " v-if="theme !== 'dark'"/>
53
+ <IconSunSolid class="w-5 h-5 text-yellow-300
54
+ " v-else/>
55
+ mode
56
+ </span>
57
+ </li>
58
+
59
+ <li>
60
+ <button @click="logout" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-600 dark:hover:text-white" role="menuitem">Sign out</button>
46
61
  </li>
47
- </ul>
62
+ </ul>
63
+ </div>
48
64
  </div>
49
65
  </div>
50
- </div>
51
66
  </div>
52
67
  </div>
53
- </nav>
54
-
55
-
68
+ </nav>
56
69
 
57
70
  <aside
58
71
  v-if="loggedIn"
59
72
 
60
- id="logo-sidebar" class="fixed border-none top-0 left-0 z-50 w-64 h-screen transition-transform -translate-x-full bg-nav-menu-bg border-r border- sm:translate-x-0 dark:bg-gray-800 dark:border-gray-700" aria-label="Sidebar">
61
- <div class="h-full px-3 pb-4 overflow-y-auto bg-nav-menu-bg dark:bg-gray-800">
62
- <div class="flex ms-2 md:me-24 m-4 ">
63
- <img src="https://flowbite.com/docs/images/logo.svg" class="h-8 me-3" alt="FlowBite Logo" />
64
- <span class="self-center text-header-text-size font-semibold sm:text-header-text-size whitespace-nowrap dark:text-header-text text-header-logo-color">
65
- {{ coreStore.config?.brandName }}
66
- </span>
67
- </div>
73
+ id="logo-sidebar" class="fixed top-0 left-0 z-10 w-64 h-screen pt-20 transition-transform -translate-x-full bg-white border-r border-gray-200 sm:translate-x-0 dark:bg-gray-800 dark:border-gray-700" aria-label="Sidebar">
74
+ <div class="h-full px-3 pb-4 overflow-y-auto bg-white dark:bg-gray-800">
68
75
  <ul class="space-y-2 font-medium">
69
76
  <template v-for="(item, i) in coreStore.menu" :key="`menu-${i}`">
70
- <div v-if="item.type === 'divider'" class="border-t border-nav-menu-devider dark:border-gray-700"></div>
77
+ <div v-if="item.type === 'divider'" class="border-t border-gray-200 dark:border-gray-700"></div>
71
78
  <div v-else-if="item.type === 'gap'" class="flex items-center justify-center h-8"></div>
72
- <div v-else-if="item.type === 'heading'" class="flex items-center justify-left pl-2 h-8 text-gray-400 dark:text-gray-400
73
- ">{{ item.label }}</div>
74
-
75
79
 
76
80
  <li v-else-if="item.children">
77
- <button type="button" class="flex items-center w-full p-2 text-base text-nav-menu-text rounded-default transition duration-75 group hover:bg-nav-menu-bg-hover dark:text-white dark:hover:bg-gray-700"
81
+ <button type="button" class="flex items-center w-full p-2 text-base text-gray-900 transition duration-75 rounded-lg group hover:bg-gray-100 dark:text-white dark:hover:bg-gray-700"
78
82
  :aria-controls="`dropdown-example${i}`"
79
83
  :data-collapse-toggle="`dropdown-example${i}`"
80
84
  >
81
- <component v-if="item.icon" :is="getIcon(item.icon)" class="w-5 h-5 text-gray-500 transition duration-75 dark:text-gray-400 dark:group-hover:text-white" ></component>
85
+ <component v-if="item.icon" :is="getIcon(item.icon)" class="w-5 h-5 text-gray-500 transition duration-75 dark:text-gray-400 group-hover:text-gray-900 dark:group-hover:text-white" ></component>
82
86
 
83
87
  <span class="flex-1 ms-3 text-left rtl:text-right whitespace-nowrap">{{ item.label }}</span>
84
88
  <svg class="w-3 h-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 10 6">
@@ -86,7 +90,7 @@
86
90
  </svg>
87
91
  </button>
88
92
 
89
- <ul :id="`dropdown-example${i}`" role="none" class="pt-1 space-y-1" :class="{ 'hidden': !item.open }">
93
+ <ul :id="`dropdown-example${i}`" role="none" class="py-2 space-y-2" :class="{ 'hidden': !item.open }">
90
94
  <template v-for="(child, j) in item.children" :key="`menu-${i}-${j}`">
91
95
  <li>
92
96
  <MenuLink :item="child" isChild="true" />
@@ -108,7 +112,7 @@
108
112
  </div>
109
113
  </div>
110
114
 
111
- <div v-else-if="routerIsReady">
115
+ <div v-else>
112
116
  <RouterView/>
113
117
  </div>
114
118
  <AcceptModal />
@@ -128,23 +132,10 @@ import AcceptModal from './components/AcceptModal.vue';
128
132
  import MenuLink from './components/MenuLink.vue';
129
133
  import { useRoute, useRouter } from 'vue-router';
130
134
  import { getIcon } from '@/utils';
131
- import { useHead } from 'unhead'
132
- import { createHead } from 'unhead'
133
- // import { link } from 'fs';
134
- const coreStore = useCoreStore();
135
-
136
-
137
- createHead()
138
-
139
-
140
-
141
-
142
135
 
143
136
 
144
137
  const route = useRoute();
145
138
  const router = useRouter();
146
- const title = ref('');
147
-
148
139
 
149
140
  const routerIsReady = ref(false);
150
141
 
@@ -162,6 +153,7 @@ async function logout() {
162
153
  router.push({ name: 'login' });
163
154
  }
164
155
 
156
+ const coreStore = useCoreStore();
165
157
 
166
158
 
167
159
 
@@ -175,17 +167,6 @@ onMounted(async () => {
175
167
  initRouter();
176
168
  initFlowbite();
177
169
  await coreStore.fetchMenuAndResource();
178
- title.value = coreStore.config.title || 'Admin Forth';
179
- useHead({
180
- title: title.value,
181
- link: [
182
- {
183
- rel: 'icon',
184
- href: coreStore.config.favicon || '/favicon.ico',
185
- },
186
- ],
187
-
188
- })
189
170
  })
190
171
 
191
172
  </script>
@@ -16,7 +16,7 @@ const modalStore = useModalStore();
16
16
  <Teleport to="body">
17
17
  <div v-if="modalStore.isOpened" class="bg-gray-900/50 dark:bg-gray-900/80 overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-50 justify-center items-center w-full md:inset-0 h-[calc(100%-1rem)] max-h-full">
18
18
  <div class="relative p-4 w-full max-w-md max-h-full top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 " >
19
- <div class="relative bg-white rounded-lg shadow dark:bg-gray-700 dark:shadow-black">
19
+ <div class="relative bg-white rounded-lg shadow dark:bg-gray-700">
20
20
  <button type="button"@click="modalStore.togleModal" class="absolute top-3 end-2.5 text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm w-8 h-8 ms-auto inline-flex justify-center items-center dark:hover:bg-gray-600 dark:hover:text-white" >
21
21
  <svg class="w-3 h-3" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14">
22
22
  <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6"/>
@@ -5,7 +5,7 @@
5
5
  <label for="start-time" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">{{ label }}</label>
6
6
 
7
7
  <div class="relative">
8
- <div class="absolute inset-y-0 end-0 top-0 flex items-center pe-3.5 pointer-events-none">
8
+ <div class="absolute inset-y-0 end-0 top-0 flex items-center pe-3.5">
9
9
  <IconCalendar class="w-4 h-4 text-gray-500 dark:text-gray-400"/>
10
10
  </div>
11
11
 
@@ -97,7 +97,7 @@ const start = computed(() => {
97
97
  })
98
98
 
99
99
  function updateFromProps() {
100
- if (!props.valueStart) {
100
+ if (props.valueStart === undefined) {
101
101
  datepickerStartEl.value.value = '';
102
102
  startTime.value = '';
103
103
  }
@@ -157,5 +157,5 @@ onMounted(() => {
157
157
 
158
158
  onBeforeUnmount(() => {
159
159
  removeChangeDateListener();
160
- });
160
+ })
161
161
  </script>
@@ -26,7 +26,7 @@
26
26
  <div class="mx-auto grid grid-cols-2 gap-4 mb-2" :class="{hidden: !showTimeInputs}">
27
27
  <div>
28
28
  <div class="relative">
29
- <div class="absolute inset-y-0 end-0 top-0 flex items-center pe-3.5 pointer-events-none">
29
+ <div class="absolute inset-y-0 end-0 top-0 flex items-center pe-3.5">
30
30
  <IconTime class="w-4 h-4 text-gray-500 dark:text-gray-400 bg-white dark:bg-gray-700"/>
31
31
  </div>
32
32
 
@@ -132,11 +132,11 @@ const end = computed(() => {
132
132
  })
133
133
 
134
134
  function updateFromProps() {
135
- if (!props.valueStart) {
135
+ if (props.valueStart === undefined) {
136
136
  datepickerStartEl.value.value = '';
137
137
  startTime.value = '';
138
138
  }
139
- if (!props.valueEnd) {
139
+ if (props.valueEnd === undefined) {
140
140
  datepickerEndEl.value.value = '';
141
141
  endTime.value = '';
142
142
  }
@@ -9,8 +9,7 @@
9
9
  :placeholder="selectedItems.length ? '' : 'Select...'"
10
10
  />
11
11
  <div class="absolute inset-y-0 left-2 flex items-center pr-2 flex-wrap">
12
- {{ }}
13
- <div v-for="item in selectedItems" :key="item?.name" class="bg-blue-100 text-blue-800 text-xs font-medium me-2 px-2.5 py-0.5 rounded dark:bg-blue-900 dark:text-blue-300">
12
+ <div v-for="item in selectedItems" :key="item.name" class="bg-blue-100 text-blue-800 text-xs font-medium me-2 px-2.5 py-0.5 rounded dark:bg-blue-900 dark:text-blue-300">
14
13
  <span>{{ item.label }}</span>
15
14
  <button
16
15
  type="button"
@@ -35,7 +34,7 @@
35
34
  <IconCaretUpSolid v-else class="h-5 w-5 text-gray-400" />
36
35
  </div>
37
36
  </div>
38
- <div v-if="showDropdown" class="absolute z-10 mt-1 w-full bg-white shadow-lg dark:shadow-black rounded-md py-1 text-base ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm">
37
+ <div v-if="showDropdown" class="absolute z-10 mt-1 w-full bg-white shadow-lg rounded-md py-1 text-base ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm">
39
38
  <div
40
39
  v-for="item in filteredItems"
41
40
  :key="item.value"
@@ -77,14 +76,10 @@ const showDropdown = ref(false);
77
76
  const selectedItems = ref([]);
78
77
 
79
78
  function updateFromProps() {
79
+ console.log('⚡ updateFromProps', props.modelValue)
80
80
  if (props.modelValue !== undefined) {
81
81
  if (props.single) {
82
- const el = props.options.find(item => item.value === props.modelValue);
83
- if (el) {
84
- selectedItems.value = [el];
85
- } else {
86
- selectedItems.value = [];
87
- }
82
+ selectedItems.value = [props.options.find(item => item.value === props.modelValue)];
88
83
  } else {
89
84
  selectedItems.value = props.options.filter(item => props.modelValue.includes(item.value));
90
85
  }
@@ -98,10 +93,6 @@ onMounted(() => {
98
93
  updateFromProps();
99
94
  });
100
95
 
101
- watch(() => props.options, () => {
102
- updateFromProps();
103
- });
104
-
105
96
  addClickListener();
106
97
 
107
98
  });
@@ -2,7 +2,7 @@
2
2
  <!-- drawer component -->
3
3
  <div id="drawer-navigation"
4
4
 
5
- class="fixed top-14 right-0 z-40 p-4 overflow-y-auto transition-transform translate-x-full bg-white w-80 dark:bg-gray-800 shadow-xl dark:shadow-black"
5
+ class="fixed top-14 right-0 z-40 p-4 overflow-y-auto transition-transform translate-x-full bg-white w-80 dark:bg-gray-800 shadow-xl"
6
6
 
7
7
  :class="show ? 'top-0 transform-none' : ''"
8
8
  tabindex="-1" aria-labelledby="drawer-navigation-label"
@@ -22,14 +22,8 @@
22
22
  <li v-for="c in columnsWithFilter" :key="c">
23
23
  <p class="dark:text-gray-400">{{ c.label }}</p>
24
24
 
25
- <Dropdown
26
- v-if="c.foreignResource"
27
- :options="columnOptions[c.name] || []"
28
- @update:modelValue="setFilterItem({ column: c, operator: 'in', value: $event })"
29
- :modelValue="filters.find(f => f.field === c.name && f.operator === 'in')?.value || []"
30
- />
31
- <Dropdown
32
- v-else-if="c.type === 'boolean'"
25
+ <Dropdown
26
+ v-if="c.type === 'boolean'"
33
27
  :options="[{ label: 'Yes', value: true }, { label: 'No', value: false }, { label: 'Unset', value: null }]"
34
28
  @update:modelValue="setFilterItem({ column: c, operator: 'in', value: $event })"
35
29
  :modelValue="filters.find(f => f.field === c.name && f.operator === 'in')?.value || []"
@@ -68,15 +62,22 @@
68
62
  :value="getFilterItem({ column: c, operator: 'ilike' })"
69
63
  >
70
64
 
71
- <CustomRangePicker
72
- v-else-if="['integer', 'decimal', 'float'].includes(c.type)"
73
- :min="c.min"
74
- :max="c.max"
75
- :valueStart="getFilterItem({ column: c, operator: 'gte' })"
76
- @update:valueStart="setFilterItem({ column: c, operator: 'gte', value: $event || undefined })"
77
- :valueEnd="getFilterItem({ column: c, operator: 'lte' })"
78
- @update:valueEnd="setFilterItem({ column: c, operator: 'lte', value: $event || undefined })"
79
- />
65
+ <div v-else-if="['integer', 'decimal', 'float'].includes(c.type)" class="flex gap-2">
66
+ <input
67
+ type="number" aria-describedby="helper-text-explanation"
68
+ class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-20 p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
69
+ placeholder="From"
70
+ @input="setFilterItem({ column: c, operator: 'gte', value: $event.target.value || undefined })"
71
+ :value="getFilterItem({ column: c, operator: 'gte' })"
72
+ >
73
+ <input
74
+ type="number" aria-describedby="helper-text-explanation"
75
+ class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-20 p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
76
+ placeholder="To"
77
+ @input="setFilterItem({ column: c, operator: 'lte', value: $event.target.value || undefined})"
78
+ :value="getFilterItem({ column: c, operator: 'lte' })"
79
+ >
80
+ </div>
80
81
 
81
82
  </li>
82
83
  </ul>
@@ -92,59 +93,25 @@
92
93
  </div>
93
94
  </div>
94
95
 
95
- <div v-if="show" drawer-backdrop="" class="bg-gray-900/50 dark:bg-gray-900/80 fixed inset-0 z-50"
96
+ <div v-if="show" drawer-backdrop="" class="bg-gray-900/50 dark:bg-gray-900/80 fixed inset-0 z-30"
96
97
  @click="$emit('hide')">
97
98
  </div>
98
99
  </template>
99
100
 
100
101
  <script setup>
101
- import { watch, computed, ref, onMounted } from 'vue'
102
+ import { watch, computed } from 'vue'
102
103
  import Dropdown from '@/components/Dropdown.vue';
103
104
  import CustomDateRangePicker from '@/components/CustomDateRangePicker.vue';
104
- import { callAdminForthApi } from '@/utils';
105
- import { useRouter } from 'vue-router';
106
- import { computedAsync } from '@vueuse/core'
107
- import CustomRangePicker from "@/components/CustomRangePicker.vue";
108
105
 
109
106
  // props: columns
110
107
  // add support for v-model:filers
111
108
  const props = defineProps(['columns', 'filters', 'show', 'columnsMinMax']);
112
109
  const emits = defineEmits(['update:filters', 'hide']);
113
110
 
114
- const router = useRouter();
115
-
116
-
117
- const columnsWithFilter = computed(
111
+ const columnsWithFilter = computed(
118
112
  () => props.columns?.filter(column => column.showIn.includes('filter')) || []
119
113
  );
120
114
 
121
- const columnOptions = computedAsync(async () => {
122
- const ret = {};
123
- if (!props.columns) {
124
- return ret;
125
- }
126
- await Promise.all(
127
- Object.values(props.columns).map(async (column) => {
128
- if (column.foreignResource) {
129
- const list = await callAdminForthApi({
130
- method: 'POST',
131
- path: `/get_resource_foreign_data`,
132
- body: {
133
- resourceId: router.currentRoute.value.params.resourceId,
134
- column: column.name,
135
- limit: 1000,
136
- offset: 0,
137
- },
138
- });
139
- ret[column.name] = list.items;
140
- }
141
- })
142
- );
143
-
144
- return ret;
145
- }, {});
146
-
147
-
148
115
  // sync 'body' class 'overflow-hidden' with show prop show
149
116
  watch(() => props.show, (show) => {
150
117
  if (show) {
@@ -1,11 +1,11 @@
1
1
  <template>
2
2
  <RouterLink
3
3
  :to="{name: item.resourceId ? 'resource-list' : item.path, params: item.resourceId ? { resourceId: item.resourceId }: {}}"
4
- class="flex items-center py-2 text-nav-menu-text rounded-default hover:bg-nav-menu-bg-hover active:bg-nav-menu-bg-active" role="menuitem"
4
+ class="flex items-center py-2 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-600 dark:hover:text-white" role="menuitem"
5
5
  :class="{
6
6
  'px-4': isChild,
7
7
  'px-2': !isChild,
8
- 'bg-nav-menu-bg-active dark:bg-gray-700': item.resourceId ?
8
+ 'bg-blue-100 dark:bg-gray-700': item.resourceId ?
9
9
  ($route.params.resourceId === item.resourceId && $route.name === 'resource-list') :
10
10
  ($route.name === item.path)
11
11
  }"