From 1fc4082112699f4e716b47dc6393ca3b34622a34 Mon Sep 17 00:00:00 2001 From: Ivan Borshchov Date: Mon, 8 Jul 2024 15:31:16 +0300 Subject: [PATCH] Deploy website - based on f472e40cbab90c7cc94fc2a9ddebcbdb024a05c5 --- 404.html | 2 +- assets/js/0f6f7c87.5573ae14.js | 1 + assets/js/0f6f7c87.c6cf02a5.js | 1 - assets/js/1e563bf9.13dbe7a8.js | 1 + assets/js/1e563bf9.858ef25d.js | 1 - assets/js/485ec31e.3b8764e1.js | 1 - assets/js/485ec31e.a9d27b05.js | 1 + ...ime~main.b7616b0d.js => runtime~main.46bf9e76.js} | 2 +- blog/archive/index.html | 2 +- blog/first-blog-post/index.html | 2 +- blog/index.html | 2 +- blog/long-blog-post/index.html | 2 +- blog/mdx-blog-post/index.html | 2 +- blog/tags/docusaurus/index.html | 2 +- blog/tags/facebook/index.html | 2 +- blog/tags/hello/index.html | 2 +- blog/tags/hola/index.html | 2 +- blog/tags/index.html | 2 +- blog/welcome/index.html | 2 +- docs/api/index.html | 2 +- docs/api/plugins/AuditLogPlugin/types/index.html | 2 +- .../types/type-aliases/PluginOptions/index.html | 2 +- .../plugins/ForeignInlineListPlugin/types/index.html | 2 +- .../types/type-aliases/PluginOptions/index.html | 2 +- docs/api/plugins/S3UploadPlugin/types/index.html | 2 +- .../types/type-aliases/PluginOptions/index.html | 2 +- .../plugins/TwoFactorsAuthPlugin/types/index.html | 2 +- .../types/type-aliases/PluginOptions/index.html | 2 +- .../enumerations/ActionCheckSource/index.html | 2 +- .../enumerations/AdminForthDataTypes/index.html | 2 +- .../AdminForthFilterOperators/index.html | 2 +- .../enumerations/AdminForthMenuTypes/index.html | 2 +- .../enumerations/AdminForthResourcePages/index.html | 2 +- .../enumerations/AdminForthSortDirections/index.html | 2 +- .../enumerations/AllowedActionsEnum/index.html | 2 +- docs/api/types/AdminForthConfig/index.html | 2 +- .../interfaces/AdminForthClass/index.html | 2 +- .../AdminForthDataSourceConnector/index.html | 2 +- .../AdminForthDataSourceConnectorBase/index.html | 2 +- .../index.html | 2 +- .../interfaces/AdminForthPluginType/index.html | 2 +- .../interfaces/CodeInjectorType/index.html | 2 +- .../interfaces/ExpressHttpServer/index.html | 2 +- .../interfaces/GenericHttpServer/index.html | 2 +- .../type-aliases/AdminForthColumnEnumItem/index.html | 2 +- .../AdminForthComponentDeclaration/index.html | 2 +- .../AdminForthComponentDeclarationFull/index.html | 2 +- .../type-aliases/AdminForthConfig/index.html | 2 +- .../type-aliases/AdminForthConfigMenuItem/index.html | 2 +- .../type-aliases/AdminForthDataSource/index.html | 2 +- .../AdminForthFieldComponents/index.html | 2 +- .../AdminForthForeignResource/index.html | 2 +- .../type-aliases/AdminForthResource/index.html | 2 +- .../type-aliases/AdminForthResourceColumn/index.html | 2 +- .../type-aliases/AdminUser/index.html | 2 +- .../AfterDataSourceResponseFunction/index.html | 2 +- .../type-aliases/AfterSaveFunction/index.html | 2 +- .../type-aliases/AllowedActionValue/index.html | 2 +- .../type-aliases/AllowedActions/index.html | 2 +- .../BeforeDataSourceRequestFunction/index.html | 2 +- .../BeforeLoginConfirmationFunction/index.html | 2 +- .../type-aliases/BeforeSaveFunction/index.html | 2 +- .../type-aliases/ValidationObject/index.html | 2 +- .../FrontendAPI/enumerations/AlertVariant/index.html | 2 +- docs/api/types/FrontendAPI/index.html | 2 +- .../interfaces/FrontendAPIInterface/index.html | 2 +- .../FrontendAPI/type-aliases/AlertParams/index.html | 2 +- .../type-aliases/ConfirmParams/index.html | 2 +- docs/tutorial/Customization/alert/index.html | 2 +- docs/tutorial/Customization/branding/index.html | 2 +- docs/tutorial/Customization/bulkActions/index.html | 2 +- .../Customization/customFieldRendering/index.html | 2 +- docs/tutorial/Customization/customPages/index.html | 12 +++++++++--- docs/tutorial/Customization/hooks/index.html | 2 +- .../tutorial/Customization/limitingAccess/index.html | 2 +- .../tutorial/Customization/pageInjections/index.html | 4 ++-- .../tutorial/Customization/virtualColumns/index.html | 2 +- docs/tutorial/Plugins/AuditLog/index.html | 2 +- docs/tutorial/Plugins/ForeignInlineList/index.html | 2 +- docs/tutorial/Plugins/QuillEditor/index.html | 2 +- docs/tutorial/Plugins/TwoFactorsAuth/index.html | 2 +- docs/tutorial/Plugins/s3Upload/index.html | 2 +- docs/tutorial/deploy/index.html | 6 +++++- docs/tutorial/gettingStarted/index.html | 2 +- docs/tutorial/glossary/index.html | 2 +- index.html | 2 +- markdown-page/index.html | 2 +- search/index.html | 2 +- 88 files changed, 98 insertions(+), 88 deletions(-) create mode 100644 assets/js/0f6f7c87.5573ae14.js delete mode 100644 assets/js/0f6f7c87.c6cf02a5.js create mode 100644 assets/js/1e563bf9.13dbe7a8.js delete mode 100644 assets/js/1e563bf9.858ef25d.js delete mode 100644 assets/js/485ec31e.3b8764e1.js create mode 100644 assets/js/485ec31e.a9d27b05.js rename assets/js/{runtime~main.b7616b0d.js => runtime~main.46bf9e76.js} (97%) diff --git a/404.html b/404.html index 2587887a5..8484c4537 100644 --- a/404.html +++ b/404.html @@ -13,7 +13,7 @@ - + diff --git a/assets/js/0f6f7c87.5573ae14.js b/assets/js/0f6f7c87.5573ae14.js new file mode 100644 index 000000000..c092d8d7b --- /dev/null +++ b/assets/js/0f6f7c87.5573ae14.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkadminforth=self.webpackChunkadminforth||[]).push([[1768],{9706:(n,e,t)=>{t.r(e),t.d(e,{assets:()=>c,contentTitle:()=>r,default:()=>u,frontMatter:()=>s,metadata:()=>i,toc:()=>d});var o=t(4848),a=t(8453);const s={},r="Page Injections",i={id:"tutorial/Customization/pageInjections",title:"Page Injections",description:"In addition to ability to create custom pages and overwrite how fields are rendered, you can also inject custom components in standard AdminForth page.",source:"@site/docs/tutorial/03-Customization/08-pageInjections.md",sourceDirName:"tutorial/03-Customization",slug:"/tutorial/Customization/pageInjections",permalink:"/docs/tutorial/Customization/pageInjections",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:8,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Alerts and confirmations",permalink:"/docs/tutorial/Customization/alert"},next:{title:"Custom bulk actions",permalink:"/docs/tutorial/Customization/bulkActions"}},c={},d=[];function l(n){const e={blockquote:"blockquote",code:"code",h1:"h1",img:"img",p:"p",pre:"pre",...(0,a.R)(),...n.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(e.h1,{id:"page-injections",children:"Page Injections"}),"\n",(0,o.jsx)(e.p,{children:"In addition to ability to create custom pages and overwrite how fields are rendered, you can also inject custom components in standard AdminForth page."}),"\n",(0,o.jsxs)(e.p,{children:["For example let's add a custom pie chart to the ",(0,o.jsx)(e.code,{children:"list"})," page of the ",(0,o.jsx)(e.code,{children:"aparts"})," resource. Pie chart will show the distribution of the rooms count and more over will allow to filter the list by the rooms count."]}),"\n",(0,o.jsx)(e.pre,{children:(0,o.jsx)(e.code,{className:"language-ts",metastring:'title="/index.ts"',children:"{\n resourceId: 'aparts',\n ...\n//diff-add\n options: {\n//diff-add\n pageInjections: {\n//diff-add\n list: {\n//diff-add\n afterBreadcrumbs: '@@/ApartsPie.vue',\n//diff-add\n }\n//diff-add\n } \n//diff-add\n }\n}\n"})}),"\n",(0,o.jsxs)(e.p,{children:["Now create file ",(0,o.jsx)(e.code,{children:"ApartsPie.vue"})," in the ",(0,o.jsx)(e.code,{children:"custom"})," folder of your project:"]}),"\n",(0,o.jsx)(e.pre,{children:(0,o.jsx)(e.code,{className:"language-html",metastring:'title="./custom/ApartsPie.vue"',children:'\n\n + diff --git a/blog/first-blog-post/index.html b/blog/first-blog-post/index.html index 5de358332..f9681eb1f 100644 --- a/blog/first-blog-post/index.html +++ b/blog/first-blog-post/index.html @@ -13,7 +13,7 @@ - + diff --git a/blog/index.html b/blog/index.html index e3e1bbc1a..0db9357b1 100644 --- a/blog/index.html +++ b/blog/index.html @@ -13,7 +13,7 @@ - + diff --git a/blog/long-blog-post/index.html b/blog/long-blog-post/index.html index bd02778b5..186b28f45 100644 --- a/blog/long-blog-post/index.html +++ b/blog/long-blog-post/index.html @@ -13,7 +13,7 @@ - + diff --git a/blog/mdx-blog-post/index.html b/blog/mdx-blog-post/index.html index 9618d54f2..2dae90414 100644 --- a/blog/mdx-blog-post/index.html +++ b/blog/mdx-blog-post/index.html @@ -13,7 +13,7 @@ - + diff --git a/blog/tags/docusaurus/index.html b/blog/tags/docusaurus/index.html index 17dab75e8..ae56e89f4 100644 --- a/blog/tags/docusaurus/index.html +++ b/blog/tags/docusaurus/index.html @@ -13,7 +13,7 @@ - + diff --git a/blog/tags/facebook/index.html b/blog/tags/facebook/index.html index 5820c109d..780e05982 100644 --- a/blog/tags/facebook/index.html +++ b/blog/tags/facebook/index.html @@ -13,7 +13,7 @@ - + diff --git a/blog/tags/hello/index.html b/blog/tags/hello/index.html index b3d07e0e5..88821be09 100644 --- a/blog/tags/hello/index.html +++ b/blog/tags/hello/index.html @@ -13,7 +13,7 @@ - + diff --git a/blog/tags/hola/index.html b/blog/tags/hola/index.html index cacece7a7..5678ba885 100644 --- a/blog/tags/hola/index.html +++ b/blog/tags/hola/index.html @@ -13,7 +13,7 @@ - + diff --git a/blog/tags/index.html b/blog/tags/index.html index 63646b1d1..91954f672 100644 --- a/blog/tags/index.html +++ b/blog/tags/index.html @@ -13,7 +13,7 @@ - + diff --git a/blog/welcome/index.html b/blog/welcome/index.html index 868b4b664..79f552253 100644 --- a/blog/welcome/index.html +++ b/blog/welcome/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/api/index.html b/docs/api/index.html index 479c9815e..5de837898 100644 --- a/docs/api/index.html +++ b/docs/api/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/api/plugins/AuditLogPlugin/types/index.html b/docs/api/plugins/AuditLogPlugin/types/index.html index 03fb19a7c..8582df525 100644 --- a/docs/api/plugins/AuditLogPlugin/types/index.html +++ b/docs/api/plugins/AuditLogPlugin/types/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/api/plugins/AuditLogPlugin/types/type-aliases/PluginOptions/index.html b/docs/api/plugins/AuditLogPlugin/types/type-aliases/PluginOptions/index.html index a5588e28d..45e37221a 100644 --- a/docs/api/plugins/AuditLogPlugin/types/type-aliases/PluginOptions/index.html +++ b/docs/api/plugins/AuditLogPlugin/types/type-aliases/PluginOptions/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/api/plugins/ForeignInlineListPlugin/types/index.html b/docs/api/plugins/ForeignInlineListPlugin/types/index.html index 68e11a62a..df58f8806 100644 --- a/docs/api/plugins/ForeignInlineListPlugin/types/index.html +++ b/docs/api/plugins/ForeignInlineListPlugin/types/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/api/plugins/ForeignInlineListPlugin/types/type-aliases/PluginOptions/index.html b/docs/api/plugins/ForeignInlineListPlugin/types/type-aliases/PluginOptions/index.html index 6371bf30a..a349dbb8b 100644 --- a/docs/api/plugins/ForeignInlineListPlugin/types/type-aliases/PluginOptions/index.html +++ b/docs/api/plugins/ForeignInlineListPlugin/types/type-aliases/PluginOptions/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/api/plugins/S3UploadPlugin/types/index.html b/docs/api/plugins/S3UploadPlugin/types/index.html index 2759f9b74..7f1bb5a7a 100644 --- a/docs/api/plugins/S3UploadPlugin/types/index.html +++ b/docs/api/plugins/S3UploadPlugin/types/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/api/plugins/S3UploadPlugin/types/type-aliases/PluginOptions/index.html b/docs/api/plugins/S3UploadPlugin/types/type-aliases/PluginOptions/index.html index f4e6c7682..232075f24 100644 --- a/docs/api/plugins/S3UploadPlugin/types/type-aliases/PluginOptions/index.html +++ b/docs/api/plugins/S3UploadPlugin/types/type-aliases/PluginOptions/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/api/plugins/TwoFactorsAuthPlugin/types/index.html b/docs/api/plugins/TwoFactorsAuthPlugin/types/index.html index 7132616fd..df695ea27 100644 --- a/docs/api/plugins/TwoFactorsAuthPlugin/types/index.html +++ b/docs/api/plugins/TwoFactorsAuthPlugin/types/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/api/plugins/TwoFactorsAuthPlugin/types/type-aliases/PluginOptions/index.html b/docs/api/plugins/TwoFactorsAuthPlugin/types/type-aliases/PluginOptions/index.html index 5abd858a2..23f94af4a 100644 --- a/docs/api/plugins/TwoFactorsAuthPlugin/types/type-aliases/PluginOptions/index.html +++ b/docs/api/plugins/TwoFactorsAuthPlugin/types/type-aliases/PluginOptions/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/api/types/AdminForthConfig/enumerations/ActionCheckSource/index.html b/docs/api/types/AdminForthConfig/enumerations/ActionCheckSource/index.html index 0c4bec8dd..0785c41d1 100644 --- a/docs/api/types/AdminForthConfig/enumerations/ActionCheckSource/index.html +++ b/docs/api/types/AdminForthConfig/enumerations/ActionCheckSource/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/api/types/AdminForthConfig/enumerations/AdminForthDataTypes/index.html b/docs/api/types/AdminForthConfig/enumerations/AdminForthDataTypes/index.html index b12f959da..8179a97fe 100644 --- a/docs/api/types/AdminForthConfig/enumerations/AdminForthDataTypes/index.html +++ b/docs/api/types/AdminForthConfig/enumerations/AdminForthDataTypes/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/api/types/AdminForthConfig/enumerations/AdminForthFilterOperators/index.html b/docs/api/types/AdminForthConfig/enumerations/AdminForthFilterOperators/index.html index 01a0dca1d..e515e73a7 100644 --- a/docs/api/types/AdminForthConfig/enumerations/AdminForthFilterOperators/index.html +++ b/docs/api/types/AdminForthConfig/enumerations/AdminForthFilterOperators/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/api/types/AdminForthConfig/enumerations/AdminForthMenuTypes/index.html b/docs/api/types/AdminForthConfig/enumerations/AdminForthMenuTypes/index.html index 277825ebf..22ae9c513 100644 --- a/docs/api/types/AdminForthConfig/enumerations/AdminForthMenuTypes/index.html +++ b/docs/api/types/AdminForthConfig/enumerations/AdminForthMenuTypes/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/api/types/AdminForthConfig/enumerations/AdminForthResourcePages/index.html b/docs/api/types/AdminForthConfig/enumerations/AdminForthResourcePages/index.html index ad414de0b..c85d0ab7a 100644 --- a/docs/api/types/AdminForthConfig/enumerations/AdminForthResourcePages/index.html +++ b/docs/api/types/AdminForthConfig/enumerations/AdminForthResourcePages/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/api/types/AdminForthConfig/enumerations/AdminForthSortDirections/index.html b/docs/api/types/AdminForthConfig/enumerations/AdminForthSortDirections/index.html index 846f34b05..fb7f4fa7e 100644 --- a/docs/api/types/AdminForthConfig/enumerations/AdminForthSortDirections/index.html +++ b/docs/api/types/AdminForthConfig/enumerations/AdminForthSortDirections/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/api/types/AdminForthConfig/enumerations/AllowedActionsEnum/index.html b/docs/api/types/AdminForthConfig/enumerations/AllowedActionsEnum/index.html index 47d45f34b..c441c7f41 100644 --- a/docs/api/types/AdminForthConfig/enumerations/AllowedActionsEnum/index.html +++ b/docs/api/types/AdminForthConfig/enumerations/AllowedActionsEnum/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/api/types/AdminForthConfig/index.html b/docs/api/types/AdminForthConfig/index.html index 96ae3792a..c86508a87 100644 --- a/docs/api/types/AdminForthConfig/index.html +++ b/docs/api/types/AdminForthConfig/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/api/types/AdminForthConfig/interfaces/AdminForthClass/index.html b/docs/api/types/AdminForthConfig/interfaces/AdminForthClass/index.html index 89a65d6fd..bf9b712fc 100644 --- a/docs/api/types/AdminForthConfig/interfaces/AdminForthClass/index.html +++ b/docs/api/types/AdminForthConfig/interfaces/AdminForthClass/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/api/types/AdminForthConfig/interfaces/AdminForthDataSourceConnector/index.html b/docs/api/types/AdminForthConfig/interfaces/AdminForthDataSourceConnector/index.html index 42bdc9b01..4a9312d99 100644 --- a/docs/api/types/AdminForthConfig/interfaces/AdminForthDataSourceConnector/index.html +++ b/docs/api/types/AdminForthConfig/interfaces/AdminForthDataSourceConnector/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/api/types/AdminForthConfig/interfaces/AdminForthDataSourceConnectorBase/index.html b/docs/api/types/AdminForthConfig/interfaces/AdminForthDataSourceConnectorBase/index.html index 11568c2ad..ccfd66466 100644 --- a/docs/api/types/AdminForthConfig/interfaces/AdminForthDataSourceConnectorBase/index.html +++ b/docs/api/types/AdminForthConfig/interfaces/AdminForthDataSourceConnectorBase/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/api/types/AdminForthConfig/interfaces/AdminForthDataSourceConnectorConstructor/index.html b/docs/api/types/AdminForthConfig/interfaces/AdminForthDataSourceConnectorConstructor/index.html index 1aebcef68..e3c160fb9 100644 --- a/docs/api/types/AdminForthConfig/interfaces/AdminForthDataSourceConnectorConstructor/index.html +++ b/docs/api/types/AdminForthConfig/interfaces/AdminForthDataSourceConnectorConstructor/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/api/types/AdminForthConfig/interfaces/AdminForthPluginType/index.html b/docs/api/types/AdminForthConfig/interfaces/AdminForthPluginType/index.html index d911865fa..0db0b6d22 100644 --- a/docs/api/types/AdminForthConfig/interfaces/AdminForthPluginType/index.html +++ b/docs/api/types/AdminForthConfig/interfaces/AdminForthPluginType/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/api/types/AdminForthConfig/interfaces/CodeInjectorType/index.html b/docs/api/types/AdminForthConfig/interfaces/CodeInjectorType/index.html index 6d33ba009..9ae34f50b 100644 --- a/docs/api/types/AdminForthConfig/interfaces/CodeInjectorType/index.html +++ b/docs/api/types/AdminForthConfig/interfaces/CodeInjectorType/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/api/types/AdminForthConfig/interfaces/ExpressHttpServer/index.html b/docs/api/types/AdminForthConfig/interfaces/ExpressHttpServer/index.html index 60d788474..1511b3388 100644 --- a/docs/api/types/AdminForthConfig/interfaces/ExpressHttpServer/index.html +++ b/docs/api/types/AdminForthConfig/interfaces/ExpressHttpServer/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/api/types/AdminForthConfig/interfaces/GenericHttpServer/index.html b/docs/api/types/AdminForthConfig/interfaces/GenericHttpServer/index.html index 75336a403..d587eef9a 100644 --- a/docs/api/types/AdminForthConfig/interfaces/GenericHttpServer/index.html +++ b/docs/api/types/AdminForthConfig/interfaces/GenericHttpServer/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/api/types/AdminForthConfig/type-aliases/AdminForthColumnEnumItem/index.html b/docs/api/types/AdminForthConfig/type-aliases/AdminForthColumnEnumItem/index.html index 659fbd440..2e2e000ac 100644 --- a/docs/api/types/AdminForthConfig/type-aliases/AdminForthColumnEnumItem/index.html +++ b/docs/api/types/AdminForthConfig/type-aliases/AdminForthColumnEnumItem/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/api/types/AdminForthConfig/type-aliases/AdminForthComponentDeclaration/index.html b/docs/api/types/AdminForthConfig/type-aliases/AdminForthComponentDeclaration/index.html index c12ad5677..68666da58 100644 --- a/docs/api/types/AdminForthConfig/type-aliases/AdminForthComponentDeclaration/index.html +++ b/docs/api/types/AdminForthConfig/type-aliases/AdminForthComponentDeclaration/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/api/types/AdminForthConfig/type-aliases/AdminForthComponentDeclarationFull/index.html b/docs/api/types/AdminForthConfig/type-aliases/AdminForthComponentDeclarationFull/index.html index 90f749c92..11514e8a6 100644 --- a/docs/api/types/AdminForthConfig/type-aliases/AdminForthComponentDeclarationFull/index.html +++ b/docs/api/types/AdminForthConfig/type-aliases/AdminForthComponentDeclarationFull/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/api/types/AdminForthConfig/type-aliases/AdminForthConfig/index.html b/docs/api/types/AdminForthConfig/type-aliases/AdminForthConfig/index.html index b05597f24..7cba1186b 100644 --- a/docs/api/types/AdminForthConfig/type-aliases/AdminForthConfig/index.html +++ b/docs/api/types/AdminForthConfig/type-aliases/AdminForthConfig/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/api/types/AdminForthConfig/type-aliases/AdminForthConfigMenuItem/index.html b/docs/api/types/AdminForthConfig/type-aliases/AdminForthConfigMenuItem/index.html index 1c7dd2b4b..5f0ec140d 100644 --- a/docs/api/types/AdminForthConfig/type-aliases/AdminForthConfigMenuItem/index.html +++ b/docs/api/types/AdminForthConfig/type-aliases/AdminForthConfigMenuItem/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/api/types/AdminForthConfig/type-aliases/AdminForthDataSource/index.html b/docs/api/types/AdminForthConfig/type-aliases/AdminForthDataSource/index.html index 59dc1c526..61c23f5be 100644 --- a/docs/api/types/AdminForthConfig/type-aliases/AdminForthDataSource/index.html +++ b/docs/api/types/AdminForthConfig/type-aliases/AdminForthDataSource/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/api/types/AdminForthConfig/type-aliases/AdminForthFieldComponents/index.html b/docs/api/types/AdminForthConfig/type-aliases/AdminForthFieldComponents/index.html index 7c3e30fcb..3a4a40615 100644 --- a/docs/api/types/AdminForthConfig/type-aliases/AdminForthFieldComponents/index.html +++ b/docs/api/types/AdminForthConfig/type-aliases/AdminForthFieldComponents/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/api/types/AdminForthConfig/type-aliases/AdminForthForeignResource/index.html b/docs/api/types/AdminForthConfig/type-aliases/AdminForthForeignResource/index.html index 562d88b12..06e574d6c 100644 --- a/docs/api/types/AdminForthConfig/type-aliases/AdminForthForeignResource/index.html +++ b/docs/api/types/AdminForthConfig/type-aliases/AdminForthForeignResource/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/api/types/AdminForthConfig/type-aliases/AdminForthResource/index.html b/docs/api/types/AdminForthConfig/type-aliases/AdminForthResource/index.html index 0e52d2f16..81395486e 100644 --- a/docs/api/types/AdminForthConfig/type-aliases/AdminForthResource/index.html +++ b/docs/api/types/AdminForthConfig/type-aliases/AdminForthResource/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/api/types/AdminForthConfig/type-aliases/AdminForthResourceColumn/index.html b/docs/api/types/AdminForthConfig/type-aliases/AdminForthResourceColumn/index.html index 7fe65ae44..0f75c2a25 100644 --- a/docs/api/types/AdminForthConfig/type-aliases/AdminForthResourceColumn/index.html +++ b/docs/api/types/AdminForthConfig/type-aliases/AdminForthResourceColumn/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/api/types/AdminForthConfig/type-aliases/AdminUser/index.html b/docs/api/types/AdminForthConfig/type-aliases/AdminUser/index.html index b9e106529..6a7e02bc5 100644 --- a/docs/api/types/AdminForthConfig/type-aliases/AdminUser/index.html +++ b/docs/api/types/AdminForthConfig/type-aliases/AdminUser/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/api/types/AdminForthConfig/type-aliases/AfterDataSourceResponseFunction/index.html b/docs/api/types/AdminForthConfig/type-aliases/AfterDataSourceResponseFunction/index.html index 4f44283e2..6ea4ec68f 100644 --- a/docs/api/types/AdminForthConfig/type-aliases/AfterDataSourceResponseFunction/index.html +++ b/docs/api/types/AdminForthConfig/type-aliases/AfterDataSourceResponseFunction/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/api/types/AdminForthConfig/type-aliases/AfterSaveFunction/index.html b/docs/api/types/AdminForthConfig/type-aliases/AfterSaveFunction/index.html index 010e4de6b..6ec906035 100644 --- a/docs/api/types/AdminForthConfig/type-aliases/AfterSaveFunction/index.html +++ b/docs/api/types/AdminForthConfig/type-aliases/AfterSaveFunction/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/api/types/AdminForthConfig/type-aliases/AllowedActionValue/index.html b/docs/api/types/AdminForthConfig/type-aliases/AllowedActionValue/index.html index f336d16d9..f7e3a3bd4 100644 --- a/docs/api/types/AdminForthConfig/type-aliases/AllowedActionValue/index.html +++ b/docs/api/types/AdminForthConfig/type-aliases/AllowedActionValue/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/api/types/AdminForthConfig/type-aliases/AllowedActions/index.html b/docs/api/types/AdminForthConfig/type-aliases/AllowedActions/index.html index ad7e94328..1f832de96 100644 --- a/docs/api/types/AdminForthConfig/type-aliases/AllowedActions/index.html +++ b/docs/api/types/AdminForthConfig/type-aliases/AllowedActions/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/api/types/AdminForthConfig/type-aliases/BeforeDataSourceRequestFunction/index.html b/docs/api/types/AdminForthConfig/type-aliases/BeforeDataSourceRequestFunction/index.html index 117a448a7..e8b0f4025 100644 --- a/docs/api/types/AdminForthConfig/type-aliases/BeforeDataSourceRequestFunction/index.html +++ b/docs/api/types/AdminForthConfig/type-aliases/BeforeDataSourceRequestFunction/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/api/types/AdminForthConfig/type-aliases/BeforeLoginConfirmationFunction/index.html b/docs/api/types/AdminForthConfig/type-aliases/BeforeLoginConfirmationFunction/index.html index 4b0daae3d..8ec2f9a1e 100644 --- a/docs/api/types/AdminForthConfig/type-aliases/BeforeLoginConfirmationFunction/index.html +++ b/docs/api/types/AdminForthConfig/type-aliases/BeforeLoginConfirmationFunction/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/api/types/AdminForthConfig/type-aliases/BeforeSaveFunction/index.html b/docs/api/types/AdminForthConfig/type-aliases/BeforeSaveFunction/index.html index 1d291122b..43db2a24e 100644 --- a/docs/api/types/AdminForthConfig/type-aliases/BeforeSaveFunction/index.html +++ b/docs/api/types/AdminForthConfig/type-aliases/BeforeSaveFunction/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/api/types/AdminForthConfig/type-aliases/ValidationObject/index.html b/docs/api/types/AdminForthConfig/type-aliases/ValidationObject/index.html index 385d55bef..af64a0341 100644 --- a/docs/api/types/AdminForthConfig/type-aliases/ValidationObject/index.html +++ b/docs/api/types/AdminForthConfig/type-aliases/ValidationObject/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/api/types/FrontendAPI/enumerations/AlertVariant/index.html b/docs/api/types/FrontendAPI/enumerations/AlertVariant/index.html index ebd1c777c..66286ef7f 100644 --- a/docs/api/types/FrontendAPI/enumerations/AlertVariant/index.html +++ b/docs/api/types/FrontendAPI/enumerations/AlertVariant/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/api/types/FrontendAPI/index.html b/docs/api/types/FrontendAPI/index.html index 868b6347c..8a7bbe7b4 100644 --- a/docs/api/types/FrontendAPI/index.html +++ b/docs/api/types/FrontendAPI/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/api/types/FrontendAPI/interfaces/FrontendAPIInterface/index.html b/docs/api/types/FrontendAPI/interfaces/FrontendAPIInterface/index.html index f051103b3..194cee060 100644 --- a/docs/api/types/FrontendAPI/interfaces/FrontendAPIInterface/index.html +++ b/docs/api/types/FrontendAPI/interfaces/FrontendAPIInterface/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/api/types/FrontendAPI/type-aliases/AlertParams/index.html b/docs/api/types/FrontendAPI/type-aliases/AlertParams/index.html index 4916f6c9b..d1469931c 100644 --- a/docs/api/types/FrontendAPI/type-aliases/AlertParams/index.html +++ b/docs/api/types/FrontendAPI/type-aliases/AlertParams/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/api/types/FrontendAPI/type-aliases/ConfirmParams/index.html b/docs/api/types/FrontendAPI/type-aliases/ConfirmParams/index.html index 440341c56..59ca6ed57 100644 --- a/docs/api/types/FrontendAPI/type-aliases/ConfirmParams/index.html +++ b/docs/api/types/FrontendAPI/type-aliases/ConfirmParams/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/tutorial/Customization/alert/index.html b/docs/tutorial/Customization/alert/index.html index ce29680cf..b3d891bbd 100644 --- a/docs/tutorial/Customization/alert/index.html +++ b/docs/tutorial/Customization/alert/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/tutorial/Customization/branding/index.html b/docs/tutorial/Customization/branding/index.html index 8259a0b45..031a00217 100644 --- a/docs/tutorial/Customization/branding/index.html +++ b/docs/tutorial/Customization/branding/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/tutorial/Customization/bulkActions/index.html b/docs/tutorial/Customization/bulkActions/index.html index 876da00ec..9508594ce 100644 --- a/docs/tutorial/Customization/bulkActions/index.html +++ b/docs/tutorial/Customization/bulkActions/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/tutorial/Customization/customFieldRendering/index.html b/docs/tutorial/Customization/customFieldRendering/index.html index 6636ed08f..4035fd34b 100644 --- a/docs/tutorial/Customization/customFieldRendering/index.html +++ b/docs/tutorial/Customization/customFieldRendering/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/tutorial/Customization/customPages/index.html b/docs/tutorial/Customization/customPages/index.html index 3694a32e4..f1483543a 100644 --- a/docs/tutorial/Customization/customPages/index.html +++ b/docs/tutorial/Customization/customPages/index.html @@ -13,7 +13,7 @@ - + @@ -23,7 +23,7 @@

Install CHart.js library into your main package (near index.ts):

npm install apexcharts --save

Create a Vue component in the custom directory of your project, e.g. Dashboard.vue:

-
./custom/Dashboard.vue
<template>
<div class="px-4 py-8 bg-blue-50 dark:bg-gray-900 dark:shadow-none h-screen">
<h1 class="mb-4 text-xl font-extrabold text-gray-900 dark:text-white md:text-2xl lg:text-3xl"><span
class="text-transparent bg-clip-text bg-gradient-to-r to-emerald-600 from-sky-400">Appartments</span>
Statistics.</h1>

<div class="grid grid-cols-3 gap-4">
<div class="max-w-md w-full bg-white rounded-lg shadow dark:bg-gray-800 p-4 md:p-6" v-if="data">
<div class="flex justify-between">
<div>
<h5 class="leading-none text-3xl font-bold text-gray-900 dark:text-white pb-2">{{ data.totalAparts }}</h5>
<p class="text-base font-normal text-gray-500 dark:text-gray-400">Apartments last 7 days</p>
</div>

</div>
<div id="area-chart"></div>

</div>

<div class="w-full bg-white rounded-lg shadow dark:bg-gray-800 p-4 md:p-6 row-span-2 col-span-2" v-if="data">

<div class="grid grid-cols-2 py-3">
<dl>
<dt class="text-base font-normal text-gray-500 dark:text-gray-400 pb-1">Listed price</dt>
<dd class="leading-none text-xl font-bold text-green-500 dark:text-green-400">{{
new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(
data.totalListedPrice,
) }}
</dd>
</dl>
<dl>
<dt class="text-base font-normal text-gray-500 dark:text-gray-400 pb-1">Unlisted price</dt>
<dd class="leading-none text-xl font-bold text-red-600 dark:text-red-500">{{
new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(
data.totalUnlistedPrice,
) }}
</dd>
</dl>
</div>

<div id="bar-chart"></div>

</div>

<div class="max-w-md w-full bg-white rounded-lg shadow dark:bg-gray-800 p-4 md:p-6" v-if="data">
<div class="flex justify-between mb-5">
<div>
<p class="text-base font-normal text-gray-500 dark:text-gray-400">
Unlisted vs Listed price
</p>
</div>
</div>
<div id="size-chart" class="[&>div]:mx-auto"></div>
</div>
</div>

</div>
</template>

<script setup>
import { ref, onMounted } from 'vue';
import ApexCharts from 'apexcharts';
import dayjs from 'dayjs';

const data = ref({});

const optionsC1 = {
chart: {
height: 145,
type: "area",
fontFamily: "Inter, sans-serif",
dropShadow: {
enabled: false,
},
toolbar: {
show: false,
},
},
tooltip: {
enabled: true,
x: {
show: false,
},
},
fill: {
type: "gradient",
gradient: {
opacityFrom: 0.55,
opacityTo: 0,
shade: "#1C64F2",
gradientToColors: ["#1C64F2"],
},
},
dataLabels: {
enabled: false,
},
stroke: {
width: 6,
},
grid: {
show: false,
strokeDashArray: 4,
padding: {
left: 2,
right: 2,
top: 0
},
},
series: [
{
name: "Added appartments",
data: [],
color: "#1A56DB",
},
],
xaxis: {
categories: [],
labels: {
show: false,
},
axisBorder: {
show: false,
},
axisTicks: {
show: false,
},
},
yaxis: {
show: false,
},
};

const optionsC2 = {
series: [
{
name: "Listed",
color: "#31C48D",
data: [],
},
{
name: "Unlisted",
data: [],
color: "#F05252",
}
],
chart: {
sparkline: {
enabled: false,
},
type: "bar",
width: "100%",
height: 400,
toolbar: {
show: false,
}
},
fill: {
opacity: 1,
},
plotOptions: {
bar: {
horizontal: true,
columnWidth: "100%",
borderRadiusApplication: "end",
borderRadius: 6,
dataLabels: {
position: "top",
},
},
},
legend: {
show: true,
position: "bottom",
},
dataLabels: {
enabled: false,
},
tooltip: {
shared: true,
intersect: false,
formatter: function (value) {
return value
},
},
xaxis: {
labels: {
show: true,
style: {
fontFamily: "Inter, sans-serif",
cssClass: 'text-xs font-normal fill-gray-500 dark:fill-gray-400'
},
formatter: function (value) {
return value
}
},
categories: [],
axisTicks: {
show: false,
},
axisBorder: {
show: false,
},
},
yaxis: {
labels: {
show: true,
style: {
fontFamily: "Inter, sans-serif",
cssClass: 'text-xs font-normal fill-gray-500 dark:fill-gray-400'
}
}
},
grid: {
show: true,
strokeDashArray: 4,
padding: {
left: 10,
right: 2,
// top: -20
},
},
fill: {
opacity: 1,
}
}

const optionsC3 = {
chart: {
height: 145,
type: "area",
fontFamily: "Inter, sans-serif",
dropShadow: {
enabled: false,
},
toolbar: {
show: false,
},
},
tooltip: {
enabled: true,
x: {
show: false,
},
},
fill: {
type: "gradient",
gradient: {
opacityFrom: 0.55,
opacityTo: 0,
shade: "#1C64F2",
gradientToColors: ["#1C64F2"],
},
},
dataLabels: {
enabled: false,
},
stroke: {
width: 6,
},
grid: {
show: false,
strokeDashArray: 4,
padding: {
left: 2,
right: 2,
top: -26
},
},
series: [
{
name: "Listed Price",
data: [],
color: "#1A56DB",
},
{
name: "Unlisted Price",
data: [],
color: "#7E3BF2",
},
],
xaxis: {
categories: [],
labels: {
show: false,
},
axisBorder: {
show: false,
},
axisTicks: {
show: false,
},
},
yaxis: {
show: false,
labels: {
formatter: function (value) {
return '$' + value;
}
}
},
}

onMounted(async () => {
// Fetch data from the API
// and set it to the chartData
try {
const resp = await fetch('/api/dashboard/');
if (resp.status === 401) {
// user will be redirected to login page automatically so no need to handle anything here
return;
}
data.value = await resp.json();
} catch (error) {
window.adminforth.alert({
message: `Error fetching data: ${error.message}`,
variant: 'danger',
timeout: 'unlimited'
});
}

const apartsByDaysReverse = data.value.apartsByDays.reverse();

optionsC1.series[0].data = apartsByDaysReverse.map((item) => item.count);
optionsC1.xaxis.categories = apartsByDaysReverse.map((item) => dayjs(item.day).format('DD MMM'));
const chart = new ApexCharts(document.getElementById("area-chart"), optionsC1);
chart.render();

optionsC2.series[0].data = data.value.listedVsUnlistedByDays.map((item) => item.listed);
optionsC2.series[1].data = data.value.listedVsUnlistedByDays.map((item) => item.unlisted);
optionsC2.xaxis.categories = data.value.listedVsUnlistedByDays.map((item) => dayjs(item.day).format('DD MMM'));
const chart2 = new ApexCharts(document.getElementById("bar-chart"), optionsC2);
chart2.render();

optionsC3.series[0].data = data.value.listedVsUnlistedPriceByDays.map((item) => item.listedPrice.toFixed(2));
optionsC3.series[1].data = data.value.listedVsUnlistedPriceByDays.map((item) => item.unlistedPrice.toFixed(2));
optionsC3.xaxis.categories = data.value.listedVsUnlistedPriceByDays.map((item) => dayjs(item.day).format('DD MMM'));
const chart3 = new ApexCharts(document.getElementById("size-chart"), optionsC3);
chart3.render();
})
</script>
+
./custom/Dashboard.vue
<template>
<div class="px-4 py-8 bg-blue-50 dark:bg-gray-900 dark:shadow-none h-screen">
<h1 class="mb-4 text-xl font-extrabold text-gray-900 dark:text-white md:text-2xl lg:text-3xl"><span
class="text-transparent bg-clip-text bg-gradient-to-r to-emerald-600 from-sky-400">Appartments</span>
Statistics.</h1>

<div class="grid grid-cols-3 gap-4">
<div class="max-w-md w-full bg-white rounded-lg shadow dark:bg-gray-800 p-4 md:p-6" v-if="data">
<div class="flex justify-between">
<div>
<h5 class="leading-none text-3xl font-bold text-gray-900 dark:text-white pb-2">{{ data.totalAparts }}</h5>
<p class="text-base font-normal text-gray-500 dark:text-gray-400">Apartments last 7 days</p>
</div>

</div>
<div id="area-chart"></div>

</div>

<div class="w-full bg-white rounded-lg shadow dark:bg-gray-800 p-4 md:p-6 row-span-2 col-span-2" v-if="data">

<div class="grid grid-cols-2 py-3">
<dl>
<dt class="text-base font-normal text-gray-500 dark:text-gray-400 pb-1">Listed price</dt>
<dd class="leading-none text-xl font-bold text-green-500 dark:text-green-400">{{
new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(
data.totalListedPrice,
) }}
</dd>
</dl>
<dl>
<dt class="text-base font-normal text-gray-500 dark:text-gray-400 pb-1">Unlisted price</dt>
<dd class="leading-none text-xl font-bold text-red-600 dark:text-red-500">{{
new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(
data.totalUnlistedPrice,
) }}
</dd>
</dl>
</div>

<div id="bar-chart"></div>

</div>

<div class="max-w-md w-full bg-white rounded-lg shadow dark:bg-gray-800 p-4 md:p-6" v-if="data">
<div class="flex justify-between mb-5">
<div>
<p class="text-base font-normal text-gray-500 dark:text-gray-400">
Unlisted vs Listed price
</p>
</div>
</div>
<div id="size-chart" class="[&>div]:mx-auto"></div>
</div>
</div>

</div>
</template>

<script setup>
import { ref, onMounted } from 'vue';
import ApexCharts from 'apexcharts';
import dayjs from 'dayjs';
import { callApi } from '@/utils';

const data = ref({});

const optionsC1 = {
chart: {
height: 145,
type: "area",
fontFamily: "Inter, sans-serif",
dropShadow: {
enabled: false,
},
toolbar: {
show: false,
},
},
tooltip: {
enabled: true,
x: {
show: false,
},
},
fill: {
type: "gradient",
gradient: {
opacityFrom: 0.55,
opacityTo: 0,
shade: "#1C64F2",
gradientToColors: ["#1C64F2"],
},
},
dataLabels: {
enabled: false,
},
stroke: {
width: 6,
},
grid: {
show: false,
strokeDashArray: 4,
padding: {
left: 2,
right: 2,
top: 0
},
},
series: [
{
name: "Added appartments",
data: [],
color: "#1A56DB",
},
],
xaxis: {
categories: [],
labels: {
show: false,
},
axisBorder: {
show: false,
},
axisTicks: {
show: false,
},
},
yaxis: {
show: false,
},
};

const optionsC2 = {
series: [
{
name: "Listed",
color: "#31C48D",
data: [],
},
{
name: "Unlisted",
data: [],
color: "#F05252",
}
],
chart: {
sparkline: {
enabled: false,
},
type: "bar",
width: "100%",
height: 400,
toolbar: {
show: false,
}
},
fill: {
opacity: 1,
},
plotOptions: {
bar: {
horizontal: true,
columnWidth: "100%",
borderRadiusApplication: "end",
borderRadius: 6,
dataLabels: {
position: "top",
},
},
},
legend: {
show: true,
position: "bottom",
},
dataLabels: {
enabled: false,
},
tooltip: {
shared: true,
intersect: false,
formatter: function (value) {
return value
},
},
xaxis: {
labels: {
show: true,
style: {
fontFamily: "Inter, sans-serif",
cssClass: 'text-xs font-normal fill-gray-500 dark:fill-gray-400'
},
formatter: function (value) {
return value
}
},
categories: [],
axisTicks: {
show: false,
},
axisBorder: {
show: false,
},
},
yaxis: {
labels: {
show: true,
style: {
fontFamily: "Inter, sans-serif",
cssClass: 'text-xs font-normal fill-gray-500 dark:fill-gray-400'
}
}
},
grid: {
show: true,
strokeDashArray: 4,
padding: {
left: 10,
right: 2,
// top: -20
},
},
fill: {
opacity: 1,
}
}

const optionsC3 = {
chart: {
height: 145,
type: "area",
fontFamily: "Inter, sans-serif",
dropShadow: {
enabled: false,
},
toolbar: {
show: false,
},
},
tooltip: {
enabled: true,
x: {
show: false,
},
},
fill: {
type: "gradient",
gradient: {
opacityFrom: 0.55,
opacityTo: 0,
shade: "#1C64F2",
gradientToColors: ["#1C64F2"],
},
},
dataLabels: {
enabled: false,
},
stroke: {
width: 6,
},
grid: {
show: false,
strokeDashArray: 4,
padding: {
left: 2,
right: 2,
top: -26
},
},
series: [
{
name: "Listed Price",
data: [],
color: "#1A56DB",
},
{
name: "Unlisted Price",
data: [],
color: "#7E3BF2",
},
],
xaxis: {
categories: [],
labels: {
show: false,
},
axisBorder: {
show: false,
},
axisTicks: {
show: false,
},
},
yaxis: {
show: false,
labels: {
formatter: function (value) {
return '$' + value;
}
}
},
}

onMounted(async () => {
// Fetch data from the API
// and set it to the chartData
try {
data.value = await callApi({path: '/api/dashboard/', method: 'GET'});
} catch (error) {
window.adminforth.alert({
message: `Error fetching data: ${error.message}`,
variant: 'danger',
timeout: 'unlimited'
});
}

const apartsByDaysReverse = data.value.apartsByDays.reverse();

optionsC1.series[0].data = apartsByDaysReverse.map((item) => item.count);
optionsC1.xaxis.categories = apartsByDaysReverse.map((item) => dayjs(item.day).format('DD MMM'));
const chart = new ApexCharts(document.getElementById("area-chart"), optionsC1);
chart.render();

optionsC2.series[0].data = data.value.listedVsUnlistedByDays.map((item) => item.listed);
optionsC2.series[1].data = data.value.listedVsUnlistedByDays.map((item) => item.unlisted);
optionsC2.xaxis.categories = data.value.listedVsUnlistedByDays.map((item) => dayjs(item.day).format('DD MMM'));
const chart2 = new ApexCharts(document.getElementById("bar-chart"), optionsC2);
chart2.render();

optionsC3.series[0].data = data.value.listedVsUnlistedPriceByDays.map((item) => item.listedPrice.toFixed(2));
optionsC3.series[1].data = data.value.listedVsUnlistedPriceByDays.map((item) => item.unlistedPrice.toFixed(2));
optionsC3.xaxis.categories = data.value.listedVsUnlistedPriceByDays.map((item) => dayjs(item.day).format('DD MMM'));
const chart3 = new ApexCharts(document.getElementById("size-chart"), optionsC3);
chart3.render();
})
</script>

🫨 use https://flowbite.com/ to copy-paste pre-designed tailwind design blocks for your pages

@@ -37,7 +37,7 @@ Now we have to define this endpoint in the backend to make our page work:

Defining custom API for own page and components

Open index.ts file and add the following code BEFORE admin.express.serve( !

-
/index.ts

....

app.get('/api/dashboard/',
admin.express.authorize(
async (req, res) => {
const days = req.body.days || 7;
const apartsByDays = await db.prepare(
`SELECT
strftime('%Y-%m-%d', created_at, 'unixepoch') as day,
COUNT(*) as count
FROM apartments
GROUP BY day
ORDER BY day DESC
LIMIT ?;
`
).all(days);

const totalAparts = apartsByDays.reduce((acc, { count }) => acc + count, 0);

// add listed, unlisted, listedPrice, unlistedPrice
const listedVsUnlistedByDays = await db.prepare(
`SELECT
strftime('%Y-%m-%d', created_at, 'unixepoch') as day,
SUM(listed) as listed,
COUNT(*) - SUM(listed) as unlisted,
SUM(listed * price) as listedPrice,
SUM((1 - listed) * price) as unlistedPrice
FROM apartments
GROUP BY day
ORDER BY day DESC
LIMIT ?;
`
).all(days);

const listedVsUnlistedPriceByDays = await db.prepare(
`SELECT
strftime('%Y-%m-%d', created_at, 'unixepoch') as day,
SUM(listed * price) as listedPrice,
SUM((1 - listed) * price) as unlistedPrice
FROM apartments
GROUP BY day
ORDER BY day DESC
LIMIT ?;
`
).all(days);

const totalListedPrice = Math.round(listedVsUnlistedByDays.reduce((acc, { listedPrice }) => acc + listedPrice, 0));
const totalUnlistedPrice = Math.round(listedVsUnlistedByDays.reduce((acc, { unlistedPrice }) => acc + unlistedPrice, 0));

res.json({
apartsByDays,
totalAparts,
listedVsUnlistedByDays,
totalListedPrice,
totalUnlistedPrice,
listedVsUnlistedPriceByDays,
});
}
)
);

// serve after you added all api
admin.express.serve(app, express)
admin.discoverDatabases();

+
/index.ts

....

app.get(`${ADMIN_BASE_URL}/api/dashboard/`,
admin.express.authorize(
async (req, res) => {
const days = req.body.days || 7;
const apartsByDays = await db.prepare(
`SELECT
strftime('%Y-%m-%d', created_at, 'unixepoch') as day,
COUNT(*) as count
FROM apartments
GROUP BY day
ORDER BY day DESC
LIMIT ?;
`
).all(days);

const totalAparts = apartsByDays.reduce((acc, { count }) => acc + count, 0);

// add listed, unlisted, listedPrice, unlistedPrice
const listedVsUnlistedByDays = await db.prepare(
`SELECT
strftime('%Y-%m-%d', created_at, 'unixepoch') as day,
SUM(listed) as listed,
COUNT(*) - SUM(listed) as unlisted,
SUM(listed * price) as listedPrice,
SUM((1 - listed) * price) as unlistedPrice
FROM apartments
GROUP BY day
ORDER BY day DESC
LIMIT ?;
`
).all(days);

const listedVsUnlistedPriceByDays = await db.prepare(
`SELECT
strftime('%Y-%m-%d', created_at, 'unixepoch') as day,
SUM(listed * price) as listedPrice,
SUM((1 - listed) * price) as unlistedPrice
FROM apartments
GROUP BY day
ORDER BY day DESC
LIMIT ?;
`
).all(days);

const totalListedPrice = Math.round(listedVsUnlistedByDays.reduce((acc, { listedPrice }) => acc + listedPrice, 0));
const totalUnlistedPrice = Math.round(listedVsUnlistedByDays.reduce((acc, { unlistedPrice }) => acc + unlistedPrice, 0));

res.json({
apartsByDays,
totalAparts,
listedVsUnlistedByDays,
totalListedPrice,
totalUnlistedPrice,
listedVsUnlistedPriceByDays,
});
}
)
);

// serve after you added all api
admin.express.serve(app, express)
admin.discoverDatabases();

🫨 Please note that we are using admin.express.authorize middleware to check if the user is logged in. If you want to make this endpoint public, you can remove this middleware. If user is not logged in, the request will return 401 Unauthorized status code, and protect our statistics from leak.

@@ -48,6 +48,12 @@

  data.value = await callApi({path: '/api/dashboard/', method: 'GET'});
const response = await fetch('/api/dashboard/');
data.value = await response.json();
+

however, the callApi function will handle path prefixing(you can change baseUrl and it will take this into account) and 401 redirect to login when user is logged out

+

Demo:

AdminForth dashboard demo

diff --git a/docs/tutorial/Customization/hooks/index.html b/docs/tutorial/Customization/hooks/index.html index fe6cdb6ee..f9b7627f9 100644 --- a/docs/tutorial/Customization/hooks/index.html +++ b/docs/tutorial/Customization/hooks/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/tutorial/Customization/limitingAccess/index.html b/docs/tutorial/Customization/limitingAccess/index.html index 5a833418e..50cc1a728 100644 --- a/docs/tutorial/Customization/limitingAccess/index.html +++ b/docs/tutorial/Customization/limitingAccess/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/tutorial/Customization/pageInjections/index.html b/docs/tutorial/Customization/pageInjections/index.html index eaabf3043..1f4b417a0 100644 --- a/docs/tutorial/Customization/pageInjections/index.html +++ b/docs/tutorial/Customization/pageInjections/index.html @@ -13,7 +13,7 @@ - + @@ -22,7 +22,7 @@

For example let's add a custom pie chart to the list page of the aparts resource. Pie chart will show the distribution of the rooms count and more over will allow to filter the list by the rooms count.

/index.ts
{
resourceId: 'aparts',
...
options: {
pageInjections: {
list: {
afterBreadcrumbs: '@@/ApartsPie.vue',
}
}
}
}

Now create file ApartsPie.vue in the custom folder of your project:

-
./custom/ApartsPie.vue
<template>
<div class="max-w-sm w-full bg-white rounded-lg shadow dark:bg-gray-800 p-4 md:p-4 mb-5">
<div id="pie-chart"></div>
</div>
</template>

<script setup lang="ts">
import { onMounted, ref, Ref } from 'vue';
import ApexCharts from 'apexcharts';

const data: Ref<any[]> = ref([]);

const POSSIBLE_COLORS = ["#1C64F2", "#16BDCA", "#9061F9", "#F0A936", "#F55252", "#3B82F6", "#10B981", "#F472B6", "#6B7280"];

const chatOptions = {
series: [],
colors: POSSIBLE_COLORS,
chart: {
height: 200,
width: "100%",
type: "pie",
events: {
dataPointSelection: function (event, chartContext, config) {
if (config.selectedDataPoints[0].length) {
const selectedRoomsCount = data.value[config.dataPointIndex].rooms;
window.adminforth.updateListFilter({field: 'number_of_rooms', operator: 'eq', value: selectedRoomsCount});
} else {
// clear filter
window.adminforth.updateListFilter({field: 'number_of_rooms', value: undefined});
}
}
},
},

stroke: {
colors: ["white"],
lineCap: "",
},
plotOptions: {
pie: {
labels: {
show: true,
},
size: "100%",
dataLabels: {
offset: -25
}
},
},
labels: ["Direct", "Organic search", "Referrals"],
dataLabels: {
enabled: true,
style: {
fontFamily: "Inter, sans-serif",
},
},
legend: {
position: "right",
fontFamily: "Inter, sans-serif",
},
yaxis: {
labels: {
formatter: function (value) {
return value + "%"
},
},
},
xaxis: {
labels: {
formatter: function (value) {
return value + "%"
},
},
axisTicks: {
show: false,
},
axisBorder: {
show: false,
},
},
}

onMounted(async () => {
try {
const resp = await fetch('/api/aparts-by-room-percentages');
if (resp.status === 401) {
// user will be redirected to login page automatically so no need to handle anything here
return;
}
data.value = await resp.json();
} catch (error) {
window.adminforth.alert({
message: `Error fetching data: ${error.message}`,
variant: 'danger',
timeout: 'unlimited'
});
return;
}

chatOptions.series = data.value.map((item) => item.percentage);
chatOptions.labels = data.value.map((item) => `${item.rooms} rooms`);
const chart = new ApexCharts(document.getElementById("pie-chart"), chatOptions);
chart.render();

})

</script>
+
./custom/ApartsPie.vue
<template>
<div class="max-w-sm w-full bg-white rounded-lg shadow dark:bg-gray-800 p-4 md:p-4 mb-5">
<div id="pie-chart"></div>
</div>
</template>

<script setup lang="ts">
import { onMounted, ref, Ref } from 'vue';
import ApexCharts from 'apexcharts';
import { callApi } from '@/utils';


const data: Ref<any[]> = ref([]);

const POSSIBLE_COLORS = ["#1C64F2", "#16BDCA", "#9061F9", "#F0A936", "#F55252", "#3B82F6", "#10B981", "#F472B6", "#6B7280"];

const chatOptions = {
series: [],
colors: POSSIBLE_COLORS,
chart: {
height: 200,
width: "100%",
type: "pie",
events: {
dataPointSelection: function (event, chartContext, config) {
if (config.selectedDataPoints[0].length) {
const selectedRoomsCount = data.value[config.dataPointIndex].rooms;
window.adminforth.updateListFilter({field: 'number_of_rooms', operator: 'eq', value: selectedRoomsCount});
} else {
// clear filter
window.adminforth.updateListFilter({field: 'number_of_rooms', value: undefined});
}
}
},
},

stroke: {
colors: ["white"],
lineCap: "",
},
plotOptions: {
pie: {
labels: {
show: true,
},
size: "100%",
dataLabels: {
offset: -25
}
},
},
labels: ["Direct", "Organic search", "Referrals"],
dataLabels: {
enabled: true,
style: {
fontFamily: "Inter, sans-serif",
},
},
legend: {
position: "right",
fontFamily: "Inter, sans-serif",
},
yaxis: {
labels: {
formatter: function (value) {
return value + "%"
},
},
},
xaxis: {
labels: {
formatter: function (value) {
return value + "%"
},
},
axisTicks: {
show: false,
},
axisBorder: {
show: false,
},
},
}

onMounted(async () => {
try {
data.value = await callApi({path: '/api/aparts-by-room-percentages', method: 'GET'});
} catch (error) {
window.adminforth.alert({
message: `Error fetching data: ${error.message}`,
variant: 'danger',
timeout: 'unlimited'
});
return;
}

chatOptions.series = data.value.map((item) => item.percentage);
chatOptions.labels = data.value.map((item) => `${item.rooms} rooms`);
const chart = new ApexCharts(document.getElementById("pie-chart"), chatOptions);
chart.render();

})

</script>

Also we have to add an Api to get percentages:

./index.ts
  app.get('/api/aparts-by-room-percentages/',
admin.express.authorize(
async (req, res) => {
const roomPercentages = await db.prepare(
`SELECT
number_of_rooms,
COUNT(*) as count
FROM apartments
GROUP BY number_of_rooms
ORDER BY number_of_rooms;
`
).all();

const totalAparts = roomPercentages.reduce((acc, { count }) => acc + count, 0);

res.json(
roomPercentages.map(
({ number_of_rooms, count }) => ({
rooms: number_of_rooms,
percentage: Math.round(count / totalAparts * 100),
})
)
);
}
)
);

// serve after you added all api
admin.discoverDatabases();
admin.express.serve(app)
diff --git a/docs/tutorial/Customization/virtualColumns/index.html b/docs/tutorial/Customization/virtualColumns/index.html index f16ac7637..a8ddd198c 100644 --- a/docs/tutorial/Customization/virtualColumns/index.html +++ b/docs/tutorial/Customization/virtualColumns/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/tutorial/Plugins/AuditLog/index.html b/docs/tutorial/Plugins/AuditLog/index.html index fe5e263a2..b1646443a 100644 --- a/docs/tutorial/Plugins/AuditLog/index.html +++ b/docs/tutorial/Plugins/AuditLog/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/tutorial/Plugins/ForeignInlineList/index.html b/docs/tutorial/Plugins/ForeignInlineList/index.html index f324146e6..1a7eb09cc 100644 --- a/docs/tutorial/Plugins/ForeignInlineList/index.html +++ b/docs/tutorial/Plugins/ForeignInlineList/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/tutorial/Plugins/QuillEditor/index.html b/docs/tutorial/Plugins/QuillEditor/index.html index 66d5bc6f2..14baeb829 100644 --- a/docs/tutorial/Plugins/QuillEditor/index.html +++ b/docs/tutorial/Plugins/QuillEditor/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/tutorial/Plugins/TwoFactorsAuth/index.html b/docs/tutorial/Plugins/TwoFactorsAuth/index.html index 474e4bcf7..78eac4c01 100644 --- a/docs/tutorial/Plugins/TwoFactorsAuth/index.html +++ b/docs/tutorial/Plugins/TwoFactorsAuth/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/tutorial/Plugins/s3Upload/index.html b/docs/tutorial/Plugins/s3Upload/index.html index f471681ec..2b8f187f6 100644 --- a/docs/tutorial/Plugins/s3Upload/index.html +++ b/docs/tutorial/Plugins/s3Upload/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/tutorial/deploy/index.html b/docs/tutorial/deploy/index.html index d7f07e201..169e54a65 100644 --- a/docs/tutorial/deploy/index.html +++ b/docs/tutorial/deploy/index.html @@ -13,7 +13,7 @@ - + @@ -51,6 +51,10 @@

./compose.yml
version: '3.8'

services:
traefik:
image: "traefik:v2.5"
command:
- "--api.insecure=true"
- "--providers.docker=true"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.myresolver.acme.httpchallenge=true"
- "--certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web"
- "--certificatesresolvers.myresolver.acme.email=demo@devforth.io" # ⚠️ replace with your email
- "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"
ports:
- "80:80"
- "443:443"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
- "./letsencrypt:/letsencrypt"
labels:
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
- "traefik.http.routers.http-catchall.rule=hostregexp(`{host:.+}`)"
- "traefik.http.routers.http-catchall.entrypoints=web"
- "traefik.http.routers.http-catchall.middlewares=redirect-to-https"
- "traefik.http.routers.http-catchall.tls=false"

adminforth:
build: ./app
environment:
- NODE_ENV=production
- ADMINFORTH_SECRET=!CHANGEME! # ⚠️ replace with your secret
labels:
- "traefik.enable=true"
- "traefik.http.routers.adminforth.tls=true"
- "traefik.http.routers.adminforth.tls.certresolver=myresolver"
- "traefik.http.routers.adminforth.rule=PathPrefix(`/`)"
- "traefik.http.services.adminforth.loadbalancer.server.port=3500"
- "traefik.http.routers.adminforth.priority=1"


networks:
default:
driver: bridge

Now pull this compose file and all directories to your server and run:

docker compose -p stack-my-app -f compose.yml up -d --build --remove-orphans --wait
+
+

🫨 You can also test this compose stack locally on your machine but SSL will nto work, +so locally you can ignore Chrome warning about SSL and test your AdminForth application.

+

Subpath deployment

If you want to deploy your AdminForth application to a sub-folder like https://mydomain.com/admin you should do the following:

diff --git a/docs/tutorial/gettingStarted/index.html b/docs/tutorial/gettingStarted/index.html index 23bd1f7b3..8036e29c4 100644 --- a/docs/tutorial/gettingStarted/index.html +++ b/docs/tutorial/gettingStarted/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/tutorial/glossary/index.html b/docs/tutorial/glossary/index.html index a70b6fbcc..f79585f3f 100644 --- a/docs/tutorial/glossary/index.html +++ b/docs/tutorial/glossary/index.html @@ -13,7 +13,7 @@ - + diff --git a/index.html b/index.html index 387766d38..1a950025b 100644 --- a/index.html +++ b/index.html @@ -13,7 +13,7 @@ - + diff --git a/markdown-page/index.html b/markdown-page/index.html index 475e1197a..4c18900eb 100644 --- a/markdown-page/index.html +++ b/markdown-page/index.html @@ -13,7 +13,7 @@ - + diff --git a/search/index.html b/search/index.html index d81d1867d..a244b4e99 100644 --- a/search/index.html +++ b/search/index.html @@ -13,7 +13,7 @@ - +