From 67209ec6469e97198d6a1564827bba63a25ebbf5 Mon Sep 17 00:00:00 2001 From: Ivan Borshchov Date: Fri, 21 Jun 2024 13:24:21 +0300 Subject: [PATCH] Deploy website - based on c760757ef31e9d882a244ec4903546ea69a93614 --- 404.html | 2 +- ...df0239.f8c7dd3e.js => 3fdf0239.d522841b.js} | 2 +- ...574ab0.66ef880b.js => 58574ab0.0202d015.js} | 2 +- ...61071f.c8837661.js => 7661071f.bdcf50cf.js} | 2 +- assets/js/9c3f971e.9a6788a7.js | 1 - assets/js/9c3f971e.9c9d639a.js | 1 + assets/js/a74188c8.3d4f353d.js | 1 - assets/js/a74188c8.67de149c.js | 1 + ...f32620.db159716.js => d9f32620.64356def.js} | 2 +- ...in.dae80c53.js => runtime~main.a24a64d5.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/Plugins/AuditLog/index.html | 2 +- docs/Plugins/ForeignInlineList/index.html | 2 +- docs/api/index.html | 2 +- docs/api/plugins/AuditLog/types/index.html | 2 +- .../type-aliases/PluginOptions/index.html | 2 +- .../ForeignInlineListPlugin/types/index.html | 2 +- .../type-aliases/PluginOptions/index.html | 2 +- .../enumerations/ActionCheckSource/index.html | 2 +- .../AdminForthDataTypes/index.html | 2 +- .../AdminForthFilterOperators/index.html | 2 +- .../AdminForthMenuTypes/index.html | 2 +- .../AdminForthResourcePages/index.html | 2 +- .../AdminForthSortDirections/index.html | 2 +- .../enumerations/AllowedActionsEnum/index.html | 2 +- docs/api/types/AdminForthConfig/index.html | 2 +- .../interfaces/AdminForthClass/index.html | 2 +- .../interfaces/AdminForthPluginType/index.html | 2 +- .../interfaces/CodeInjectorType/index.html | 2 +- .../interfaces/ExpressHttpServer/index.html | 2 +- .../interfaces/GenericHttpServer/index.html | 2 +- .../AdminForthColumnEnumItem/index.html | 2 +- .../AdminForthComponentDeclaration/index.html | 2 +- .../index.html | 2 +- .../type-aliases/AdminForthConfig/index.html | 18 +++++++++++++++--- .../AdminForthConfigMenuItem/index.html | 2 +- .../AdminForthDataSource/index.html | 2 +- .../AdminForthFieldComponents/index.html | 2 +- .../AdminForthForeignResource/index.html | 2 +- .../type-aliases/AdminForthResource/index.html | 2 +- .../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 +- .../type-aliases/BeforeSaveFunction/index.html | 2 +- .../type-aliases/ValidationObject/index.html | 2 +- .../enumerations/AlertVariant/index.html | 2 +- docs/api/types/FrontendAPI/index.html | 2 +- .../interfaces/FrontendAPIInterface/index.html | 2 +- .../type-aliases/AlertParams/index.html | 2 +- .../type-aliases/ConfirmParams/index.html | 2 +- .../type-aliases/FilterParams/index.html | 2 +- .../type-aliases/Operator/index.html | 2 +- docs/customization/index.html | 8 ++++---- docs/gettingStarted/index.html | 2 +- docs/glossary/index.html | 2 +- index.html | 2 +- markdown-page/index.html | 2 +- 71 files changed, 86 insertions(+), 74 deletions(-) rename assets/js/{3fdf0239.f8c7dd3e.js => 3fdf0239.d522841b.js} (96%) rename assets/js/{58574ab0.66ef880b.js => 58574ab0.0202d015.js} (98%) rename assets/js/{7661071f.c8837661.js => 7661071f.bdcf50cf.js} (96%) delete mode 100644 assets/js/9c3f971e.9a6788a7.js create mode 100644 assets/js/9c3f971e.9c9d639a.js delete mode 100644 assets/js/a74188c8.3d4f353d.js create mode 100644 assets/js/a74188c8.67de149c.js rename assets/js/{d9f32620.db159716.js => d9f32620.64356def.js} (96%) rename assets/js/{runtime~main.dae80c53.js => runtime~main.a24a64d5.js} (94%) diff --git a/404.html b/404.html index d22690759..994b981ae 100644 --- a/404.html +++ b/404.html @@ -5,7 +5,7 @@ Page Not Found | AdminForth - + diff --git a/assets/js/3fdf0239.f8c7dd3e.js b/assets/js/3fdf0239.d522841b.js similarity index 96% rename from assets/js/3fdf0239.f8c7dd3e.js rename to assets/js/3fdf0239.d522841b.js index 83f550ca6..ed1d83c21 100644 --- a/assets/js/3fdf0239.f8c7dd3e.js +++ b/assets/js/3fdf0239.d522841b.js @@ -1 +1 @@ -"use strict";(self.webpackChunkadminforth=self.webpackChunkadminforth||[]).push([[7132],{519:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>c,contentTitle:()=>r,default:()=>u,frontMatter:()=>t,metadata:()=>l,toc:()=>a});var s=i(4848),o=i(8453);const t={},r=void 0,l={id:"Plugins/ForeignInlineList",title:"ForeignInlineList",description:"Foreign inline list plugin allows to display a list (table) of items from a foreign table in the show view.",source:"@site/docs/Plugins/ForeignInlineList.md",sourceDirName:"Plugins",slug:"/Plugins/ForeignInlineList",permalink:"/docs/Plugins/ForeignInlineList",draft:!1,unlisted:!1,tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"AuditLog",permalink:"/docs/Plugins/AuditLog"},next:{title:"TypeDoc API",permalink:"/docs/api/"}},c={},a=[{value:"Usage",id:"usage",level:2}];function d(e){const n={a:"a",code:"code",h2:"h2",img:"img",p:"p",pre:"pre",...(0,o.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.p,{children:"Foreign inline list plugin allows to display a list (table) of items from a foreign table in the show view."}),"\n",(0,s.jsx)(n.h2,{id:"usage",children:"Usage"}),"\n",(0,s.jsx)(n.p,{children:"Import plugin:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-ts",children:"import ForeignInlineListPlugin from 'adminforth/plugins/ForeignInlineListPlugin';\n"})}),"\n",(0,s.jsx)(n.p,{children:"If yu are using pure Node without TypeScript, you can use the following code:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-js",children:"import ForeignInlineListPlugin from 'adminforth/dist/plugins/ForeignInlineListPlugin/index.js';\n"})}),"\n",(0,s.jsxs)(n.p,{children:["In ",(0,s.jsx)(n.a,{href:"/docs/gettingStarted",children:"Getting Started"})," we created a ",(0,s.jsx)(n.code,{children:"'apparts'"})," resource which has a field ",(0,s.jsx)(n.code,{children:"'user_id'"}),".\nThis field refers to record from ",(0,s.jsx)(n.code,{children:"'users'"})," resource. This means that we can display a list of appartments in the user's show view."]}),"\n",(0,s.jsxs)(n.p,{children:["Add to your ",(0,s.jsx)(n.code,{children:"'users'"})," resource configuration (which we created in ), plugin instance:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-ts",children:"{ \n ...\n resourceId: 'users',\n ...\n plugins: [\n new ForeignInlineListPlugin({\n foreignResourceId: 'apparts',\n modifyTableResourceConfig: (resourceConfig: AdminForthResource) => {\n // hide column 'square_meter' from both 'list' and 'filter'\n const column = resourceConfig.columns.find((c: AdminForthResourceColumn) => c.name === 'square_meter')!.showIn = [];\n resourceConfig.options!.listPageSize = 1;\n\n // feel free to console.log and edit resourceConfig as you need\n },\n }),\n ],\n}\n"})}),"\n",(0,s.jsxs)(n.p,{children:["You can use ",(0,s.jsx)(n.code,{children:"modifyTableResourceConfig"})," callback to modify what columns to show in the list and filter of the foreign table."]}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.img,{alt:"alt text",src:i(4064).A+"",width:"3458",height:"1823"})}),"\n",(0,s.jsxs)(n.p,{children:["See ",(0,s.jsx)(n.a,{href:"/docs/api/plugins/ForeignInlineListPlugin/types/type-aliases/PluginOptions",children:"API Reference"})," for more all options."]})]})}function u(e={}){const{wrapper:n}={...(0,o.R)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},4064:(e,n,i)=>{i.d(n,{A:()=>s});const s=i.p+"assets/images/localhost_3500_resource_users_show_maf3gn-cd12d0c625c41cb2120f2e0eb7e04a86.png"},8453:(e,n,i)=>{i.d(n,{R:()=>r,x:()=>l});var s=i(6540);const o={},t=s.createContext(o);function r(e){const n=s.useContext(t);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function l(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:r(e.components),s.createElement(t.Provider,{value:n},e.children)}}}]); \ No newline at end of file +"use strict";(self.webpackChunkadminforth=self.webpackChunkadminforth||[]).push([[7132],{519:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>c,contentTitle:()=>r,default:()=>u,frontMatter:()=>t,metadata:()=>l,toc:()=>a});var s=i(4848),o=i(8453);const t={},r=void 0,l={id:"Plugins/ForeignInlineList",title:"ForeignInlineList",description:"Foreign inline list plugin allows to display a list (table) of items from a foreign table in the show view.",source:"@site/docs/Plugins/ForeignInlineList.md",sourceDirName:"Plugins",slug:"/Plugins/ForeignInlineList",permalink:"/docs/Plugins/ForeignInlineList",draft:!1,unlisted:!1,tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"AuditLog",permalink:"/docs/Plugins/AuditLog"},next:{title:"TypeDoc API",permalink:"/docs/api/"}},c={},a=[{value:"Usage",id:"usage",level:2}];function d(e){const n={a:"a",code:"code",h2:"h2",img:"img",p:"p",pre:"pre",...(0,o.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.p,{children:"Foreign inline list plugin allows to display a list (table) of items from a foreign table in the show view."}),"\n",(0,s.jsx)(n.h2,{id:"usage",children:"Usage"}),"\n",(0,s.jsx)(n.p,{children:"Import plugin:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-ts",children:"import ForeignInlineListPlugin from 'adminforth/plugins/ForeignInlineListPlugin';\n"})}),"\n",(0,s.jsx)(n.p,{children:"If yu are using pure Node without TypeScript, you can use the following code:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-js",children:"import ForeignInlineListPlugin from 'adminforth/dist/plugins/ForeignInlineListPlugin/index.js';\n"})}),"\n",(0,s.jsxs)(n.p,{children:["In ",(0,s.jsx)(n.a,{href:"/docs/gettingStarted",children:"Getting Started"})," we created a ",(0,s.jsx)(n.code,{children:"'apparts'"})," resource which has a field ",(0,s.jsx)(n.code,{children:"'user_id'"}),".\nThis field refers to record from ",(0,s.jsx)(n.code,{children:"'users'"})," resource. This means that we can display a list of appartments in the user's show view."]}),"\n",(0,s.jsxs)(n.p,{children:["Add to your ",(0,s.jsx)(n.code,{children:"'users'"})," resource configuration (which we created in ), plugin instance:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-ts",children:"{ \n ...\n resourceId: 'users',\n ...\n plugins: [\n new ForeignInlineListPlugin({\n foreignResourceId: 'apparts',\n modifyTableResourceConfig: (resourceConfig: AdminForthResource) => {\n // hide column 'square_meter' from both 'list' and 'filter'\n const column = resourceConfig.columns.find((c: AdminForthResourceColumn) => c.name === 'square_meter')!.showIn = [];\n resourceConfig.options!.listPageSize = 1;\n\n // feel free to console.log and edit resourceConfig as you need\n },\n }),\n ],\n}\n"})}),"\n",(0,s.jsxs)(n.p,{children:["You can use ",(0,s.jsx)(n.code,{children:"modifyTableResourceConfig"})," callback to modify what columns to show in the list and filter of the foreign table."]}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.img,{alt:"alt text",src:i(7771).A+"",width:"3458",height:"1823"})}),"\n",(0,s.jsxs)(n.p,{children:["See ",(0,s.jsx)(n.a,{href:"/docs/api/plugins/ForeignInlineListPlugin/types/type-aliases/PluginOptions",children:"API Reference"})," for more all options."]})]})}function u(e={}){const{wrapper:n}={...(0,o.R)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},7771:(e,n,i)=>{i.d(n,{A:()=>s});const s=i.p+"assets/images/localhost_3500_resource_users_show_maf3gn-cd12d0c625c41cb2120f2e0eb7e04a86.png"},8453:(e,n,i)=>{i.d(n,{R:()=>r,x:()=>l});var s=i(6540);const o={},t=s.createContext(o);function r(e){const n=s.useContext(t);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function l(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:r(e.components),s.createElement(t.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/58574ab0.66ef880b.js b/assets/js/58574ab0.0202d015.js similarity index 98% rename from assets/js/58574ab0.66ef880b.js rename to assets/js/58574ab0.0202d015.js index 592b75ccb..256bf4f88 100644 --- a/assets/js/58574ab0.66ef880b.js +++ b/assets/js/58574ab0.0202d015.js @@ -1 +1 @@ -"use strict";(self.webpackChunkadminforth=self.webpackChunkadminforth||[]).push([[2487],{830:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>i,default:()=>p,frontMatter:()=>a,metadata:()=>o,toc:()=>d});var r=t(4848),s=t(8453);const a={},i="Getting Started",o={id:"gettingStarted",title:"Getting Started",description:"Prerequisites",source:"@site/docs/01-gettingStarted.md",sourceDirName:".",slug:"/gettingStarted",permalink:"/docs/gettingStarted",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:1,frontMatter:{},sidebar:"tutorialSidebar",next:{title:"Glossary",permalink:"/docs/glossary"}},l={},d=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Installation",id:"installation",level:2},{value:"Basic Philosophy",id:"basic-philosophy",level:2},{value:"Setting up a first demo",id:"setting-up-a-first-demo",level:2},{value:"Possible configuration options",id:"possible-configuration-options",level:2}];function c(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",img:"img",p:"p",pre:"pre",...(0,s.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.h1,{id:"getting-started",children:"Getting Started"}),"\n",(0,r.jsx)(n.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,r.jsx)(n.p,{children:"We recommend using Node v18 and higher:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"nvm install 18\nnvm alias default 18\nnvm use 18\n"})}),"\n",(0,r.jsx)(n.h2,{id:"installation",children:"Installation"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"mkdir myadmin\ncd myadmin\nnpm install adminforth\n"})}),"\n",(0,r.jsxs)(n.p,{children:["AdminForth does not provide own HTTP server, but can add own listeners over exisitng ",(0,r.jsx)(n.a,{href:"https://expressjs.com/",children:"Express"})," server (Fastify support is planned in future). This allows to create custom APIs for backoffice in a way you know."]}),"\n",(0,r.jsx)(n.p,{children:"Let's install express:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"npm install express@4.19.2\n"})}),"\n",(0,r.jsx)(n.p,{children:"For demo purposes we will use SQLite data source. You can use postgress, Mongo or Clickhouse as well."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"npm install better-sqlite3@10.0.0\n"})}),"\n",(0,r.jsx)(n.p,{children:"You can use adminforth in pure Node, but we recommend using TypeScript for better development experience:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"npm install typescript@5.4.5 tsx@4.11.2 --save-dev\n"})}),"\n",(0,r.jsx)(n.h2,{id:"basic-philosophy",children:"Basic Philosophy"}),"\n",(0,r.jsx)(n.p,{children:"AdminForth connects to existing databases and provides a backoffice for managing data including CRUD operations, filtering, sorting, and more."}),"\n",(0,r.jsx)(n.p,{children:"Database should be already created by using any database management tool, ORM or migrator. AdminForth does not provide a way to create tables or columns in the database."}),"\n",(0,r.jsx)(n.p,{children:'Once you have a database, you pass a connection string to AdminForth and define resources(tables) and columns you would like to see in backoffice. For most DB AdminForth can "discover" column types and constraints (e.g. max-length) by connecting to DB. However you can redefine them in AdminForth configuration. Type and constraints definition are take precedence over DB schema.'}),"\n",(0,r.jsx)(n.p,{children:'Also in AdminForth you can define in "Vue" way how each field will be rendered, and create own pages e.g. Dashboards.'}),"\n",(0,r.jsxs)(n.p,{children:["In the demo we will create a simple database with 2 tables: ",(0,r.jsx)(n.code,{children:"apartments"})," and ",(0,r.jsx)(n.code,{children:"users"}),". We will just use plain SQL to create tables and insert some fake data."]}),"\n",(0,r.jsx)(n.p,{children:"Users table will be used to store a credentials for login into backoffice itself."}),"\n",(0,r.jsx)(n.h2,{id:"setting-up-a-first-demo",children:"Setting up a first demo"}),"\n",(0,r.jsxs)(n.p,{children:["Open ",(0,r.jsx)(n.code,{children:"package.json"}),", set ",(0,r.jsx)(n.code,{children:"type"})," to ",(0,r.jsx)(n.code,{children:"module"})," and add ",(0,r.jsx)(n.code,{children:"start"})," script:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-json",children:'{\n ...\n "type": "module",\n "scripts": {\n ...\n "start": "ADMINFORTH_SECRET=CHANGE_ME_IN_PRODUCTION NODE_ENV=development tsx watch index.ts"\n },\n}\n'})}),"\n",(0,r.jsxs)(n.p,{children:["Create ",(0,r.jsx)(n.code,{children:"index.ts"})," file in root directory with following content:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-typescript",children:"\nimport betterSqlite3 from 'better-sqlite3';\nimport express from 'express';\nimport AdminForth from 'adminforth';\n\nconst dbFile = 'test.sqlite';\nconst db = betterSqlite3(dbFile)\n \nconst tableExists = db.prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name='apartments';`).get();\nif (!tableExists) {\n await db.prepare(`\n CREATE TABLE apartments (\n id VARCHAR(20) PRIMARY KEY NOT NULL,\n title VARCHAR(255) NOT NULL,\n square_meter REAL,\n price DECIMAL(10, 2) NOT NULL,\n number_of_rooms INT,\n description TEXT,\n property_type VARCHAR(255) DEFAULT 'apartment',\n listed BOOLEAN DEFAULT FALSE,\n created_at TIMESTAMP,\n user_id VARCHAR(255)\n );`).run();\n\n await db.prepare(`\n CREATE TABLE users (\n id VARCHAR(255) PRIMARY KEY NOT NULL,\n email VARCHAR(255) NOT NULL,\n password_hash VARCHAR(255) NOT NULL,\n created_at VARCHAR(255) NOT NULL,\n role VARCHAR(255) NOT NULL\n );`).run();\n\n for (let i = 0; i < 50; i++) {\n await db.prepare(`\n INSERT INTO apartments (\n id, title, square_meter, price, number_of_rooms, description, created_at, listed, property_type\n ) VALUES ('${i}', 'Apartment ${i}', ${Math.random() * 100}, ${Math.random() * 10000}, ${Math\n .floor(Math.random() * 5) }, 'Next gen appartments', ${Date.now() / 1000 - i * 60 * 60 * 24}, ${i % 2 == 0}, ${i % 2 == 0 ? \"'house'\" : \"'apartment'\"});\n `).run();\n }\n}\n\nconst ADMIN_BASE_URL = '';\n\nconst admin = new AdminForth({\n baseUrl : ADMIN_BASE_URL,\n rootUser: {\n username: 'adminforth', // use these as credentials to login\n password: 'adminforth',\n },\n auth: {\n resourceId: 'users', // resource for getting user\n usernameField: 'email',\n passwordHashField: 'password_hash',\n },\n customization: {\n brandName: 'My Admin',\n datesFormat: 'D MMM YY HH:mm:ss',\n emptyFieldPlaceholder: '-',\n },\n\n dataSources: [\n {\n id: 'maindb',\n url: `sqlite://${dbFile}`\n },\n ],\n resources: [\n {\n dataSource: 'maindb', \n table: 'apartments',\n resourceId: 'apparts', // resourceId is defaulted to table name but you can change it e.g. \n // in case of same table names from different data sources\n label: 'Apartments', // label is defaulted to table name but you can change it\n recordLabel: (r) => `\ud83c\udfe1 ${r.title}`,\n columns: [\n { \n name: 'id', \n label: 'Identifier', // if you wish you can redefine label\n showIn: ['filter', 'show'], // show in filter and in show page\n primaryKey: true,\n fillOnCreate: ({initialRecord, adminUser}) => Math.random().toString(36).substring(7), // initialRecord is values user entered, adminUser object of user who creates record\n },\n { \n name: 'title',\n required: true,\n showIn: ['list', 'create', 'edit', 'filter', 'show'], // the default is full set\n maxLength: 255, // you can set max length for string fields\n minLength: 3, // you can set min length for string fields\n }, \n {\n name: 'created_at',\n type: AdminForth.Types.DATETIME ,\n allowMinMaxQuery: true,\n showIn: ['list', 'filter', 'show', 'edit'],\n fillOnCreate: ({initialRecord, adminUser}) => (new Date()).toISOString(),\n },\n { \n name: 'price',\n min: 10,\n max: 10000.12,\n allowMinMaxQuery: true, // use better experience for filtering e.g. date range, set it only if you have index on this column or if there will be low number of rows\n editingNote: 'Price is in USD', // you can appear note on editing or creating page\n },\n { \n name: 'square_meter', \n label: 'Square', \n allowMinMaxQuery: true,\n minValue: 1, // you can set min /max value for number fields\n maxValue: 1000,\n },\n { \n name: 'number_of_rooms',\n allowMinMaxQuery: true,\n enum: [\n { value: 1, label: '1 room' },\n { value: 2, label: '2 rooms' },\n { value: 3, label: '3 rooms' },\n { value: 4, label: '4 rooms' },\n { value: 5, label: '5 rooms' },\n ],\n },\n { \n name: 'description',\n sortable: false,\n },\n {\n name: 'property_type',\n enum: [{\n value: 'house',\n label: 'House'\n }, {\n value: 'apartment',\n label: 'Apartment'\n }, {\n value: null,\n label: 'Not defined'\n }],\n },\n {\n name: 'listed',\n required: true, // will be required on create/edit\n },\n {\n name: 'user_id',\n foreignResource: {\n resourceId: 'users',\n }\n }\n ],\n options: {\n listPageSize: 12,\n allowedActions:{\n edit: true,\n delete: true,\n show: true,\n filter: true,\n },\n },\n },\n { \n dataSource: 'maindb', \n table: 'users',\n resourceId: 'users',\n label: 'Users', \n recordLabel: (r) => `\ud83d\udc64 ${r.email}`,\n columns: [\n { \n name: 'id', \n primaryKey: true,\n fillOnCreate: ({initialRecord, adminUser}) => Math.random().toString(36).substring(7),\n showIn: ['list', 'filter', 'show'],\n },\n { \n name: 'email', \n required: true,\n isUnique: true,\n validation: [\n {\n regExp: '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\\\.[a-zA-Z]{2,}$',\n message: 'Email is not valid, must be in format example@test.com'\n },\n ]\n },\n { \n name: 'created_at', \n type: AdminForth.Types.DATETIME,\n showIn: ['list', 'filter', 'show'],\n fillOnCreate: ({initialRecord, adminUser}) => (new Date()).toISOString(),\n },\n {\n name: 'role',\n enum: [\n { value: 'superadmin', label: 'Super Admin' },\n { value: 'user', label: 'User' },\n ]\n },\n {\n name: 'password',\n virtual: true, // field will not be persisted into db\n required: { create: true }, // make required only on create page\n editingNote: { edit: 'Leave empty to keep password unchanged' },\n minLength: 8,\n type: AdminForth.Types.STRING,\n showIn: ['create', 'edit'], // to show field only on create and edit pages\n masked: true, // to show stars in input field\n }\n ],\n hooks: {\n create: {\n beforeSave: async ({ record, adminUser, resource }) => {\n record.password_hash = await AdminForth.Utils.generatePasswordHash(record.password);\n return { ok:true, error: false };\n }\n },\n edit: {\n beforeSave: async ({ record, adminUser, resource}) => {\n if (record.password) {\n record.password_hash = await AdminForth.Utils.generatePasswordHash(record.password);\n }\n return { ok: true, error: false }\n },\n },\n }\n },\n ],\n menu: [\n {\n label: 'Core',\n icon: 'flowbite:brain-solid', // any icon from iconify supported in format :, e.g. from here https://icon-sets.iconify.design/flowbite/\n open: true,\n children: [\n {\n homepage: true,\n label: 'Appartments',\n icon: 'flowbite:home-solid',\n resourceId: 'apparts',\n },\n ]\n },\n {\n type: 'gap'\n },\n {\n type: 'divider'\n },\n {\n type: 'heading',\n label: 'SYSTEM',\n },\n {\n label: 'Users',\n icon: 'flowbite:user-solid',\n resourceId: 'users',\n }\n ],\n})\n\n\nconst app = express()\napp.use(express.json());\nconst port = 3500;\n\n(async () => {\n // needed to compile SPA. Call it here or from a build script e.g. in Docker build time to reduce downtime\n await admin.bundleNow({ hotReload: process.env.NODE_ENV === 'development'});\n console.log('Bundling AdminForth done. For faster serving consider calling bundleNow() from a build script.');\n})();\n\n\n// serve after you added all api\nadmin.express.serve(app, express)\nadmin.discoverDatabases();\n\n\napp.listen(port, () => {\n console.log(`Example app listening at http://localhost:${port}`)\n console.log(`\\n\u26a1 AdminForth is available at http://localhost:${port}${ADMIN_BASE_URL}\\n`)\n});\n"})}),"\n",(0,r.jsx)(n.p,{children:"Now you can run your app:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"npm start\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Open ",(0,r.jsx)(n.a,{href:"http://localhost:3500",children:"http://localhost:3500"})," in your browser and login with credentials ",(0,r.jsx)(n.code,{children:"adminforth"})," / ",(0,r.jsx)(n.code,{children:"adminforth"}),"."]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.img,{alt:"alt text",src:t(5529).A+"",width:"3456",height:"2043"})}),"\n",(0,r.jsx)(n.p,{children:"After Login you should see:"}),"\n",(0,r.jsx)(n.h2,{id:"possible-configuration-options",children:"Possible configuration options"}),"\n",(0,r.jsx)(n.p,{children:"We will use schema with different column types for apartments to show many of AdminForth features."}),"\n",(0,r.jsxs)(n.p,{children:["Check ",(0,r.jsx)(n.a,{href:"/docs/api/types/AdminForthConfig/type-aliases/AdminForthConfig",children:"AdminForthConfig"})," for all possible options."]})]})}function p(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(c,{...e})}):c(e)}},5529:(e,n,t)=>{t.d(n,{A:()=>r});const r=t.p+"assets/images/image-4073119b1a64b412c6322c1917d972fc.png"},8453:(e,n,t)=>{t.d(n,{R:()=>i,x:()=>o});var r=t(6540);const s={},a=r.createContext(s);function i(e){const n=r.useContext(a);return r.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:i(e.components),r.createElement(a.Provider,{value:n},e.children)}}}]); \ No newline at end of file +"use strict";(self.webpackChunkadminforth=self.webpackChunkadminforth||[]).push([[2487],{830:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>i,default:()=>p,frontMatter:()=>a,metadata:()=>o,toc:()=>d});var r=t(4848),s=t(8453);const a={},i="Getting Started",o={id:"gettingStarted",title:"Getting Started",description:"Prerequisites",source:"@site/docs/01-gettingStarted.md",sourceDirName:".",slug:"/gettingStarted",permalink:"/docs/gettingStarted",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:1,frontMatter:{},sidebar:"tutorialSidebar",next:{title:"Glossary",permalink:"/docs/glossary"}},l={},d=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Installation",id:"installation",level:2},{value:"Basic Philosophy",id:"basic-philosophy",level:2},{value:"Setting up a first demo",id:"setting-up-a-first-demo",level:2},{value:"Possible configuration options",id:"possible-configuration-options",level:2}];function c(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",img:"img",p:"p",pre:"pre",...(0,s.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.h1,{id:"getting-started",children:"Getting Started"}),"\n",(0,r.jsx)(n.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,r.jsx)(n.p,{children:"We recommend using Node v18 and higher:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"nvm install 18\nnvm alias default 18\nnvm use 18\n"})}),"\n",(0,r.jsx)(n.h2,{id:"installation",children:"Installation"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"mkdir myadmin\ncd myadmin\nnpm install adminforth\n"})}),"\n",(0,r.jsxs)(n.p,{children:["AdminForth does not provide own HTTP server, but can add own listeners over exisitng ",(0,r.jsx)(n.a,{href:"https://expressjs.com/",children:"Express"})," server (Fastify support is planned in future). This allows to create custom APIs for backoffice in a way you know."]}),"\n",(0,r.jsx)(n.p,{children:"Let's install express:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"npm install express@4.19.2\n"})}),"\n",(0,r.jsx)(n.p,{children:"For demo purposes we will use SQLite data source. You can use postgress, Mongo or Clickhouse as well."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"npm install better-sqlite3@10.0.0\n"})}),"\n",(0,r.jsx)(n.p,{children:"You can use adminforth in pure Node, but we recommend using TypeScript for better development experience:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"npm install typescript@5.4.5 tsx@4.11.2 --save-dev\n"})}),"\n",(0,r.jsx)(n.h2,{id:"basic-philosophy",children:"Basic Philosophy"}),"\n",(0,r.jsx)(n.p,{children:"AdminForth connects to existing databases and provides a backoffice for managing data including CRUD operations, filtering, sorting, and more."}),"\n",(0,r.jsx)(n.p,{children:"Database should be already created by using any database management tool, ORM or migrator. AdminForth does not provide a way to create tables or columns in the database."}),"\n",(0,r.jsx)(n.p,{children:'Once you have a database, you pass a connection string to AdminForth and define resources(tables) and columns you would like to see in backoffice. For most DB AdminForth can "discover" column types and constraints (e.g. max-length) by connecting to DB. However you can redefine them in AdminForth configuration. Type and constraints definition are take precedence over DB schema.'}),"\n",(0,r.jsx)(n.p,{children:'Also in AdminForth you can define in "Vue" way how each field will be rendered, and create own pages e.g. Dashboards.'}),"\n",(0,r.jsxs)(n.p,{children:["In the demo we will create a simple database with 2 tables: ",(0,r.jsx)(n.code,{children:"apartments"})," and ",(0,r.jsx)(n.code,{children:"users"}),". We will just use plain SQL to create tables and insert some fake data."]}),"\n",(0,r.jsx)(n.p,{children:"Users table will be used to store a credentials for login into backoffice itself."}),"\n",(0,r.jsx)(n.h2,{id:"setting-up-a-first-demo",children:"Setting up a first demo"}),"\n",(0,r.jsxs)(n.p,{children:["Open ",(0,r.jsx)(n.code,{children:"package.json"}),", set ",(0,r.jsx)(n.code,{children:"type"})," to ",(0,r.jsx)(n.code,{children:"module"})," and add ",(0,r.jsx)(n.code,{children:"start"})," script:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-json",children:'{\n ...\n "type": "module",\n "scripts": {\n ...\n "start": "ADMINFORTH_SECRET=CHANGE_ME_IN_PRODUCTION NODE_ENV=development tsx watch index.ts"\n },\n}\n'})}),"\n",(0,r.jsxs)(n.p,{children:["Create ",(0,r.jsx)(n.code,{children:"index.ts"})," file in root directory with following content:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-typescript",children:"\nimport betterSqlite3 from 'better-sqlite3';\nimport express from 'express';\nimport AdminForth from 'adminforth';\n\nconst dbFile = 'test.sqlite';\nconst db = betterSqlite3(dbFile)\n \nconst tableExists = db.prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name='apartments';`).get();\nif (!tableExists) {\n await db.prepare(`\n CREATE TABLE apartments (\n id VARCHAR(20) PRIMARY KEY NOT NULL,\n title VARCHAR(255) NOT NULL,\n square_meter REAL,\n price DECIMAL(10, 2) NOT NULL,\n number_of_rooms INT,\n description TEXT,\n property_type VARCHAR(255) DEFAULT 'apartment',\n listed BOOLEAN DEFAULT FALSE,\n created_at TIMESTAMP,\n user_id VARCHAR(255)\n );`).run();\n\n await db.prepare(`\n CREATE TABLE users (\n id VARCHAR(255) PRIMARY KEY NOT NULL,\n email VARCHAR(255) NOT NULL,\n password_hash VARCHAR(255) NOT NULL,\n created_at VARCHAR(255) NOT NULL,\n role VARCHAR(255) NOT NULL\n );`).run();\n\n for (let i = 0; i < 50; i++) {\n await db.prepare(`\n INSERT INTO apartments (\n id, title, square_meter, price, number_of_rooms, description, created_at, listed, property_type\n ) VALUES ('${i}', 'Apartment ${i}', ${Math.random() * 100}, ${Math.random() * 10000}, ${Math\n .floor(Math.random() * 5) }, 'Next gen appartments', ${Date.now() / 1000 - i * 60 * 60 * 24}, ${i % 2 == 0}, ${i % 2 == 0 ? \"'house'\" : \"'apartment'\"});\n `).run();\n }\n}\n\nconst ADMIN_BASE_URL = '';\n\nconst admin = new AdminForth({\n baseUrl : ADMIN_BASE_URL,\n rootUser: {\n username: 'adminforth', // use these as credentials to login\n password: 'adminforth',\n },\n auth: {\n resourceId: 'users', // resource for getting user\n usernameField: 'email',\n passwordHashField: 'password_hash',\n },\n customization: {\n brandName: 'My Admin',\n datesFormat: 'D MMM YY HH:mm:ss',\n emptyFieldPlaceholder: '-',\n },\n\n dataSources: [\n {\n id: 'maindb',\n url: `sqlite://${dbFile}`\n },\n ],\n resources: [\n {\n dataSource: 'maindb', \n table: 'apartments',\n resourceId: 'apparts', // resourceId is defaulted to table name but you can change it e.g. \n // in case of same table names from different data sources\n label: 'Apartments', // label is defaulted to table name but you can change it\n recordLabel: (r) => `\ud83c\udfe1 ${r.title}`,\n columns: [\n { \n name: 'id', \n label: 'Identifier', // if you wish you can redefine label\n showIn: ['filter', 'show'], // show in filter and in show page\n primaryKey: true,\n fillOnCreate: ({initialRecord, adminUser}) => Math.random().toString(36).substring(7), // initialRecord is values user entered, adminUser object of user who creates record\n },\n { \n name: 'title',\n required: true,\n showIn: ['list', 'create', 'edit', 'filter', 'show'], // the default is full set\n maxLength: 255, // you can set max length for string fields\n minLength: 3, // you can set min length for string fields\n }, \n {\n name: 'created_at',\n type: AdminForth.Types.DATETIME ,\n allowMinMaxQuery: true,\n showIn: ['list', 'filter', 'show', 'edit'],\n fillOnCreate: ({initialRecord, adminUser}) => (new Date()).toISOString(),\n },\n { \n name: 'price',\n min: 10,\n max: 10000.12,\n allowMinMaxQuery: true, // use better experience for filtering e.g. date range, set it only if you have index on this column or if there will be low number of rows\n editingNote: 'Price is in USD', // you can appear note on editing or creating page\n },\n { \n name: 'square_meter', \n label: 'Square', \n allowMinMaxQuery: true,\n minValue: 1, // you can set min /max value for number fields\n maxValue: 1000,\n },\n { \n name: 'number_of_rooms',\n allowMinMaxQuery: true,\n enum: [\n { value: 1, label: '1 room' },\n { value: 2, label: '2 rooms' },\n { value: 3, label: '3 rooms' },\n { value: 4, label: '4 rooms' },\n { value: 5, label: '5 rooms' },\n ],\n },\n { \n name: 'description',\n sortable: false,\n },\n {\n name: 'property_type',\n enum: [{\n value: 'house',\n label: 'House'\n }, {\n value: 'apartment',\n label: 'Apartment'\n }, {\n value: null,\n label: 'Not defined'\n }],\n },\n {\n name: 'listed',\n required: true, // will be required on create/edit\n },\n {\n name: 'user_id',\n foreignResource: {\n resourceId: 'users',\n }\n }\n ],\n options: {\n listPageSize: 12,\n allowedActions:{\n edit: true,\n delete: true,\n show: true,\n filter: true,\n },\n },\n },\n { \n dataSource: 'maindb', \n table: 'users',\n resourceId: 'users',\n label: 'Users', \n recordLabel: (r) => `\ud83d\udc64 ${r.email}`,\n columns: [\n { \n name: 'id', \n primaryKey: true,\n fillOnCreate: ({initialRecord, adminUser}) => Math.random().toString(36).substring(7),\n showIn: ['list', 'filter', 'show'],\n },\n { \n name: 'email', \n required: true,\n isUnique: true,\n validation: [\n {\n regExp: '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\\\.[a-zA-Z]{2,}$',\n message: 'Email is not valid, must be in format example@test.com'\n },\n ]\n },\n { \n name: 'created_at', \n type: AdminForth.Types.DATETIME,\n showIn: ['list', 'filter', 'show'],\n fillOnCreate: ({initialRecord, adminUser}) => (new Date()).toISOString(),\n },\n {\n name: 'role',\n enum: [\n { value: 'superadmin', label: 'Super Admin' },\n { value: 'user', label: 'User' },\n ]\n },\n {\n name: 'password',\n virtual: true, // field will not be persisted into db\n required: { create: true }, // make required only on create page\n editingNote: { edit: 'Leave empty to keep password unchanged' },\n minLength: 8,\n type: AdminForth.Types.STRING,\n showIn: ['create', 'edit'], // to show field only on create and edit pages\n masked: true, // to show stars in input field\n }\n ],\n hooks: {\n create: {\n beforeSave: async ({ record, adminUser, resource }) => {\n record.password_hash = await AdminForth.Utils.generatePasswordHash(record.password);\n return { ok:true, error: false };\n }\n },\n edit: {\n beforeSave: async ({ record, adminUser, resource}) => {\n if (record.password) {\n record.password_hash = await AdminForth.Utils.generatePasswordHash(record.password);\n }\n return { ok: true, error: false }\n },\n },\n }\n },\n ],\n menu: [\n {\n label: 'Core',\n icon: 'flowbite:brain-solid', // any icon from iconify supported in format :, e.g. from here https://icon-sets.iconify.design/flowbite/\n open: true,\n children: [\n {\n homepage: true,\n label: 'Appartments',\n icon: 'flowbite:home-solid',\n resourceId: 'apparts',\n },\n ]\n },\n {\n type: 'gap'\n },\n {\n type: 'divider'\n },\n {\n type: 'heading',\n label: 'SYSTEM',\n },\n {\n label: 'Users',\n icon: 'flowbite:user-solid',\n resourceId: 'users',\n }\n ],\n})\n\n\nconst app = express()\napp.use(express.json());\nconst port = 3500;\n\n(async () => {\n // needed to compile SPA. Call it here or from a build script e.g. in Docker build time to reduce downtime\n await admin.bundleNow({ hotReload: process.env.NODE_ENV === 'development'});\n console.log('Bundling AdminForth done. For faster serving consider calling bundleNow() from a build script.');\n})();\n\n\n// serve after you added all api\nadmin.express.serve(app, express)\nadmin.discoverDatabases();\n\n\napp.listen(port, () => {\n console.log(`Example app listening at http://localhost:${port}`)\n console.log(`\\n\u26a1 AdminForth is available at http://localhost:${port}${ADMIN_BASE_URL}\\n`)\n});\n"})}),"\n",(0,r.jsx)(n.p,{children:"Now you can run your app:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"npm start\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Open ",(0,r.jsx)(n.a,{href:"http://localhost:3500",children:"http://localhost:3500"})," in your browser and login with credentials ",(0,r.jsx)(n.code,{children:"adminforth"})," / ",(0,r.jsx)(n.code,{children:"adminforth"}),"."]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.img,{alt:"alt text",src:t(8470).A+"",width:"3456",height:"2043"})}),"\n",(0,r.jsx)(n.p,{children:"After Login you should see:"}),"\n",(0,r.jsx)(n.h2,{id:"possible-configuration-options",children:"Possible configuration options"}),"\n",(0,r.jsx)(n.p,{children:"We will use schema with different column types for apartments to show many of AdminForth features."}),"\n",(0,r.jsxs)(n.p,{children:["Check ",(0,r.jsx)(n.a,{href:"/docs/api/types/AdminForthConfig/type-aliases/AdminForthConfig",children:"AdminForthConfig"})," for all possible options."]})]})}function p(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(c,{...e})}):c(e)}},8470:(e,n,t)=>{t.d(n,{A:()=>r});const r=t.p+"assets/images/image-4073119b1a64b412c6322c1917d972fc.png"},8453:(e,n,t)=>{t.d(n,{R:()=>i,x:()=>o});var r=t(6540);const s={},a=r.createContext(s);function i(e){const n=r.useContext(a);return r.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:i(e.components),r.createElement(a.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/7661071f.c8837661.js b/assets/js/7661071f.bdcf50cf.js similarity index 96% rename from assets/js/7661071f.c8837661.js rename to assets/js/7661071f.bdcf50cf.js index 60bb351dc..2c931a99a 100644 --- a/assets/js/7661071f.c8837661.js +++ b/assets/js/7661071f.bdcf50cf.js @@ -1 +1 @@ -"use strict";(self.webpackChunkadminforth=self.webpackChunkadminforth||[]).push([[8737],{4137:(e,o,n)=>{n.r(o),n.d(o,{assets:()=>i,contentTitle:()=>l,default:()=>d,frontMatter:()=>r,metadata:()=>a,toc:()=>c});var s=n(4848),t=n(8453);const r={slug:"welcome",title:"Welcome",authors:["slorber","yangshun"],tags:["facebook","hello","docusaurus"]},l=void 0,a={permalink:"/blog/welcome",source:"@site/blog/2021-08-26-welcome/index.md",title:"Welcome",description:"Docusaurus blogging features are powered by the blog plugin.",date:"2021-08-26T00:00:00.000Z",tags:[{inline:!1,label:"Facebook",permalink:"/blog/tags/facebook",description:"Facebook tag description"},{inline:!1,label:"Hello",permalink:"/blog/tags/hello",description:"Hello tag description"},{inline:!1,label:"Docusaurus",permalink:"/blog/tags/docusaurus",description:"Docusaurus tag description"}],readingTime:.405,hasTruncateMarker:!1,authors:[{name:"S\xe9bastien Lorber",title:"Docusaurus maintainer",url:"https://sebastienlorber.com",imageURL:"https://github.com/slorber.png",key:"slorber"},{name:"Yangshun Tay",title:"Front End Engineer @ Facebook",url:"https://github.com/yangshun",imageURL:"https://github.com/yangshun.png",key:"yangshun"}],frontMatter:{slug:"welcome",title:"Welcome",authors:["slorber","yangshun"],tags:["facebook","hello","docusaurus"]},unlisted:!1,nextItem:{title:"MDX Blog Post",permalink:"/blog/mdx-blog-post"}},i={authorsImageUrls:[void 0,void 0]},c=[];function u(e){const o={a:"a",code:"code",img:"img",li:"li",p:"p",strong:"strong",ul:"ul",...(0,t.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsxs)(o.p,{children:[(0,s.jsx)(o.a,{href:"https://docusaurus.io/docs/blog",children:"Docusaurus blogging features"})," are powered by the ",(0,s.jsx)(o.a,{href:"https://docusaurus.io/docs/api/plugins/@docusaurus/plugin-content-blog",children:"blog plugin"}),"."]}),"\n",(0,s.jsxs)(o.p,{children:["Simply add Markdown files (or folders) to the ",(0,s.jsx)(o.code,{children:"blog"})," directory."]}),"\n",(0,s.jsxs)(o.p,{children:["Regular blog authors can be added to ",(0,s.jsx)(o.code,{children:"authors.yml"}),"."]}),"\n",(0,s.jsx)(o.p,{children:"The blog post date can be extracted from filenames, such as:"}),"\n",(0,s.jsxs)(o.ul,{children:["\n",(0,s.jsx)(o.li,{children:(0,s.jsx)(o.code,{children:"2019-05-30-welcome.md"})}),"\n",(0,s.jsx)(o.li,{children:(0,s.jsx)(o.code,{children:"2019-05-30-welcome/index.md"})}),"\n"]}),"\n",(0,s.jsx)(o.p,{children:"A blog post folder can be convenient to co-locate blog post images:"}),"\n",(0,s.jsx)(o.p,{children:(0,s.jsx)(o.img,{alt:"Docusaurus Plushie",src:n(2793).A+"",width:"1500",height:"500"})}),"\n",(0,s.jsx)(o.p,{children:"The blog supports tags as well!"}),"\n",(0,s.jsxs)(o.p,{children:[(0,s.jsx)(o.strong,{children:"And if you don't want a blog"}),": just delete this directory, and use ",(0,s.jsx)(o.code,{children:"blog: false"})," in your Docusaurus config."]})]})}function d(e={}){const{wrapper:o}={...(0,t.R)(),...e.components};return o?(0,s.jsx)(o,{...e,children:(0,s.jsx)(u,{...e})}):u(e)}},2793:(e,o,n)=>{n.d(o,{A:()=>s});const s=n.p+"assets/images/docusaurus-plushie-banner-a60f7593abca1e3eef26a9afa244e4fb.jpeg"},8453:(e,o,n)=>{n.d(o,{R:()=>l,x:()=>a});var s=n(6540);const t={},r=s.createContext(t);function l(e){const o=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(o):{...o,...e}}),[o,e])}function a(e){let o;return o=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:l(e.components),s.createElement(r.Provider,{value:o},e.children)}}}]); \ No newline at end of file +"use strict";(self.webpackChunkadminforth=self.webpackChunkadminforth||[]).push([[8737],{4137:(e,o,n)=>{n.r(o),n.d(o,{assets:()=>i,contentTitle:()=>l,default:()=>d,frontMatter:()=>r,metadata:()=>a,toc:()=>c});var s=n(4848),t=n(8453);const r={slug:"welcome",title:"Welcome",authors:["slorber","yangshun"],tags:["facebook","hello","docusaurus"]},l=void 0,a={permalink:"/blog/welcome",source:"@site/blog/2021-08-26-welcome/index.md",title:"Welcome",description:"Docusaurus blogging features are powered by the blog plugin.",date:"2021-08-26T00:00:00.000Z",tags:[{inline:!1,label:"Facebook",permalink:"/blog/tags/facebook",description:"Facebook tag description"},{inline:!1,label:"Hello",permalink:"/blog/tags/hello",description:"Hello tag description"},{inline:!1,label:"Docusaurus",permalink:"/blog/tags/docusaurus",description:"Docusaurus tag description"}],readingTime:.405,hasTruncateMarker:!1,authors:[{name:"S\xe9bastien Lorber",title:"Docusaurus maintainer",url:"https://sebastienlorber.com",imageURL:"https://github.com/slorber.png",key:"slorber"},{name:"Yangshun Tay",title:"Front End Engineer @ Facebook",url:"https://github.com/yangshun",imageURL:"https://github.com/yangshun.png",key:"yangshun"}],frontMatter:{slug:"welcome",title:"Welcome",authors:["slorber","yangshun"],tags:["facebook","hello","docusaurus"]},unlisted:!1,nextItem:{title:"MDX Blog Post",permalink:"/blog/mdx-blog-post"}},i={authorsImageUrls:[void 0,void 0]},c=[];function u(e){const o={a:"a",code:"code",img:"img",li:"li",p:"p",strong:"strong",ul:"ul",...(0,t.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsxs)(o.p,{children:[(0,s.jsx)(o.a,{href:"https://docusaurus.io/docs/blog",children:"Docusaurus blogging features"})," are powered by the ",(0,s.jsx)(o.a,{href:"https://docusaurus.io/docs/api/plugins/@docusaurus/plugin-content-blog",children:"blog plugin"}),"."]}),"\n",(0,s.jsxs)(o.p,{children:["Simply add Markdown files (or folders) to the ",(0,s.jsx)(o.code,{children:"blog"})," directory."]}),"\n",(0,s.jsxs)(o.p,{children:["Regular blog authors can be added to ",(0,s.jsx)(o.code,{children:"authors.yml"}),"."]}),"\n",(0,s.jsx)(o.p,{children:"The blog post date can be extracted from filenames, such as:"}),"\n",(0,s.jsxs)(o.ul,{children:["\n",(0,s.jsx)(o.li,{children:(0,s.jsx)(o.code,{children:"2019-05-30-welcome.md"})}),"\n",(0,s.jsx)(o.li,{children:(0,s.jsx)(o.code,{children:"2019-05-30-welcome/index.md"})}),"\n"]}),"\n",(0,s.jsx)(o.p,{children:"A blog post folder can be convenient to co-locate blog post images:"}),"\n",(0,s.jsx)(o.p,{children:(0,s.jsx)(o.img,{alt:"Docusaurus Plushie",src:n(7450).A+"",width:"1500",height:"500"})}),"\n",(0,s.jsx)(o.p,{children:"The blog supports tags as well!"}),"\n",(0,s.jsxs)(o.p,{children:[(0,s.jsx)(o.strong,{children:"And if you don't want a blog"}),": just delete this directory, and use ",(0,s.jsx)(o.code,{children:"blog: false"})," in your Docusaurus config."]})]})}function d(e={}){const{wrapper:o}={...(0,t.R)(),...e.components};return o?(0,s.jsx)(o,{...e,children:(0,s.jsx)(u,{...e})}):u(e)}},7450:(e,o,n)=>{n.d(o,{A:()=>s});const s=n.p+"assets/images/docusaurus-plushie-banner-a60f7593abca1e3eef26a9afa244e4fb.jpeg"},8453:(e,o,n)=>{n.d(o,{R:()=>l,x:()=>a});var s=n(6540);const t={},r=s.createContext(t);function l(e){const o=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(o):{...o,...e}}),[o,e])}function a(e){let o;return o=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:l(e.components),s.createElement(r.Provider,{value:o},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/9c3f971e.9a6788a7.js b/assets/js/9c3f971e.9a6788a7.js deleted file mode 100644 index a0e308a66..000000000 --- a/assets/js/9c3f971e.9a6788a7.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkadminforth=self.webpackChunkadminforth||[]).push([[510],{4060:(e,n,s)=>{s.r(n),s.d(n,{assets:()=>d,contentTitle:()=>i,default:()=>u,frontMatter:()=>r,metadata:()=>a,toc:()=>c});var o=s(4848),t=s(8453);const r={},i="Customization",a={id:"customization",title:"Customization",description:"Here is how you can customize the AdminForth to fit your needs.",source:"@site/docs/03-customization.md",sourceDirName:".",slug:"/customization",permalink:"/docs/customization",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:3,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Glossary",permalink:"/docs/glossary"},next:{title:"AuditLog",permalink:"/docs/Plugins/AuditLog"}},d={},c=[{value:"Customizing how AdminForth renders the cells with record values",id:"customizing-how-adminforth-renders-the-cells-with-record-values",level:2},{value:"Hooks",id:"hooks",level:2},{value:"Modify the data before it is saved to the database",id:"modify-the-data-before-it-is-saved-to-the-database",level:3},{value:"Limiting access to the resource actions",id:"limiting-access-to-the-resource-actions",level:2},{value:"Statically disable some action",id:"statically-disable-some-action",level:3},{value:"Disable some action based on logged in user record or role",id:"disable-some-action-based-on-logged-in-user-record-or-role",level:3},{value:"Reuse the same callback for multiple actions",id:"reuse-the-same-callback-for-multiple-actions",level:3},{value:"Customizing the access control based on resource values",id:"customizing-the-access-control-based-on-resource-values",level:3}];function l(e){const n={a:"a",blockquote:"blockquote",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",ul:"ul",...(0,t.R)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(n.h1,{id:"customization",children:"Customization"}),"\n",(0,o.jsx)(n.p,{children:"Here is how you can customize the AdminForth to fit your needs."}),"\n",(0,o.jsx)(n.h2,{id:"customizing-how-adminforth-renders-the-cells-with-record-values",children:"Customizing how AdminForth renders the cells with record values"}),"\n",(0,o.jsxs)(n.p,{children:["Let's change how AdminForth renders the number of rooms in the 'list' and 'show' views.\nWe will render '\ud83d\udfe8' for each room and then we will print ",(0,o.jsx)(n.code,{children:"square_meter"})," at the same cells."]}),"\n",(0,o.jsxs)(n.p,{children:["Create directory ",(0,o.jsx)(n.code,{children:"custom"}),". Create a file ",(0,o.jsx)(n.code,{children:"RoomsCell.vue"})," in it:"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-vue",children:'\n\n + diff --git a/blog/first-blog-post/index.html b/blog/first-blog-post/index.html index fe716c944..01f9bd98a 100644 --- a/blog/first-blog-post/index.html +++ b/blog/first-blog-post/index.html @@ -5,7 +5,7 @@ First Blog Post | AdminForth - + diff --git a/blog/index.html b/blog/index.html index fba393daa..937dc6eb6 100644 --- a/blog/index.html +++ b/blog/index.html @@ -5,7 +5,7 @@ Blog | AdminForth - + diff --git a/blog/long-blog-post/index.html b/blog/long-blog-post/index.html index d038ca9ab..c38393617 100644 --- a/blog/long-blog-post/index.html +++ b/blog/long-blog-post/index.html @@ -5,7 +5,7 @@ Long Blog Post | AdminForth - + diff --git a/blog/mdx-blog-post/index.html b/blog/mdx-blog-post/index.html index 8062185a4..3757a71ee 100644 --- a/blog/mdx-blog-post/index.html +++ b/blog/mdx-blog-post/index.html @@ -5,7 +5,7 @@ MDX Blog Post | AdminForth - + diff --git a/blog/tags/docusaurus/index.html b/blog/tags/docusaurus/index.html index 40d9568b2..7abe2772c 100644 --- a/blog/tags/docusaurus/index.html +++ b/blog/tags/docusaurus/index.html @@ -5,7 +5,7 @@ 4 posts tagged with "Docusaurus" | AdminForth - + diff --git a/blog/tags/facebook/index.html b/blog/tags/facebook/index.html index c584cee92..075c4a08c 100644 --- a/blog/tags/facebook/index.html +++ b/blog/tags/facebook/index.html @@ -5,7 +5,7 @@ One post tagged with "Facebook" | AdminForth - + diff --git a/blog/tags/hello/index.html b/blog/tags/hello/index.html index 5693cf89a..ac8a97299 100644 --- a/blog/tags/hello/index.html +++ b/blog/tags/hello/index.html @@ -5,7 +5,7 @@ 2 posts tagged with "Hello" | AdminForth - + diff --git a/blog/tags/hola/index.html b/blog/tags/hola/index.html index 5277b67fb..74aecb62b 100644 --- a/blog/tags/hola/index.html +++ b/blog/tags/hola/index.html @@ -5,7 +5,7 @@ One post tagged with "Hola" | AdminForth - + diff --git a/blog/tags/index.html b/blog/tags/index.html index 16c17ea23..ef2c391f6 100644 --- a/blog/tags/index.html +++ b/blog/tags/index.html @@ -5,7 +5,7 @@ Tags | AdminForth - + diff --git a/blog/welcome/index.html b/blog/welcome/index.html index 564edacfe..874c8d1e2 100644 --- a/blog/welcome/index.html +++ b/blog/welcome/index.html @@ -5,7 +5,7 @@ Welcome | AdminForth - + diff --git a/docs/Plugins/AuditLog/index.html b/docs/Plugins/AuditLog/index.html index 82778ba04..6cc94cd8d 100644 --- a/docs/Plugins/AuditLog/index.html +++ b/docs/Plugins/AuditLog/index.html @@ -5,7 +5,7 @@ AuditLog | AdminForth - + diff --git a/docs/Plugins/ForeignInlineList/index.html b/docs/Plugins/ForeignInlineList/index.html index 4d23e9631..53efcab31 100644 --- a/docs/Plugins/ForeignInlineList/index.html +++ b/docs/Plugins/ForeignInlineList/index.html @@ -5,7 +5,7 @@ ForeignInlineList | AdminForth - + diff --git a/docs/api/index.html b/docs/api/index.html index 32ea7f6d9..d5975e03a 100644 --- a/docs/api/index.html +++ b/docs/api/index.html @@ -5,7 +5,7 @@ TypeDoc API | AdminForth - + diff --git a/docs/api/plugins/AuditLog/types/index.html b/docs/api/plugins/AuditLog/types/index.html index d907aa5ea..74b986089 100644 --- a/docs/api/plugins/AuditLog/types/index.html +++ b/docs/api/plugins/AuditLog/types/index.html @@ -5,7 +5,7 @@ plugins/AuditLog/types | AdminForth - + diff --git a/docs/api/plugins/AuditLog/types/type-aliases/PluginOptions/index.html b/docs/api/plugins/AuditLog/types/type-aliases/PluginOptions/index.html index fa860a61d..b6b90aeb6 100644 --- a/docs/api/plugins/AuditLog/types/type-aliases/PluginOptions/index.html +++ b/docs/api/plugins/AuditLog/types/type-aliases/PluginOptions/index.html @@ -5,7 +5,7 @@ PluginOptions | AdminForth - + diff --git a/docs/api/plugins/ForeignInlineListPlugin/types/index.html b/docs/api/plugins/ForeignInlineListPlugin/types/index.html index 927d34f0f..11983a7fa 100644 --- a/docs/api/plugins/ForeignInlineListPlugin/types/index.html +++ b/docs/api/plugins/ForeignInlineListPlugin/types/index.html @@ -5,7 +5,7 @@ plugins/ForeignInlineListPlugin/types | AdminForth - + 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 5d5d333ff..b00213ae4 100644 --- a/docs/api/plugins/ForeignInlineListPlugin/types/type-aliases/PluginOptions/index.html +++ b/docs/api/plugins/ForeignInlineListPlugin/types/type-aliases/PluginOptions/index.html @@ -5,7 +5,7 @@ PluginOptions | AdminForth - + diff --git a/docs/api/types/AdminForthConfig/enumerations/ActionCheckSource/index.html b/docs/api/types/AdminForthConfig/enumerations/ActionCheckSource/index.html index 30a7758e7..9c5770e0f 100644 --- a/docs/api/types/AdminForthConfig/enumerations/ActionCheckSource/index.html +++ b/docs/api/types/AdminForthConfig/enumerations/ActionCheckSource/index.html @@ -5,7 +5,7 @@ ActionCheckSource | AdminForth - + diff --git a/docs/api/types/AdminForthConfig/enumerations/AdminForthDataTypes/index.html b/docs/api/types/AdminForthConfig/enumerations/AdminForthDataTypes/index.html index 0aadae0e6..89cc3f426 100644 --- a/docs/api/types/AdminForthConfig/enumerations/AdminForthDataTypes/index.html +++ b/docs/api/types/AdminForthConfig/enumerations/AdminForthDataTypes/index.html @@ -5,7 +5,7 @@ AdminForthDataTypes | AdminForth - + diff --git a/docs/api/types/AdminForthConfig/enumerations/AdminForthFilterOperators/index.html b/docs/api/types/AdminForthConfig/enumerations/AdminForthFilterOperators/index.html index 112474303..99b322f1a 100644 --- a/docs/api/types/AdminForthConfig/enumerations/AdminForthFilterOperators/index.html +++ b/docs/api/types/AdminForthConfig/enumerations/AdminForthFilterOperators/index.html @@ -5,7 +5,7 @@ AdminForthFilterOperators | AdminForth - + diff --git a/docs/api/types/AdminForthConfig/enumerations/AdminForthMenuTypes/index.html b/docs/api/types/AdminForthConfig/enumerations/AdminForthMenuTypes/index.html index 92bd26bcd..ed3347b9e 100644 --- a/docs/api/types/AdminForthConfig/enumerations/AdminForthMenuTypes/index.html +++ b/docs/api/types/AdminForthConfig/enumerations/AdminForthMenuTypes/index.html @@ -5,7 +5,7 @@ AdminForthMenuTypes | AdminForth - + diff --git a/docs/api/types/AdminForthConfig/enumerations/AdminForthResourcePages/index.html b/docs/api/types/AdminForthConfig/enumerations/AdminForthResourcePages/index.html index 82d0c18de..679756f20 100644 --- a/docs/api/types/AdminForthConfig/enumerations/AdminForthResourcePages/index.html +++ b/docs/api/types/AdminForthConfig/enumerations/AdminForthResourcePages/index.html @@ -5,7 +5,7 @@ AdminForthResourcePages | AdminForth - + diff --git a/docs/api/types/AdminForthConfig/enumerations/AdminForthSortDirections/index.html b/docs/api/types/AdminForthConfig/enumerations/AdminForthSortDirections/index.html index e3de03209..ad7bd3f16 100644 --- a/docs/api/types/AdminForthConfig/enumerations/AdminForthSortDirections/index.html +++ b/docs/api/types/AdminForthConfig/enumerations/AdminForthSortDirections/index.html @@ -5,7 +5,7 @@ AdminForthSortDirections | AdminForth - + diff --git a/docs/api/types/AdminForthConfig/enumerations/AllowedActionsEnum/index.html b/docs/api/types/AdminForthConfig/enumerations/AllowedActionsEnum/index.html index f8639bff7..6f0028b38 100644 --- a/docs/api/types/AdminForthConfig/enumerations/AllowedActionsEnum/index.html +++ b/docs/api/types/AdminForthConfig/enumerations/AllowedActionsEnum/index.html @@ -5,7 +5,7 @@ AllowedActionsEnum | AdminForth - + diff --git a/docs/api/types/AdminForthConfig/index.html b/docs/api/types/AdminForthConfig/index.html index c1f1f4f31..3f1acb2b0 100644 --- a/docs/api/types/AdminForthConfig/index.html +++ b/docs/api/types/AdminForthConfig/index.html @@ -5,7 +5,7 @@ types/AdminForthConfig | AdminForth - + diff --git a/docs/api/types/AdminForthConfig/interfaces/AdminForthClass/index.html b/docs/api/types/AdminForthConfig/interfaces/AdminForthClass/index.html index 37180369b..e0141f01d 100644 --- a/docs/api/types/AdminForthConfig/interfaces/AdminForthClass/index.html +++ b/docs/api/types/AdminForthConfig/interfaces/AdminForthClass/index.html @@ -5,7 +5,7 @@ AdminForthClass | AdminForth - + diff --git a/docs/api/types/AdminForthConfig/interfaces/AdminForthPluginType/index.html b/docs/api/types/AdminForthConfig/interfaces/AdminForthPluginType/index.html index 9e206301c..227daa0f0 100644 --- a/docs/api/types/AdminForthConfig/interfaces/AdminForthPluginType/index.html +++ b/docs/api/types/AdminForthConfig/interfaces/AdminForthPluginType/index.html @@ -5,7 +5,7 @@ AdminForthPluginType | AdminForth - + diff --git a/docs/api/types/AdminForthConfig/interfaces/CodeInjectorType/index.html b/docs/api/types/AdminForthConfig/interfaces/CodeInjectorType/index.html index 5c2e974fa..a1449cb32 100644 --- a/docs/api/types/AdminForthConfig/interfaces/CodeInjectorType/index.html +++ b/docs/api/types/AdminForthConfig/interfaces/CodeInjectorType/index.html @@ -5,7 +5,7 @@ CodeInjectorType | AdminForth - + diff --git a/docs/api/types/AdminForthConfig/interfaces/ExpressHttpServer/index.html b/docs/api/types/AdminForthConfig/interfaces/ExpressHttpServer/index.html index 3666ea79b..ea67d9e12 100644 --- a/docs/api/types/AdminForthConfig/interfaces/ExpressHttpServer/index.html +++ b/docs/api/types/AdminForthConfig/interfaces/ExpressHttpServer/index.html @@ -5,7 +5,7 @@ ExpressHttpServer | AdminForth - + diff --git a/docs/api/types/AdminForthConfig/interfaces/GenericHttpServer/index.html b/docs/api/types/AdminForthConfig/interfaces/GenericHttpServer/index.html index dcaf8c158..a9d8f389c 100644 --- a/docs/api/types/AdminForthConfig/interfaces/GenericHttpServer/index.html +++ b/docs/api/types/AdminForthConfig/interfaces/GenericHttpServer/index.html @@ -5,7 +5,7 @@ GenericHttpServer | AdminForth - + diff --git a/docs/api/types/AdminForthConfig/type-aliases/AdminForthColumnEnumItem/index.html b/docs/api/types/AdminForthConfig/type-aliases/AdminForthColumnEnumItem/index.html index 45b00259a..b582ebd0a 100644 --- a/docs/api/types/AdminForthConfig/type-aliases/AdminForthColumnEnumItem/index.html +++ b/docs/api/types/AdminForthConfig/type-aliases/AdminForthColumnEnumItem/index.html @@ -5,7 +5,7 @@ AdminForthColumnEnumItem | AdminForth - + diff --git a/docs/api/types/AdminForthConfig/type-aliases/AdminForthComponentDeclaration/index.html b/docs/api/types/AdminForthConfig/type-aliases/AdminForthComponentDeclaration/index.html index 0e259db68..6f7c5aee7 100644 --- a/docs/api/types/AdminForthConfig/type-aliases/AdminForthComponentDeclaration/index.html +++ b/docs/api/types/AdminForthConfig/type-aliases/AdminForthComponentDeclaration/index.html @@ -5,7 +5,7 @@ AdminForthComponentDeclaration | AdminForth - + diff --git a/docs/api/types/AdminForthConfig/type-aliases/AdminForthComponentDeclarationFull/index.html b/docs/api/types/AdminForthConfig/type-aliases/AdminForthComponentDeclarationFull/index.html index 4566c5d1c..1a5af3570 100644 --- a/docs/api/types/AdminForthConfig/type-aliases/AdminForthComponentDeclarationFull/index.html +++ b/docs/api/types/AdminForthConfig/type-aliases/AdminForthComponentDeclarationFull/index.html @@ -5,7 +5,7 @@ AdminForthComponentDeclarationFull | AdminForth - + diff --git a/docs/api/types/AdminForthConfig/type-aliases/AdminForthConfig/index.html b/docs/api/types/AdminForthConfig/type-aliases/AdminForthConfig/index.html index 3e541021d..597c6eb05 100644 --- a/docs/api/types/AdminForthConfig/type-aliases/AdminForthConfig/index.html +++ b/docs/api/types/AdminForthConfig/type-aliases/AdminForthConfig/index.html @@ -5,7 +5,7 @@ AdminForthConfig | AdminForth - + @@ -90,12 +90,24 @@

cus

optional datesFormat: string

-

DayJS format string for all dates in the app

+

favicon?: string,

+

/**

+
    +
  • DayJS format string for all dates in the app
  • +

customization.emptyFieldPlaceholder?​

optional emptyFieldPlaceholder: object | string

Placeholder for empty fields in lists and show views, by default empty string ''

+

customization.favicon?​

+
+

optional favicon: string

+
+

Path to your app favicon

+

Example: +Place file favicon.png to ./custom folder and set this option:

+
favicon: '@@/favicon.png',

customization.title?​

optional title: string

@@ -161,6 +173,6 @@

rootUser.us

styles?​

optional styles: Object

-
+
\ No newline at end of file diff --git a/docs/api/types/AdminForthConfig/type-aliases/AdminForthConfigMenuItem/index.html b/docs/api/types/AdminForthConfig/type-aliases/AdminForthConfigMenuItem/index.html index 5a74b83a2..1199379a4 100644 --- a/docs/api/types/AdminForthConfig/type-aliases/AdminForthConfigMenuItem/index.html +++ b/docs/api/types/AdminForthConfig/type-aliases/AdminForthConfigMenuItem/index.html @@ -5,7 +5,7 @@ AdminForthConfigMenuItem | AdminForth - + diff --git a/docs/api/types/AdminForthConfig/type-aliases/AdminForthDataSource/index.html b/docs/api/types/AdminForthConfig/type-aliases/AdminForthDataSource/index.html index eca8f9615..ff92097ad 100644 --- a/docs/api/types/AdminForthConfig/type-aliases/AdminForthDataSource/index.html +++ b/docs/api/types/AdminForthConfig/type-aliases/AdminForthDataSource/index.html @@ -5,7 +5,7 @@ AdminForthDataSource | AdminForth - + diff --git a/docs/api/types/AdminForthConfig/type-aliases/AdminForthFieldComponents/index.html b/docs/api/types/AdminForthConfig/type-aliases/AdminForthFieldComponents/index.html index ab8c71064..f2d6b85a5 100644 --- a/docs/api/types/AdminForthConfig/type-aliases/AdminForthFieldComponents/index.html +++ b/docs/api/types/AdminForthConfig/type-aliases/AdminForthFieldComponents/index.html @@ -5,7 +5,7 @@ AdminForthFieldComponents | AdminForth - + diff --git a/docs/api/types/AdminForthConfig/type-aliases/AdminForthForeignResource/index.html b/docs/api/types/AdminForthConfig/type-aliases/AdminForthForeignResource/index.html index 78d10e69c..e89a0e488 100644 --- a/docs/api/types/AdminForthConfig/type-aliases/AdminForthForeignResource/index.html +++ b/docs/api/types/AdminForthConfig/type-aliases/AdminForthForeignResource/index.html @@ -5,7 +5,7 @@ AdminForthForeignResource | AdminForth - + diff --git a/docs/api/types/AdminForthConfig/type-aliases/AdminForthResource/index.html b/docs/api/types/AdminForthConfig/type-aliases/AdminForthResource/index.html index 80c9c5d03..644d7043b 100644 --- a/docs/api/types/AdminForthConfig/type-aliases/AdminForthResource/index.html +++ b/docs/api/types/AdminForthConfig/type-aliases/AdminForthResource/index.html @@ -5,7 +5,7 @@ AdminForthResource | AdminForth - + diff --git a/docs/api/types/AdminForthConfig/type-aliases/AdminForthResourceColumn/index.html b/docs/api/types/AdminForthConfig/type-aliases/AdminForthResourceColumn/index.html index 9afea00c4..201f20eb9 100644 --- a/docs/api/types/AdminForthConfig/type-aliases/AdminForthResourceColumn/index.html +++ b/docs/api/types/AdminForthConfig/type-aliases/AdminForthResourceColumn/index.html @@ -5,7 +5,7 @@ AdminForthResourceColumn | AdminForth - + diff --git a/docs/api/types/AdminForthConfig/type-aliases/AdminUser/index.html b/docs/api/types/AdminForthConfig/type-aliases/AdminUser/index.html index 9a0621bee..3a515d665 100644 --- a/docs/api/types/AdminForthConfig/type-aliases/AdminUser/index.html +++ b/docs/api/types/AdminForthConfig/type-aliases/AdminUser/index.html @@ -5,7 +5,7 @@ AdminUser | AdminForth - + diff --git a/docs/api/types/AdminForthConfig/type-aliases/AfterDataSourceResponseFunction/index.html b/docs/api/types/AdminForthConfig/type-aliases/AfterDataSourceResponseFunction/index.html index b959920a9..d14b3e119 100644 --- a/docs/api/types/AdminForthConfig/type-aliases/AfterDataSourceResponseFunction/index.html +++ b/docs/api/types/AdminForthConfig/type-aliases/AfterDataSourceResponseFunction/index.html @@ -5,7 +5,7 @@ AfterDataSourceResponseFunction() | AdminForth - + diff --git a/docs/api/types/AdminForthConfig/type-aliases/AfterSaveFunction/index.html b/docs/api/types/AdminForthConfig/type-aliases/AfterSaveFunction/index.html index 0c543084b..14491bf7c 100644 --- a/docs/api/types/AdminForthConfig/type-aliases/AfterSaveFunction/index.html +++ b/docs/api/types/AdminForthConfig/type-aliases/AfterSaveFunction/index.html @@ -5,7 +5,7 @@ AfterSaveFunction() | AdminForth - + diff --git a/docs/api/types/AdminForthConfig/type-aliases/AllowedActionValue/index.html b/docs/api/types/AdminForthConfig/type-aliases/AllowedActionValue/index.html index f587e4e51..9e0255074 100644 --- a/docs/api/types/AdminForthConfig/type-aliases/AllowedActionValue/index.html +++ b/docs/api/types/AdminForthConfig/type-aliases/AllowedActionValue/index.html @@ -5,7 +5,7 @@ AllowedActionValue | AdminForth - + diff --git a/docs/api/types/AdminForthConfig/type-aliases/AllowedActions/index.html b/docs/api/types/AdminForthConfig/type-aliases/AllowedActions/index.html index 613c0caec..23021e50f 100644 --- a/docs/api/types/AdminForthConfig/type-aliases/AllowedActions/index.html +++ b/docs/api/types/AdminForthConfig/type-aliases/AllowedActions/index.html @@ -5,7 +5,7 @@ AllowedActions | AdminForth - + diff --git a/docs/api/types/AdminForthConfig/type-aliases/BeforeDataSourceRequestFunction/index.html b/docs/api/types/AdminForthConfig/type-aliases/BeforeDataSourceRequestFunction/index.html index bbf4fe490..8c081d47c 100644 --- a/docs/api/types/AdminForthConfig/type-aliases/BeforeDataSourceRequestFunction/index.html +++ b/docs/api/types/AdminForthConfig/type-aliases/BeforeDataSourceRequestFunction/index.html @@ -5,7 +5,7 @@ BeforeDataSourceRequestFunction() | AdminForth - + diff --git a/docs/api/types/AdminForthConfig/type-aliases/BeforeSaveFunction/index.html b/docs/api/types/AdminForthConfig/type-aliases/BeforeSaveFunction/index.html index 866a042ef..2e06f1583 100644 --- a/docs/api/types/AdminForthConfig/type-aliases/BeforeSaveFunction/index.html +++ b/docs/api/types/AdminForthConfig/type-aliases/BeforeSaveFunction/index.html @@ -5,7 +5,7 @@ BeforeSaveFunction() | AdminForth - + diff --git a/docs/api/types/AdminForthConfig/type-aliases/ValidationObject/index.html b/docs/api/types/AdminForthConfig/type-aliases/ValidationObject/index.html index 31aba2f4b..3a959a411 100644 --- a/docs/api/types/AdminForthConfig/type-aliases/ValidationObject/index.html +++ b/docs/api/types/AdminForthConfig/type-aliases/ValidationObject/index.html @@ -5,7 +5,7 @@ ValidationObject | AdminForth - + diff --git a/docs/api/types/FrontendAPI/enumerations/AlertVariant/index.html b/docs/api/types/FrontendAPI/enumerations/AlertVariant/index.html index 2ae7ccff7..490c0e140 100644 --- a/docs/api/types/FrontendAPI/enumerations/AlertVariant/index.html +++ b/docs/api/types/FrontendAPI/enumerations/AlertVariant/index.html @@ -5,7 +5,7 @@ AlertVariant | AdminForth - + diff --git a/docs/api/types/FrontendAPI/index.html b/docs/api/types/FrontendAPI/index.html index dc963a0fd..95b68db18 100644 --- a/docs/api/types/FrontendAPI/index.html +++ b/docs/api/types/FrontendAPI/index.html @@ -5,7 +5,7 @@ types/FrontendAPI | AdminForth - + diff --git a/docs/api/types/FrontendAPI/interfaces/FrontendAPIInterface/index.html b/docs/api/types/FrontendAPI/interfaces/FrontendAPIInterface/index.html index 06b6dc074..fb8eb46f0 100644 --- a/docs/api/types/FrontendAPI/interfaces/FrontendAPIInterface/index.html +++ b/docs/api/types/FrontendAPI/interfaces/FrontendAPIInterface/index.html @@ -5,7 +5,7 @@ FrontendAPIInterface | AdminForth - + diff --git a/docs/api/types/FrontendAPI/type-aliases/AlertParams/index.html b/docs/api/types/FrontendAPI/type-aliases/AlertParams/index.html index 11f53904a..cad3ab533 100644 --- a/docs/api/types/FrontendAPI/type-aliases/AlertParams/index.html +++ b/docs/api/types/FrontendAPI/type-aliases/AlertParams/index.html @@ -5,7 +5,7 @@ AlertParams | AdminForth - + diff --git a/docs/api/types/FrontendAPI/type-aliases/ConfirmParams/index.html b/docs/api/types/FrontendAPI/type-aliases/ConfirmParams/index.html index 61514bbdc..3d0c96740 100644 --- a/docs/api/types/FrontendAPI/type-aliases/ConfirmParams/index.html +++ b/docs/api/types/FrontendAPI/type-aliases/ConfirmParams/index.html @@ -5,7 +5,7 @@ ConfirmParams | AdminForth - + diff --git a/docs/api/types/FrontendAPI/type-aliases/FilterParams/index.html b/docs/api/types/FrontendAPI/type-aliases/FilterParams/index.html index ddbb9f8c3..17dfb45a2 100644 --- a/docs/api/types/FrontendAPI/type-aliases/FilterParams/index.html +++ b/docs/api/types/FrontendAPI/type-aliases/FilterParams/index.html @@ -5,7 +5,7 @@ FilterParams | AdminForth - + diff --git a/docs/api/types/FrontendAPI/type-aliases/Operator/index.html b/docs/api/types/FrontendAPI/type-aliases/Operator/index.html index 384d97dd4..033b021b7 100644 --- a/docs/api/types/FrontendAPI/type-aliases/Operator/index.html +++ b/docs/api/types/FrontendAPI/type-aliases/Operator/index.html @@ -5,7 +5,7 @@ Operator | AdminForth - + diff --git a/docs/customization/index.html b/docs/customization/index.html index de9d5c725..b2c950240 100644 --- a/docs/customization/index.html +++ b/docs/customization/index.html @@ -5,7 +5,7 @@ Customization | AdminForth - + @@ -17,7 +17,7 @@

<template>
<div class="flex items-center">
<span v-for="room in record.number_of_rooms">
🟨
</span>

{{ room.square_meter }} m²
</div>
</template>

<script setup>
defineProps({
record: Object
});
</script>

Now you can use this component in the configuration of the resource:

-
{
...
resourceId: 'apparts',
...
columns: [
...
{
...
name: 'number_of_rooms',
...
components: {
show: 'custom/RoomsCell.vue',
list: 'custom/RoomsCell.vue',
}
},
...
],
...
}
+
{
...
resourceId: 'apparts',
...
columns: [
...
{
...
name: 'number_of_rooms',
...
components: {
show: '@@/RoomsCell.vue',
list: '@@/RoomsCell.vue',
}
},
...
],
...
}

Hooks​

Hooks are used to:

    @@ -25,7 +25,7 @@

    HooksallowedActions for this) +
  • prevent the request to db depending on some condition (Better use allowedActions for this)

Modify the data before it is saved to the database​

Let's add id to adminUser when user creates a new appartment:

@@ -49,6 +49,6 @@

Customizing the access control based on resource values​

More advanced case, allow to edit apartments only if user is owner of the apartment (defined as user_id), otherwise return error "You are not assigned to this apartment and can't edit it":

-
import type { AdminUser, ActionCheckSource } from  'adminforth/types/AdminForthConfig.js';

async function canModifyAppart({ adminUser, source, meta }: { adminUser: AdminUser, meta: any, source: ActionCheckSource }): boolean {
if (source === ActionCheckSource.DisplayButtons) {
// if check is done for displaying button - we show button to everyone
return true;
}
if (adminUser.isRoot) {
return false; //root user is not in db so can't be assigned
}
const { oldRecord, newRecord } = meta;
if (oldRecord.user_id !== adminUser.dbUser.id) {
return "You are not assigned to this apartment and can't edit it";
}
if (newRecord.user_id !== oldRecord.user_id) {
return "You can't change the owner of the apartment";
}
return true;
}


{
...
resourceId: 'apparts',
...
options: {
allowedActions: {
edit: canModifyAppart,
}
...
}
}
+
import type { AdminUser, ActionCheckSource } from  'adminforth/types/AdminForthConfig.js';

async function canModifyAppart({ adminUser, source, meta }: { adminUser: AdminUser, meta: any, source: ActionCheckSource }): boolean {
if (source === ActionCheckSource.DisplayButtons) {
// if check is done for displaying button - we show button to everyone
return true;
}
if (adminUser.isRoot) {
return "Root user can't create appartment, relogin as DB user";
}
const { oldRecord, newRecord } = meta;
if (oldRecord.user_id !== adminUser.dbUser.id) {
return "You are not assigned to this apartment and can't edit it";
}
if (newRecord.user_id !== oldRecord.user_id) {
return "You can't change the owner of the apartment";
}
return true;
}


{
...
resourceId: 'apparts',
...
options: {
allowedActions: {
edit: canModifyAppart,
}
...
}
}
\ No newline at end of file diff --git a/docs/gettingStarted/index.html b/docs/gettingStarted/index.html index 4302f078c..cc70c0bc4 100644 --- a/docs/gettingStarted/index.html +++ b/docs/gettingStarted/index.html @@ -5,7 +5,7 @@ Getting Started | AdminForth - + diff --git a/docs/glossary/index.html b/docs/glossary/index.html index fa7cb8e74..2032c0698 100644 --- a/docs/glossary/index.html +++ b/docs/glossary/index.html @@ -5,7 +5,7 @@ Glossary | AdminForth - + diff --git a/index.html b/index.html index 46de4176f..d911387c0 100644 --- a/index.html +++ b/index.html @@ -5,7 +5,7 @@ AdminForth | AdminForth - + diff --git a/markdown-page/index.html b/markdown-page/index.html index 039f70b9b..7a5cde96c 100644 --- a/markdown-page/index.html +++ b/markdown-page/index.html @@ -5,7 +5,7 @@ Markdown page example | AdminForth - +