adminforth 2.4.0-next.33 → 2.4.0-next.331
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.
- package/commands/callTsProxy.js +14 -4
- package/commands/createApp/templates/api.ts.hbs +10 -0
- package/commands/createApp/templates/custom/tsconfig.json.hbs +2 -3
- package/commands/createApp/templates/index.ts.hbs +12 -1
- package/commands/createApp/templates/package.json.hbs +1 -1
- package/commands/createApp/templates/prisma.config.ts.hbs +8 -0
- package/commands/createApp/templates/schema.prisma.hbs +0 -1
- package/commands/createApp/utils.js +10 -0
- package/commands/createCustomComponent/configLoader.js +17 -4
- package/commands/createCustomComponent/main.js +13 -7
- package/commands/createCustomComponent/templates/customCrud/beforeActionButtons.vue.hbs +38 -0
- package/commands/createCustomComponent/templates/customCrud/saveButton.vue.hbs +28 -0
- package/commands/createPlugin/templates/custom/tsconfig.json.hbs +2 -5
- package/commands/createPlugin/templates/package.json.hbs +1 -1
- package/commands/generateModels.js +30 -22
- package/dist/auth.d.ts +9 -1
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +21 -2
- package/dist/auth.js.map +1 -1
- package/dist/dataConnectors/baseConnector.d.ts +1 -1
- package/dist/dataConnectors/baseConnector.d.ts.map +1 -1
- package/dist/dataConnectors/baseConnector.js +70 -18
- package/dist/dataConnectors/baseConnector.js.map +1 -1
- package/dist/dataConnectors/clickhouse.d.ts.map +1 -1
- package/dist/dataConnectors/clickhouse.js +15 -0
- package/dist/dataConnectors/clickhouse.js.map +1 -1
- package/dist/dataConnectors/mongo.d.ts.map +1 -1
- package/dist/dataConnectors/mongo.js +50 -15
- package/dist/dataConnectors/mongo.js.map +1 -1
- package/dist/dataConnectors/mysql.d.ts.map +1 -1
- package/dist/dataConnectors/mysql.js +11 -0
- package/dist/dataConnectors/mysql.js.map +1 -1
- package/dist/dataConnectors/postgres.d.ts.map +1 -1
- package/dist/dataConnectors/postgres.js +43 -14
- package/dist/dataConnectors/postgres.js.map +1 -1
- package/dist/dataConnectors/sqlite.d.ts.map +1 -1
- package/dist/dataConnectors/sqlite.js +11 -0
- package/dist/dataConnectors/sqlite.js.map +1 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +44 -21
- package/dist/index.js.map +1 -1
- package/dist/modules/codeInjector.d.ts +2 -0
- package/dist/modules/codeInjector.d.ts.map +1 -1
- package/dist/modules/codeInjector.js +62 -6
- package/dist/modules/codeInjector.js.map +1 -1
- package/dist/modules/configValidator.d.ts +6 -0
- package/dist/modules/configValidator.d.ts.map +1 -1
- package/dist/modules/configValidator.js +209 -25
- package/dist/modules/configValidator.js.map +1 -1
- package/dist/modules/restApi.d.ts +1 -1
- package/dist/modules/restApi.d.ts.map +1 -1
- package/dist/modules/restApi.js +199 -31
- package/dist/modules/restApi.js.map +1 -1
- package/dist/modules/styles.d.ts +499 -13
- package/dist/modules/styles.d.ts.map +1 -1
- package/dist/modules/styles.js +555 -31
- package/dist/modules/styles.js.map +1 -1
- package/dist/modules/utils.d.ts +7 -15
- package/dist/modules/utils.d.ts.map +1 -1
- package/dist/modules/utils.js +45 -68
- package/dist/modules/utils.js.map +1 -1
- package/dist/servers/express.d.ts +5 -0
- package/dist/servers/express.d.ts.map +1 -1
- package/dist/servers/express.js +40 -1
- package/dist/servers/express.js.map +1 -1
- package/dist/spa/index.html +1 -1
- package/dist/spa/package-lock.json +1208 -708
- package/dist/spa/package.json +34 -34
- package/dist/spa/src/App.vue +132 -174
- package/dist/spa/src/adminforth.ts +41 -17
- package/dist/spa/src/afcl/AreaChart.vue +0 -1
- package/dist/spa/src/afcl/BarChart.vue +2 -2
- package/dist/spa/src/afcl/Button.vue +3 -3
- package/dist/spa/src/afcl/ButtonGroup.vue +91 -0
- package/dist/spa/src/afcl/Card.vue +25 -0
- package/dist/spa/src/afcl/Checkbox.vue +21 -13
- package/dist/spa/src/afcl/CountryFlag.vue +4 -1
- package/dist/spa/src/{components/CustomDatePicker.vue → afcl/DatePicker.vue} +95 -9
- package/dist/spa/src/afcl/Dialog.vue +47 -27
- package/dist/spa/src/afcl/Dropzone.vue +145 -48
- package/dist/spa/src/afcl/Input.vue +14 -6
- package/dist/spa/src/afcl/JsonViewer.vue +25 -0
- package/dist/spa/src/afcl/LinkButton.vue +3 -3
- package/dist/spa/src/afcl/PieChart.vue +5 -5
- package/dist/spa/src/afcl/ProgressBar.vue +7 -7
- package/dist/spa/src/afcl/Select.vue +82 -34
- package/dist/spa/src/afcl/Skeleton.vue +6 -6
- package/dist/spa/src/afcl/Table.vue +313 -75
- package/dist/spa/src/afcl/Textarea.vue +31 -0
- package/dist/spa/src/afcl/Toggle.vue +32 -0
- package/dist/spa/src/afcl/Tooltip.vue +28 -18
- package/dist/spa/src/afcl/VerticalTabs.vue +21 -7
- package/dist/spa/src/afcl/index.ts +6 -3
- package/dist/spa/src/components/AcceptModal.vue +48 -14
- package/dist/spa/src/components/Breadcrumbs.vue +5 -5
- package/dist/spa/src/components/CallActionWrapper.vue +15 -0
- package/dist/spa/src/components/ColumnValueInput.vue +38 -18
- package/dist/spa/src/components/ColumnValueInputWrapper.vue +4 -3
- package/dist/spa/src/components/CustomDateRangePicker.vue +9 -8
- package/dist/spa/src/components/CustomRangePicker.vue +37 -21
- package/dist/spa/src/components/ErrorMessage.vue +21 -0
- package/dist/spa/src/components/Filters.vue +195 -132
- package/dist/spa/src/components/GroupsTable.vue +9 -8
- package/dist/spa/src/components/MenuLink.vue +95 -23
- package/dist/spa/src/components/ResourceForm.vue +99 -51
- package/dist/spa/src/components/ResourceListTable.vue +121 -95
- package/dist/spa/src/components/ResourceListTableVirtual.vue +119 -88
- package/dist/spa/src/components/ShowTable.vue +21 -15
- package/dist/spa/src/components/Sidebar.vue +472 -0
- package/dist/spa/src/components/SingleSkeletLoader.vue +6 -6
- package/dist/spa/src/components/SkeleteLoader.vue +3 -3
- package/dist/spa/src/components/ThreeDotsMenu.vue +84 -15
- package/dist/spa/src/components/Toast.vue +40 -29
- package/dist/spa/src/components/UserMenuSettingsButton.vue +69 -0
- package/dist/spa/src/components/ValueRenderer.vue +44 -17
- package/dist/spa/src/controls/BoolToggle.vue +34 -0
- package/dist/spa/src/i18n.ts +5 -3
- package/dist/spa/src/main.ts +1 -1
- package/dist/spa/src/renderers/CompactField.vue +1 -1
- package/dist/spa/src/renderers/CompactUUID.vue +1 -1
- package/dist/spa/src/router/index.ts +8 -0
- package/dist/spa/src/shims-vue.d.ts +5 -0
- package/dist/spa/src/spa_types/core.ts +13 -1
- package/dist/spa/src/stores/core.ts +15 -1
- package/dist/spa/src/stores/filters.ts +33 -2
- package/dist/spa/src/stores/modal.ts +6 -1
- package/dist/spa/src/stores/toast.ts +22 -3
- package/dist/spa/src/types/Back.ts +168 -23
- package/dist/spa/src/types/Common.ts +109 -32
- package/dist/spa/src/types/FrontendAPI.ts +32 -23
- package/dist/spa/src/types/adapters/CaptchaAdapter.ts +34 -0
- package/dist/spa/src/types/adapters/EmailAdapter.ts +2 -4
- package/dist/spa/src/types/adapters/ImageVisionAdapter.ts +30 -0
- package/dist/spa/src/types/adapters/KeyValueAdapter.ts +16 -0
- package/dist/spa/src/types/adapters/StorageAdapter.ts +4 -2
- package/dist/spa/src/types/adapters/index.ts +3 -0
- package/dist/spa/src/utils.ts +291 -11
- package/dist/spa/src/views/CreateView.vue +88 -22
- package/dist/spa/src/views/EditView.vue +55 -22
- package/dist/spa/src/views/ListView.vue +144 -87
- package/dist/spa/src/views/LoginView.vue +26 -35
- package/dist/spa/src/views/ResourceParent.vue +2 -2
- package/dist/spa/src/views/SettingsView.vue +121 -0
- package/dist/spa/src/views/ShowView.vue +83 -53
- package/dist/spa/src/websocket.ts +6 -1
- package/dist/spa/tsconfig.app.json +1 -1
- package/dist/spa/vite.config.ts +45 -2
- package/dist/types/Back.d.ts +151 -14
- package/dist/types/Back.d.ts.map +1 -1
- package/dist/types/Back.js +15 -0
- package/dist/types/Back.js.map +1 -1
- package/dist/types/Common.d.ts +123 -29
- package/dist/types/Common.d.ts.map +1 -1
- package/dist/types/Common.js.map +1 -1
- package/dist/types/FrontendAPI.d.ts +32 -18
- package/dist/types/FrontendAPI.d.ts.map +1 -1
- package/dist/types/FrontendAPI.js.map +1 -1
- package/dist/types/adapters/CaptchaAdapter.d.ts +30 -0
- package/dist/types/adapters/CaptchaAdapter.d.ts.map +1 -0
- package/dist/types/adapters/CaptchaAdapter.js +5 -0
- package/dist/types/adapters/CaptchaAdapter.js.map +1 -0
- package/dist/types/adapters/EmailAdapter.d.ts +2 -3
- package/dist/types/adapters/EmailAdapter.d.ts.map +1 -1
- package/dist/types/adapters/ImageVisionAdapter.d.ts +25 -0
- package/dist/types/adapters/ImageVisionAdapter.d.ts.map +1 -0
- package/dist/types/adapters/ImageVisionAdapter.js +2 -0
- package/dist/types/adapters/ImageVisionAdapter.js.map +1 -0
- package/dist/types/adapters/KeyValueAdapter.d.ts +10 -0
- package/dist/types/adapters/KeyValueAdapter.d.ts.map +1 -0
- package/dist/types/adapters/KeyValueAdapter.js +2 -0
- package/dist/types/adapters/KeyValueAdapter.js.map +1 -0
- package/dist/types/adapters/StorageAdapter.d.ts +2 -0
- package/dist/types/adapters/StorageAdapter.d.ts.map +1 -1
- package/dist/types/adapters/index.d.ts +3 -0
- package/dist/types/adapters/index.d.ts.map +1 -1
- package/package.json +4 -2
package/dist/spa/package.json
CHANGED
|
@@ -10,50 +10,50 @@
|
|
|
10
10
|
"build-only": "vite build",
|
|
11
11
|
"type-check": "vue-tsc --build --force",
|
|
12
12
|
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
|
|
13
|
-
"i18n:extract": "echo {} > i18n-empty.json && vue-i18n-extract report --vueFiles \"./src/**/*.{js,vue}\" --output ./i18n-messages.json --languageFiles \"i18n-empty.json\" --add"
|
|
13
|
+
"i18n:extract": "echo {} > i18n-empty.json && vue-i18n-extract report --vueFiles \"./src/**/*.{js,vue,ts}\" --output ./i18n-messages.json --languageFiles \"i18n-empty.json\" --add"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@iconify-prerendered/vue-flag": "^0.28.
|
|
17
|
-
"@iconify-prerendered/vue-flowbite": "^0.
|
|
18
|
-
"@unhead/vue": "^1.
|
|
19
|
-
"@vueuse/core": "^10.
|
|
16
|
+
"@iconify-prerendered/vue-flag": "^0.28.1754899047",
|
|
17
|
+
"@iconify-prerendered/vue-flowbite": "^0.28.1754899090",
|
|
18
|
+
"@unhead/vue": "^1.11.20",
|
|
19
|
+
"@vueuse/core": "^10.11.1",
|
|
20
20
|
"apexcharts": "^4.7.0",
|
|
21
|
-
"dayjs": "^1.11.
|
|
22
|
-
"debounce": "^2.
|
|
23
|
-
"flowbite-datepicker": "^1.2
|
|
24
|
-
"javascript-time-ago": "^2.5.
|
|
25
|
-
"pinia": "^2.1
|
|
26
|
-
"sanitize-html": "^2.
|
|
27
|
-
"unhead": "^1.
|
|
21
|
+
"dayjs": "^1.11.19",
|
|
22
|
+
"debounce": "^2.2.0",
|
|
23
|
+
"flowbite-datepicker": "^1.3.2",
|
|
24
|
+
"javascript-time-ago": "^2.5.12",
|
|
25
|
+
"pinia": "^2.3.1",
|
|
26
|
+
"sanitize-html": "^2.17.0",
|
|
27
|
+
"unhead": "^1.11.20",
|
|
28
28
|
"uuid": "^10.0.0",
|
|
29
|
-
"vue": "^3.5.
|
|
29
|
+
"vue": "^3.5.22",
|
|
30
30
|
"vue-diff": "^1.2.4",
|
|
31
|
-
"vue-i18n": "^10.0.
|
|
32
|
-
"vue-router": "^4.3
|
|
31
|
+
"vue-i18n": "^10.0.8",
|
|
32
|
+
"vue-router": "^4.6.3",
|
|
33
33
|
"vue-slider-component": "^4.1.0-beta.7"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
|
-
"@rushstack/eslint-patch": "^1.
|
|
37
|
-
"@tsconfig/node20": "^20.1.
|
|
38
|
-
"@types/node": "^20.
|
|
39
|
-
"@vitejs/plugin-vue": "^5.
|
|
36
|
+
"@rushstack/eslint-patch": "^1.14.1",
|
|
37
|
+
"@tsconfig/node20": "^20.1.6",
|
|
38
|
+
"@types/node": "^20.19.24",
|
|
39
|
+
"@vitejs/plugin-vue": "^5.2.4",
|
|
40
40
|
"@vue/eslint-config-typescript": "^13.0.0",
|
|
41
|
-
"@vue/tsconfig": "^0.
|
|
42
|
-
"autoprefixer": "^10.4.
|
|
43
|
-
"eslint": "^8.57.
|
|
44
|
-
"eslint-plugin-vue": "^9.
|
|
45
|
-
"flag-icons": "^7.
|
|
41
|
+
"@vue/tsconfig": "^0.8.1",
|
|
42
|
+
"autoprefixer": "^10.4.21",
|
|
43
|
+
"eslint": "^8.57.1",
|
|
44
|
+
"eslint-plugin-vue": "^9.33.0",
|
|
45
|
+
"flag-icons": "^7.5.0",
|
|
46
46
|
"flowbite": "^3.1.2",
|
|
47
|
-
"i18n-iso-countries": "^7.
|
|
48
|
-
"npm-run-all2": "^6.
|
|
49
|
-
"portfinder": "^1.0.
|
|
50
|
-
"postcss": "^8.
|
|
51
|
-
"sass": "^1.
|
|
52
|
-
"tailwindcss": "^3.4.
|
|
53
|
-
"typescript": "~5.
|
|
54
|
-
"vite": "^5.
|
|
47
|
+
"i18n-iso-countries": "^7.14.0",
|
|
48
|
+
"npm-run-all2": "^6.2.6",
|
|
49
|
+
"portfinder": "^1.0.38",
|
|
50
|
+
"postcss": "^8.5.6",
|
|
51
|
+
"sass": "^1.93.3",
|
|
52
|
+
"tailwindcss": "^3.4.18",
|
|
53
|
+
"typescript": "~5.9.3",
|
|
54
|
+
"vite": "^5.4.21",
|
|
55
55
|
"vue-i18n-extract": "^2.0.7",
|
|
56
|
-
"vue-tsc": "^2.
|
|
57
|
-
"vue3-json-viewer": "^2.
|
|
56
|
+
"vue-tsc": "^2.2.12",
|
|
57
|
+
"vue3-json-viewer": "^2.4.1"
|
|
58
58
|
}
|
|
59
59
|
}
|
package/dist/spa/src/App.vue
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
<div>
|
|
3
3
|
<nav
|
|
4
4
|
v-if="loggedIn && routerIsReady && loginRedirectCheckIsReady && defaultLayout"
|
|
5
|
-
class="fixed h-14 top-0 z-
|
|
5
|
+
class="fixed h-14 top-0 z-30 w-full border-b shadow-sm bg-lightNavbar shadow-headerShadow dark:bg-darkNavbar dark:border-darkSidebarDevider"
|
|
6
6
|
>
|
|
7
|
-
<div class="px-3 lg:px-5 lg:pl-3 flex items-center justify-between h-full w-full" >
|
|
7
|
+
<div class="af-header px-3 lg:px-5 lg:pl-3 flex items-center justify-between h-full w-full" >
|
|
8
8
|
<div class="flex items-center justify-start rtl:justify-end">
|
|
9
9
|
<button @click="sideBarOpen = !sideBarOpen"
|
|
10
10
|
type="button" class="inline-flex items-center p-2 text-sm rounded-lg sm:hidden hover:bg-lightSidebarItemHover focus:outline-none focus:ring-2 focus:ring-lightSidebarDevider dark:text-darkSidebarIcons dark:hover:bg-darkSidebarHover dark:focus:ring-lightSidebarDevider">
|
|
@@ -24,8 +24,9 @@
|
|
|
24
24
|
/>
|
|
25
25
|
|
|
26
26
|
<div class="flex items-center ms-3 ">
|
|
27
|
-
<span
|
|
28
|
-
|
|
27
|
+
<span
|
|
28
|
+
v-if="!coreStore.config?.singleTheme"
|
|
29
|
+
@click="toggleTheme" class="cursor-pointer flex items-center gap-1 block px-4 py-2 text-sm text-black dark:text-darkSidebarTextHover dark:hover:text-darkSidebarTextActive" role="menuitem">
|
|
29
30
|
<IconMoonSolid class="w-5 h-5 text-blue-300" v-if="coreStore.theme !== 'dark'" />
|
|
30
31
|
<IconSunSolid class="w-5 h-5 text-yellow-300" v-else />
|
|
31
32
|
</span>
|
|
@@ -40,7 +41,7 @@
|
|
|
40
41
|
</button>
|
|
41
42
|
</div>
|
|
42
43
|
|
|
43
|
-
<div class="z-50 hidden my-4 text-base list-none bg-
|
|
44
|
+
<div class="z-50 hidden my-4 text-base list-none bg-lightUserMenuBackground divide-y divide-lightUserMenuBorder text-lightUserMenuText rounded shadow dark:shadow-black dark:bg-darkUserMenuBackground dark:divide-darkUserMenuBorder text-darkUserMenuText dark:shadow-black" id="dropdown-user">
|
|
44
45
|
<div class="px-4 py-3" role="none">
|
|
45
46
|
<p class="text-sm text-gray-900 dark:text-darkNavbarText" role="none" v-if="coreStore.userFullname">
|
|
46
47
|
{{ coreStore.userFullname }}
|
|
@@ -51,15 +52,18 @@
|
|
|
51
52
|
</div>
|
|
52
53
|
|
|
53
54
|
<ul class="py-1" role="none">
|
|
54
|
-
<li v-for="c in
|
|
55
|
+
<li v-for="c in userMenuComponents" class="bg-lightUserMenuItemBackground hover:bg-lightUserMenuItemBackgroundHover text-lightUserMenuItemText hover:text-lightUserMenuItemText dark:bg-darkUserMenuItemBackground dark:hover:bg-darkUserMenuItemBackgroundHover dark:text-darkUserMenuItemText dark:hover:darkUserMenuItemTextHover" >
|
|
55
56
|
<component
|
|
56
57
|
:is="getCustomComponent(c)"
|
|
57
58
|
:meta="c.meta"
|
|
58
59
|
:adminUser="coreStore.adminUser"
|
|
59
60
|
/>
|
|
60
61
|
</li>
|
|
62
|
+
<li v-if="coreStore?.config?.settingPages && coreStore.config.settingPages.length > 0">
|
|
63
|
+
<UserMenuSettingsButton />
|
|
64
|
+
</li>
|
|
61
65
|
<li>
|
|
62
|
-
<button @click="logout" class="cursor-pointer flex items-center gap-1 block px-4 py-2 text-sm
|
|
66
|
+
<button @click="logout" class="cursor-pointer flex items-center gap-1 block px-4 py-2 text-sm bg-lightUserMenuItemBackground hover:bg-lightUserMenuItemBackgroundHover text-lightUserMenuItemText hover:text-lightUserMenuItemText dark:bg-darkUserMenuItemBackground dark:hover:bg-darkUserMenuItemBackgroundHover dark:text-darkUserMenuItemText dark:hover:darkUserMenuItemTextHover w-full" role="menuitem">{{ $t('Sign out') }}</button>
|
|
63
67
|
</li>
|
|
64
68
|
</ul>
|
|
65
69
|
</div>
|
|
@@ -68,114 +72,20 @@
|
|
|
68
72
|
</div>
|
|
69
73
|
</nav>
|
|
70
74
|
|
|
71
|
-
<
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
<div class="flex ms-2 m-4">
|
|
80
|
-
<img :src="loadFile(coreStore.config?.brandLogo || '@/assets/logo.svg')" :alt="`${ coreStore.config?.brandName } Logo`" class="h-8 me-3" />
|
|
81
|
-
<span
|
|
82
|
-
v-if="coreStore.config?.showBrandNameInSidebar"
|
|
83
|
-
class="self-center text-lightNavbarText-size font-semibold sm:text-lightNavbarText-size whitespace-nowrap dark:text-darkSidebarText text-lightSidebarText"
|
|
84
|
-
>
|
|
85
|
-
{{ coreStore.config?.brandName }}
|
|
86
|
-
</span>
|
|
87
|
-
</div>
|
|
88
|
-
|
|
89
|
-
<ul class="space-y-2 font-medium">
|
|
90
|
-
<template v-for="(item, i) in coreStore.menu" :key="`menu-${i}`">
|
|
91
|
-
<div v-if="item.type === 'divider'" class="border-t border-lightSidebarDevider dark:border-darkSidebarDevider"></div>
|
|
92
|
-
<div v-else-if="item.type === 'gap'" class="flex items-center justify-center h-8"></div>
|
|
93
|
-
<div v-else-if="item.type === 'heading'" class="flex items-center justify-left pl-2 h-8 text-lightSidebarHeading dark:text-darkSidebarHeading
|
|
94
|
-
">{{ item.label }}</div>
|
|
95
|
-
<li v-else-if="item.children" class=" ">
|
|
96
|
-
<button @click="clickOnMenuItem(i)" type="button" class="flex items-center w-full p-2 text-base text-lightSidebarText rounded-default transition duration-75 group hover:bg-lightSidebarItemHover hover:text-lightSidebarTextHover dark:text-darkSidebarText dark:hover:bg-darkSidebarHover dark:hover:text-darkSidebarTextHover"
|
|
97
|
-
:aria-controls="`dropdown-example${i}`"
|
|
98
|
-
:data-collapse-toggle="`dropdown-example${i}`"
|
|
99
|
-
>
|
|
100
|
-
|
|
101
|
-
<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>
|
|
102
|
-
|
|
103
|
-
<span class="text-ellipsis overflow-hidden flex-1 ms-3 text-left rtl:text-right whitespace-nowrap">{{ item.label }}
|
|
104
|
-
|
|
105
|
-
<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
|
|
106
|
-
fill-lightAnnouncementText dark:fill-darkAccent text-lightAnnouncementText dark:text-darkAccent">
|
|
107
|
-
<Tooltip v-if="item.badgeTooltip">
|
|
108
|
-
{{ item.badge }}
|
|
109
|
-
<template #tooltip>
|
|
110
|
-
{{ item.badgeTooltip }}
|
|
111
|
-
</template>
|
|
112
|
-
</Tooltip>
|
|
113
|
-
<template v-else>
|
|
114
|
-
{{ item.badge }}
|
|
115
|
-
</template>
|
|
116
|
-
</span>
|
|
117
|
-
</span>
|
|
118
|
-
|
|
119
|
-
<svg :class="{'rotate-180': opened.includes(i) }" class="w-3 h-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 10 6">
|
|
120
|
-
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 4 4 4-4"/>
|
|
121
|
-
</svg>
|
|
122
|
-
</button>
|
|
123
|
-
|
|
124
|
-
<ul :id="`dropdown-example${i}`" role="none" class="af-sidebar-dropdown pt-1 space-y-1" :class="{ 'hidden': !opened.includes(i) }">
|
|
125
|
-
<template v-for="(child, j) in item.children" :key="`menu-${i}-${j}`">
|
|
126
|
-
<li>
|
|
127
|
-
<MenuLink :item="child" isChild="true" @click="hideSidebar"/>
|
|
128
|
-
</li>
|
|
129
|
-
</template>
|
|
130
|
-
</ul>
|
|
131
|
-
</li>
|
|
132
|
-
<li v-else>
|
|
133
|
-
<MenuLink :item="item" @click="hideSidebar"/>
|
|
134
|
-
</li>
|
|
135
|
-
</template>
|
|
136
|
-
</ul>
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
<div id="dropdown-cta" class="p-4 mt-6 rounded-lg bg-lightAnnouncementBG dark:bg-darkAnnouncementBG
|
|
140
|
-
fill-lightAnnouncementText dark:fill-darkAccent text-lightAnnouncementText dark:text-darkAccent text-sm" role="alert"
|
|
141
|
-
v-if="ctaBadge"
|
|
142
|
-
>
|
|
143
|
-
<div class="flex items-center mb-3" :class="!ctaBadge.title ? 'float-right' : ''">
|
|
144
|
-
<!-- <span class="bg-lightPrimaryOpacity dark:bg-darkPrimaryOpacity text-sm font-semibold me-2 px-2.5 py-0.5 rounded "
|
|
145
|
-
v-if="ctaBadge.title"
|
|
146
|
-
> -->
|
|
147
|
-
<span>
|
|
148
|
-
{{ctaBadge.title}}
|
|
149
|
-
</span>
|
|
150
|
-
<button type="button"
|
|
151
|
-
class="ms-auto -mx-1.5 -my-1.5 bg-lightPrimaryOpacity dark:bg-darkPrimaryOpacity inline-flex justify-center items-center w-6 h-6 rounded-lg p-1 hover:brightness-110"
|
|
152
|
-
|
|
153
|
-
data-dismiss-target="#dropdown-cta" aria-label="Close"
|
|
154
|
-
v-if="ctaBadge?.closable" @click="closeCTA"
|
|
155
|
-
>
|
|
156
|
-
<span class="sr-only">Close</span>
|
|
157
|
-
<svg class="w-2.5 h-2.5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14">
|
|
158
|
-
<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"/>
|
|
159
|
-
</svg>
|
|
160
|
-
</button>
|
|
161
|
-
</div>
|
|
162
|
-
<p class="mb-3 text-sm " v-if="ctaBadge.html" v-html="ctaBadge.html"></p>
|
|
163
|
-
<p class="mb-3 text-sm fill-lightNavbarText dark:fill-darkPrimary text-lightNavbarText dark:text-darkNavbarPrimary" v-else>
|
|
164
|
-
{{ ctaBadge.text }}
|
|
165
|
-
</p>
|
|
166
|
-
<!-- <a class="text-sm text-lightPrimary underline font-medium hover:text-blue-900 dark:text-blue-400 dark:hover:text-blue-300" href="#">Turn new navigation off</a> -->
|
|
167
|
-
</div>
|
|
168
|
-
|
|
169
|
-
<component
|
|
170
|
-
v-for="c in coreStore?.config?.globalInjections?.sidebar || []"
|
|
171
|
-
:is="getCustomComponent(c)"
|
|
172
|
-
:meta="c.meta"
|
|
173
|
-
:adminUser="coreStore.adminUser"
|
|
174
|
-
/>
|
|
175
|
-
</div>
|
|
176
|
-
</aside>
|
|
75
|
+
<Sidebar
|
|
76
|
+
v-if="loggedIn && routerIsReady && loginRedirectCheckIsReady && defaultLayout && !headerOnlyLayout"
|
|
77
|
+
:sideBarOpen="sideBarOpen"
|
|
78
|
+
:forceIconOnly="route.meta?.sidebarAndHeader === 'preferIconOnly'"
|
|
79
|
+
@hideSidebar="hideSidebar"
|
|
80
|
+
@loadMenu="loadMenu"
|
|
81
|
+
@sidebarStateChange="handleSidebarStateChange"
|
|
82
|
+
/>
|
|
177
83
|
|
|
178
|
-
<div class="
|
|
84
|
+
<div class="af-content-wrapper transition-all duration-300 ease-in-out max-w-[100vw]"
|
|
85
|
+
:style="{
|
|
86
|
+
marginLeft: headerOnlyLayout ? 0 : isSidebarIconOnly ? '4.5rem' : expandedWidth,
|
|
87
|
+
maxWidth: headerOnlyLayout ? '100%' : isSidebarIconOnly ? 'calc(100% - 4.5rem)' : `calc(100% - ${expandedWidth})`
|
|
88
|
+
}"
|
|
179
89
|
v-if="loggedIn && routerIsReady && loginRedirectCheckIsReady && defaultLayout">
|
|
180
90
|
<div class="p-0 dark:border-gray-700 mt-14">
|
|
181
91
|
<RouterView/>
|
|
@@ -193,7 +103,7 @@
|
|
|
193
103
|
</div>
|
|
194
104
|
</div>
|
|
195
105
|
<AcceptModal />
|
|
196
|
-
<div v-if="toastStore.toasts.length>0" class="fixed bottom-5 right-5 flex gap-1 flex-col-reverse z-
|
|
106
|
+
<div v-if="toastStore.toasts.length>0" class="fixed bottom-5 right-5 flex gap-1 flex-col-reverse z-[100]">
|
|
197
107
|
<transition-group
|
|
198
108
|
name="fade"
|
|
199
109
|
tag="div"
|
|
@@ -235,10 +145,18 @@
|
|
|
235
145
|
@apply opacity-100;
|
|
236
146
|
}
|
|
237
147
|
|
|
148
|
+
@media (max-width: 640px) {
|
|
149
|
+
.af-content-wrapper {
|
|
150
|
+
margin-left: 0 !important;
|
|
151
|
+
max-width: 100% !important;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
|
|
238
156
|
</style>
|
|
239
157
|
|
|
240
158
|
<script setup lang="ts">
|
|
241
|
-
import { computed, onMounted, ref, watch, onBeforeMount
|
|
159
|
+
import { computed, onMounted, ref, watch, onBeforeMount } from 'vue';
|
|
242
160
|
import { RouterView } from 'vue-router';
|
|
243
161
|
import { Dropdown } from 'flowbite'
|
|
244
162
|
import './index.scss'
|
|
@@ -246,19 +164,15 @@ import { useCoreStore } from '@/stores/core';
|
|
|
246
164
|
import { useUserStore } from '@/stores/user';
|
|
247
165
|
import { IconMoonSolid, IconSunSolid } from '@iconify-prerendered/vue-flowbite';
|
|
248
166
|
import AcceptModal from './components/AcceptModal.vue';
|
|
249
|
-
import
|
|
167
|
+
import Sidebar from './components/Sidebar.vue';
|
|
250
168
|
import { useRoute, useRouter } from 'vue-router';
|
|
251
|
-
import { getIcon, verySimpleHash } from '@/utils';
|
|
252
169
|
import { createHead } from 'unhead'
|
|
253
|
-
import {
|
|
170
|
+
import { getCustomComponent } from '@/utils';
|
|
254
171
|
import Toast from './components/Toast.vue';
|
|
255
172
|
import {useToastStore} from '@/stores/toast';
|
|
256
|
-
import { getCustomComponent } from '@/utils';
|
|
257
|
-
import type { AdminForthConfigMenuItem, AnnouncementBadgeResponse } from './types/Common';
|
|
258
|
-
import { Tooltip } from '@/afcl';
|
|
259
173
|
import { initFrontedAPI } from '@/adminforth';
|
|
260
174
|
import adminforth from '@/adminforth';
|
|
261
|
-
|
|
175
|
+
import UserMenuSettingsButton from './components/UserMenuSettingsButton.vue';
|
|
262
176
|
|
|
263
177
|
const coreStore = useCoreStore();
|
|
264
178
|
const toastStore = useToastStore();
|
|
@@ -269,39 +183,110 @@ initFrontedAPI()
|
|
|
269
183
|
createHead()
|
|
270
184
|
const sideBarOpen = ref(false);
|
|
271
185
|
const defaultLayout = ref(true);
|
|
186
|
+
const headerOnlyLayout = ref(false);
|
|
272
187
|
const route = useRoute();
|
|
273
188
|
const router = useRouter();
|
|
274
|
-
//create a ref to store the opened menu items with ts type;
|
|
275
|
-
const opened = ref<string[]>([]);
|
|
276
189
|
const publicConfigLoaded = ref(false);
|
|
277
190
|
const dropdownUserButton = ref(null);
|
|
278
191
|
|
|
279
|
-
const sidebarAside = ref(null);
|
|
280
192
|
|
|
281
193
|
const routerIsReady = ref(false);
|
|
282
194
|
const loginRedirectCheckIsReady = ref(false);
|
|
283
195
|
|
|
196
|
+
const isSidebarIconOnly = ref(localStorage.getItem('afIconOnlySidebar') === 'true');
|
|
197
|
+
|
|
284
198
|
const loggedIn = computed(() => !!coreStore?.adminUser);
|
|
285
199
|
|
|
200
|
+
const expandedWidth = computed(() => coreStore.config?.iconOnlySidebar?.expandedSidebarWidth || '16.5rem');
|
|
201
|
+
|
|
286
202
|
const theme = ref('light');
|
|
287
203
|
|
|
204
|
+
const userMenuComponents = computed(() => {
|
|
205
|
+
console.log('🪲🆕 userMenuComponents recomputed', JSON.parse(JSON.stringify(coreStore?.config?.globalInjections?.userMenu)));
|
|
206
|
+
return coreStore?.config?.globalInjections?.userMenu || [];
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
watch(
|
|
210
|
+
() => coreStore.config?.globalInjections?.userMenu,
|
|
211
|
+
(newVal, oldVal) => {
|
|
212
|
+
// Only log when it becomes undefined (you can relax this if needed)
|
|
213
|
+
if (newVal === undefined) {
|
|
214
|
+
const err = new Error('🔍 userMenu changed to undefined');
|
|
215
|
+
console.groupCollapsed(
|
|
216
|
+
'%c[TRACE] userMenu changed to undefined',
|
|
217
|
+
'color: red; font-weight: bold;'
|
|
218
|
+
);
|
|
219
|
+
console.log('old value:', oldVal);
|
|
220
|
+
console.log('new value:', newVal);
|
|
221
|
+
console.log('coreStore.config.globalInjections:', coreStore.config?.globalInjections);
|
|
222
|
+
console.log('Stack trace:');
|
|
223
|
+
console.log(err.stack);
|
|
224
|
+
console.groupEnd();
|
|
225
|
+
} else {
|
|
226
|
+
// Optional: log ALL changes for debugging
|
|
227
|
+
console.groupCollapsed(
|
|
228
|
+
'%c[DEBUG] userMenu changed',
|
|
229
|
+
'color: orange; font-weight: bold;'
|
|
230
|
+
);
|
|
231
|
+
console.log('old value:', oldVal);
|
|
232
|
+
console.log('new value:', newVal);
|
|
233
|
+
console.log('coreStore.config.globalInjections:', coreStore.config?.globalInjections);
|
|
234
|
+
console.groupEnd();
|
|
235
|
+
}
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
deep: false,
|
|
239
|
+
immediate: false,
|
|
240
|
+
}
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
watch(() => coreStore.config?.globalInjections, (v) => {
|
|
244
|
+
console.log("🔧 globalInjections replaced:", v);
|
|
245
|
+
}, { deep: false });
|
|
246
|
+
|
|
247
|
+
watch(
|
|
248
|
+
() => coreStore.config?.globalInjections?.userMenu,
|
|
249
|
+
(newVal, oldVal) => {
|
|
250
|
+
if (newVal === undefined) {
|
|
251
|
+
const err = new Error('🔍 userMenu changed to undefined');
|
|
252
|
+
console.groupCollapsed(
|
|
253
|
+
'%c[TRACE] userMenu changed to undefined',
|
|
254
|
+
'color: red; font-weight: bold;'
|
|
255
|
+
);
|
|
256
|
+
console.log('old value:', oldVal);
|
|
257
|
+
console.log('new value:', newVal);
|
|
258
|
+
console.log('coreStore.config.globalInjections:', coreStore.config?.globalInjections);
|
|
259
|
+
console.log('Stack trace:');
|
|
260
|
+
console.log(err.stack);
|
|
261
|
+
console.groupEnd();
|
|
262
|
+
} else {
|
|
263
|
+
console.groupCollapsed(
|
|
264
|
+
'%c[DEBUG] userMenu changed',
|
|
265
|
+
'color: orange; font-weight: bold;'
|
|
266
|
+
);
|
|
267
|
+
console.log('old value:', oldVal);
|
|
268
|
+
console.log('new value:', newVal);
|
|
269
|
+
console.log('coreStore.config.globalInjections:', coreStore.config?.globalInjections);
|
|
270
|
+
console.groupEnd();
|
|
271
|
+
}
|
|
272
|
+
},
|
|
273
|
+
{ deep: false, immediate: false }
|
|
274
|
+
);
|
|
275
|
+
|
|
288
276
|
function hideSidebar(): void {
|
|
289
277
|
sideBarOpen.value = false;
|
|
290
278
|
}
|
|
291
279
|
|
|
280
|
+
function handleSidebarStateChange(state: { isSidebarIconOnly: boolean }) {
|
|
281
|
+
isSidebarIconOnly.value = state.isSidebarIconOnly;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
|
|
292
285
|
function toggleTheme() {
|
|
293
286
|
theme.value = theme.value === 'light' ? 'dark' : 'light';
|
|
294
287
|
coreStore.toggleTheme();
|
|
295
288
|
}
|
|
296
289
|
|
|
297
|
-
function clickOnMenuItem(label: string) {
|
|
298
|
-
if (opened.value.includes(label)) {
|
|
299
|
-
opened.value = opened.value.filter((item) => item !== label);
|
|
300
|
-
} else {
|
|
301
|
-
opened.value.push(label);
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
}
|
|
305
290
|
|
|
306
291
|
async function logout() {
|
|
307
292
|
userStore.unauthorize();
|
|
@@ -316,7 +301,7 @@ async function initRouter() {
|
|
|
316
301
|
|
|
317
302
|
async function loadMenu() {
|
|
318
303
|
await initRouter();
|
|
319
|
-
if (
|
|
304
|
+
if (route.meta.sidebarAndHeader !== 'none') {
|
|
320
305
|
// for custom layouts we don't need to fetch menu
|
|
321
306
|
await coreStore.fetchMenuAndResource();
|
|
322
307
|
}
|
|
@@ -324,8 +309,13 @@ async function loadMenu() {
|
|
|
324
309
|
}
|
|
325
310
|
|
|
326
311
|
function handleCustomLayout() {
|
|
327
|
-
if (route.meta?.
|
|
312
|
+
if (route.meta?.sidebarAndHeader === 'none') {
|
|
328
313
|
defaultLayout.value = false;
|
|
314
|
+
} else if (route.meta?.sidebarAndHeader === 'preferIconOnly') {
|
|
315
|
+
defaultLayout.value = true;
|
|
316
|
+
isSidebarIconOnly.value = true;
|
|
317
|
+
} else if (route.meta?.sidebarAndHeader === 'headerOnly') {
|
|
318
|
+
headerOnlyLayout.value = true;
|
|
329
319
|
} else {
|
|
330
320
|
defaultLayout.value = true;
|
|
331
321
|
}
|
|
@@ -361,13 +351,6 @@ watch([route, () => coreStore.resourceById, () => coreStore.config], async () =>
|
|
|
361
351
|
|
|
362
352
|
});
|
|
363
353
|
|
|
364
|
-
watch(()=>coreStore.menu, () => {
|
|
365
|
-
coreStore.menu.forEach((item, i) => {
|
|
366
|
-
if (item.open) {
|
|
367
|
-
opened.value.push(i);
|
|
368
|
-
};
|
|
369
|
-
});
|
|
370
|
-
})
|
|
371
354
|
|
|
372
355
|
watch(dropdownUserButton, (dropdownUserButton) => {
|
|
373
356
|
if (dropdownUserButton) {
|
|
@@ -386,11 +369,6 @@ async function loadPublicConfig() {
|
|
|
386
369
|
publicConfigLoaded.value = true;
|
|
387
370
|
}
|
|
388
371
|
|
|
389
|
-
watch(sidebarAside, (sidebarAside) => {
|
|
390
|
-
if (sidebarAside) {
|
|
391
|
-
coreStore.fetchMenuBadges();
|
|
392
|
-
}
|
|
393
|
-
})
|
|
394
372
|
|
|
395
373
|
// initialize components based on data attribute selectors
|
|
396
374
|
onMounted(async () => {
|
|
@@ -410,32 +388,12 @@ onBeforeMount(()=>{
|
|
|
410
388
|
document.documentElement.classList.toggle('dark', theme.value === 'dark');
|
|
411
389
|
})
|
|
412
390
|
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
}
|
|
419
|
-
const hash = badge.closable ? verySimpleHash(JSON.stringify(badge)) : '';
|
|
420
|
-
if (badge.closable && window.localStorage.getItem(`ctaBadge-${hash}`)) {
|
|
421
|
-
return null;
|
|
422
|
-
}
|
|
423
|
-
return {...badge, hash};
|
|
424
|
-
});
|
|
425
|
-
|
|
426
|
-
function closeCTA() {
|
|
427
|
-
if (!ctaBadge.value) {
|
|
428
|
-
return;
|
|
391
|
+
watch(() => coreStore.config?.singleTheme, (singleTheme) => {
|
|
392
|
+
if (singleTheme) {
|
|
393
|
+
theme.value = singleTheme;
|
|
394
|
+
window.localStorage.setItem('af__theme', singleTheme);
|
|
395
|
+
document.documentElement.classList.toggle('dark', theme.value === 'dark');
|
|
429
396
|
}
|
|
430
|
-
|
|
431
|
-
window.localStorage.setItem(`ctaBadge-${hash}`, '1');
|
|
432
|
-
nextTick( async() => {
|
|
433
|
-
loadMenu();
|
|
434
|
-
await coreStore.fetchMenuBadges();
|
|
435
|
-
adminforth.menu.refreshMenuBadges();
|
|
436
|
-
})
|
|
437
|
-
|
|
438
|
-
}
|
|
439
|
-
|
|
397
|
+
}, { immediate: true })
|
|
440
398
|
|
|
441
399
|
</script>
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import type { FilterParams, FrontendAPIInterface } from "./types/FrontendAPI";
|
|
2
1
|
import type { FrontendAPIInterface, ConfirmParams, AlertParams, } from '@/types/FrontendAPI';
|
|
3
|
-
import type { AdminForthFilterOperators,
|
|
2
|
+
import type { AdminForthFilterOperators, AdminForthResourceColumnCommon, FilterParams } from '@/types/Common';
|
|
4
3
|
import { useToastStore } from '@/stores/toast';
|
|
5
4
|
import { useModalStore } from '@/stores/modal';
|
|
6
5
|
import { useCoreStore } from '@/stores/core';
|
|
@@ -36,6 +35,10 @@ class FrontendAPI implements FrontendAPIInterface {
|
|
|
36
35
|
refreshMenuBadges: () => void;
|
|
37
36
|
}
|
|
38
37
|
|
|
38
|
+
public show: {
|
|
39
|
+
refresh(): void;
|
|
40
|
+
}
|
|
41
|
+
|
|
39
42
|
closeUserMenuDropdown(): void {
|
|
40
43
|
console.log('closeUserMenuDropdown')
|
|
41
44
|
}
|
|
@@ -73,9 +76,15 @@ class FrontendAPI implements FrontendAPIInterface {
|
|
|
73
76
|
updateFilter: this.updateListFilter.bind(this),
|
|
74
77
|
clearFilters: this.clearListFilters.bind(this),
|
|
75
78
|
}
|
|
79
|
+
|
|
80
|
+
this.show = {
|
|
81
|
+
refresh: () => {
|
|
82
|
+
console.log('show.refresh')
|
|
83
|
+
}
|
|
84
|
+
}
|
|
76
85
|
}
|
|
77
86
|
|
|
78
|
-
confirm(params: ConfirmParams): Promise<
|
|
87
|
+
confirm(params: ConfirmParams): Promise<boolean> {
|
|
79
88
|
return new Promise((resolve, reject) => {
|
|
80
89
|
this.modalStore.setModalContent({
|
|
81
90
|
content: params.message,
|
|
@@ -88,35 +97,50 @@ class FrontendAPI implements FrontendAPIInterface {
|
|
|
88
97
|
})
|
|
89
98
|
}
|
|
90
99
|
|
|
91
|
-
alert(params: AlertParams): void {
|
|
92
|
-
|
|
100
|
+
alert(params: AlertParams): void | Promise<string> | string {
|
|
101
|
+
const toats = {
|
|
93
102
|
message: params.message,
|
|
94
103
|
messageHtml: params.messageHtml,
|
|
95
104
|
variant: params.variant,
|
|
96
|
-
timeout: params.timeout
|
|
97
|
-
|
|
105
|
+
timeout: params.timeout,
|
|
106
|
+
buttons: params.buttons,
|
|
107
|
+
}
|
|
108
|
+
if (params.buttons && params.buttons.length > 0) {
|
|
109
|
+
return new Promise<string>((resolve) => {
|
|
110
|
+
this.toastStore.addToast({
|
|
111
|
+
...toats,
|
|
112
|
+
onResolve: (value?: any) => resolve(String(value ?? '')),
|
|
113
|
+
})
|
|
114
|
+
})
|
|
115
|
+
} else {
|
|
116
|
+
this.toastStore.addToast({...toats})
|
|
117
|
+
}
|
|
98
118
|
}
|
|
99
119
|
|
|
100
120
|
listFilterValidation(filter: FilterParams): boolean {
|
|
101
121
|
if(router.currentRoute.value.meta.type !== 'list'){
|
|
102
122
|
throw new Error(`Cannot use ${this.setListFilter.name} filter on a list page`)
|
|
103
|
-
} else {
|
|
104
|
-
console.log(this.coreStore.resourceColumnsWithFilters,'core store')
|
|
105
|
-
const filterField = this.coreStore.resourceColumnsWithFilters.find((col: AdminForthResourceColumn) => col.name === filter.field)
|
|
106
|
-
if(!filterField){
|
|
107
|
-
throw new Error(`Field ${filter.field} is not available for filtering`)
|
|
108
|
-
}
|
|
109
|
-
|
|
110
123
|
}
|
|
111
124
|
return true
|
|
112
125
|
}
|
|
113
126
|
|
|
114
127
|
setListFilter(filter: FilterParams): void {
|
|
115
128
|
if(this.listFilterValidation(filter)){
|
|
116
|
-
|
|
117
|
-
|
|
129
|
+
const existingFilterIndex = this.filtersStore.filters.findIndex((f: any) => {
|
|
130
|
+
return f.field === filter.field && f.operator === filter.operator
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
if(existingFilterIndex !== -1){
|
|
134
|
+
// Update existing filter instead of throwing error
|
|
135
|
+
const filters = [...this.filtersStore.filters];
|
|
136
|
+
if (filter.value === undefined) {
|
|
137
|
+
filters.splice(existingFilterIndex, 1);
|
|
138
|
+
} else {
|
|
139
|
+
filters[existingFilterIndex] = filter;
|
|
140
|
+
}
|
|
141
|
+
this.filtersStore.setFilters(filters);
|
|
118
142
|
} else {
|
|
119
|
-
|
|
143
|
+
this.filtersStore.setFilter(filter);
|
|
120
144
|
}
|
|
121
145
|
}
|
|
122
146
|
}
|
|
@@ -60,7 +60,7 @@ const optionsBase = {
|
|
|
60
60
|
tooltip: {
|
|
61
61
|
shared: true,
|
|
62
62
|
intersect: false,
|
|
63
|
-
formatter: function (value) {
|
|
63
|
+
formatter: function (value: any) {
|
|
64
64
|
return value
|
|
65
65
|
},
|
|
66
66
|
},
|
|
@@ -71,7 +71,7 @@ const optionsBase = {
|
|
|
71
71
|
fontFamily: "Inter, sans-serif",
|
|
72
72
|
cssClass: 'text-xs font-normal fill-gray-500 dark:fill-gray-400'
|
|
73
73
|
},
|
|
74
|
-
formatter: function (value) {
|
|
74
|
+
formatter: function (value: any) {
|
|
75
75
|
return value
|
|
76
76
|
}
|
|
77
77
|
},
|