Browse Source

docs: More dashboard docs

Michael Bromley 3 months ago
parent
commit
a3606bb708

BIN
docs/docs/guides/extending-the-dashboard/action-bar-items/action-bar-button.webp


BIN
docs/docs/guides/extending-the-dashboard/action-bar-items/action-bar-dropdown.webp


+ 35 - 7
docs/docs/guides/extending-the-dashboard/action-bar-items/index.md

@@ -2,10 +2,12 @@
 title: 'Action Bar Items'
 title: 'Action Bar Items'
 ---
 ---
 
 
-Like in the old Admin UI, we have the concept of the "action bar", which is the bar at the top of the page where you can add
+The Action Bar is the bar at the top of the page where you can add
 buttons and other actions.
 buttons and other actions.
 
 
-Currently, we only support adding buttons, but dropdown menu support is coming soon.
+:::info
+All available options are documented in the [DashboardActionBarItem reference](/reference/dashboard/extensions-api/action-bar#dashboardactionbaritem)
+:::
 
 
 ## Basic Action Bar Item
 ## Basic Action Bar Item
 
 
@@ -15,7 +17,7 @@ Here's a simple example of adding a button to the action bar:
 import { Button, defineDashboardExtension } from '@vendure/dashboard';
 import { Button, defineDashboardExtension } from '@vendure/dashboard';
 import { useState } from 'react';
 import { useState } from 'react';
 
 
-export default defineDashboardExtension({
+defineDashboardExtension({
     actionBarItems: [
     actionBarItems: [
         {
         {
             pageId: 'product-detail',
             pageId: 'product-detail',
@@ -32,6 +34,8 @@ export default defineDashboardExtension({
 });
 });
 ```
 ```
 
 
+![Action bar button](./action-bar-button.webp)
+
 ## Context Data
 ## Context Data
 
 
 The `context` prop provides access to:
 The `context` prop provides access to:
@@ -40,6 +44,30 @@ The `context` prop provides access to:
 - **`form`**: The React Hook Form instance for the current page (if applicable)
 - **`form`**: The React Hook Form instance for the current page (if applicable)
 - **`route`**: Route information and parameters
 - **`route`**: Route information and parameters
 
 
+## Dropdown Menu
+
+You can also define dropdown menu items for the Action Bar. This is useful for secondary actions that are needed
+less often by administrators.
+
+Make sure to always wrap these in the `DropdownMenuItem` component for consistent styling.
+
+```tsx
+import { DropdownMenuItem, defineDashboardExtension } from '@vendure/dashboard';
+import { useState } from 'react';
+
+defineDashboardExtension({
+    actionBarItems: [
+        {
+            pageId: 'product-list',
+            type: 'dropdown',
+            component: () => <DropdownMenuItem variant="default">My Item</DropdownMenuItem>
+        }
+    ],
+});
+```
+
+![Action bar dropdown](./action-bar-dropdown.webp)
+
 ## Practical Examples
 ## Practical Examples
 
 
 ### Export Button
 ### Export Button
@@ -48,7 +76,7 @@ The `context` prop provides access to:
 import { Button, defineDashboardExtension } from '@vendure/dashboard';
 import { Button, defineDashboardExtension } from '@vendure/dashboard';
 import { DownloadIcon } from 'lucide-react';
 import { DownloadIcon } from 'lucide-react';
 
 
-export default defineDashboardExtension({
+defineDashboardExtension({
     actionBarItems: [
     actionBarItems: [
         {
         {
             pageId: 'product-detail',
             pageId: 'product-detail',
@@ -89,7 +117,7 @@ import { RefreshCwIcon } from 'lucide-react';
 import { useState } from 'react';
 import { useState } from 'react';
 import { toast } from 'sonner';
 import { toast } from 'sonner';
 
 
-export default defineDashboardExtension({
+defineDashboardExtension({
     actionBarItems: [
     actionBarItems: [
         {
         {
             pageId: 'product-detail',
             pageId: 'product-detail',
@@ -134,7 +162,7 @@ You can conditionally show action bar items based on the entity or user permissi
 import { Button, defineDashboardExtension, PermissionGuard } from '@vendure/dashboard';
 import { Button, defineDashboardExtension, PermissionGuard } from '@vendure/dashboard';
 import { SendIcon } from 'lucide-react';
 import { SendIcon } from 'lucide-react';
 
 
-export default defineDashboardExtension({
+defineDashboardExtension({
     actionBarItems: [
     actionBarItems: [
         {
         {
             pageId: 'customer-detail',
             pageId: 'customer-detail',
@@ -173,7 +201,7 @@ You can add multiple action bar items to the same page:
 import { Button, defineDashboardExtension } from '@vendure/dashboard';
 import { Button, defineDashboardExtension } from '@vendure/dashboard';
 import { DownloadIcon, RefreshCwIcon, SendIcon } from 'lucide-react';
 import { DownloadIcon, RefreshCwIcon, SendIcon } from 'lucide-react';
 
 
-export default defineDashboardExtension({
+defineDashboardExtension({
     actionBarItems: [
     actionBarItems: [
         {
         {
             pageId: 'product-detail',
             pageId: 'product-detail',

+ 1 - 1
docs/docs/guides/extending-the-dashboard/creating-pages/detail-pages.md

@@ -125,7 +125,7 @@ import { articleList } from './article-list';
 // highlight-next-line
 // highlight-next-line
 import { articleDetail } from './article-detail';
 import { articleDetail } from './article-detail';
 
 
-export default defineDashboardExtension({
+defineDashboardExtension({
     routes: [
     routes: [
         articleList,
         articleList,
         // highlight-next-line
         // highlight-next-line

+ 1 - 1
docs/docs/guides/extending-the-dashboard/creating-pages/list-pages.md

@@ -122,7 +122,7 @@ import { defineDashboardExtension } from '@vendure/dashboard';
 // highlight-next-line
 // highlight-next-line
 import { articleList } from './article-list';
 import { articleList } from './article-list';
 
 
-export default defineDashboardExtension({
+defineDashboardExtension({
     routes: [
     routes: [
         // highlight-next-line
         // highlight-next-line
         articleList,
         articleList,

+ 2 - 2
docs/docs/guides/extending-the-dashboard/custom-form-components/index.md

@@ -92,7 +92,7 @@ First we need to register the component with the `defineDashboardExtension` func
 import { defineDashboardExtension } from '@vendure/dashboard';
 import { defineDashboardExtension } from '@vendure/dashboard';
 import { ColorPickerComponent } from './components/color-picker';
 import { ColorPickerComponent } from './components/color-picker';
 
 
-export default defineDashboardExtension({
+defineDashboardExtension({
     customFormComponents: {
     customFormComponents: {
         // Custom field components for custom fields
         // Custom field components for custom fields
         customFields: [
         customFields: [
@@ -195,7 +195,7 @@ You can then use this component in your detail form definition:
 import { defineDashboardExtension } from '@vendure/dashboard';
 import { defineDashboardExtension } from '@vendure/dashboard';
 import { MarkdownEditorComponent } from './components/markdown-editor';
 import { MarkdownEditorComponent } from './components/markdown-editor';
 
 
-export default defineDashboardExtension({
+defineDashboardExtension({
     detailForms: [
     detailForms: [
         {
         {
             // highlight-start
             // highlight-start

+ 1 - 1
docs/docs/guides/extending-the-dashboard/custom-form-components/relation-selectors.md

@@ -451,7 +451,7 @@ import {
     ActiveCustomerSelectorComponent,
     ActiveCustomerSelectorComponent,
 } from './components';
 } from './components';
 
 
-export default defineDashboardExtension({
+defineDashboardExtension({
     detailForms: [
     detailForms: [
         {
         {
             pageId: 'product-detail',
             pageId: 'product-detail',

+ 20 - 0
docs/docs/guides/extending-the-dashboard/data-fetching/index.md

@@ -1,3 +1,7 @@
+---
+title: 'Data Fetching'
+---
+
 ## API Client
 ## API Client
 
 
 The API client is the primary way to send queries and mutations to the Vendure backend. It handles channel tokens and authentication automatically.
 The API client is the primary way to send queries and mutations to the Vendure backend. It handles channel tokens and authentication automatically.
@@ -104,3 +108,19 @@ function ProductForm({ product }) {
     );
     );
 }
 }
 ```
 ```
+
+## Type Safety
+
+The Dashboard Vite plugin incorporates [gql.tada](https://gql-tada.0no.co/), which gives you type safety _without_ any code generation step!
+
+It works by analyzing your Admin API schema (including all your custom fields and other API extensions), and outputs the results
+to a file - by default you can find it at `src/gql/graphql-env.d.ts`.
+
+When you then use the `import { graphql } from '@/gql'` function to define your queries and mutations, you get automatic
+type safety when using the results in your components!
+
+When you have the `@/gql` path mapping correctly [set up as per the getting started guide](/guides/extending-the-dashboard/getting-started/#installation--setup), you should see that
+your IDE is able to infer the TypeScript type of your queries and mutations, including the correct inputs and return
+types!
+
+![Type inference](./type-inference.webp)

BIN
docs/docs/guides/extending-the-dashboard/data-fetching/type-inference.webp


+ 4 - 4
docs/docs/guides/extending-the-dashboard/navigation/index.md

@@ -11,7 +11,7 @@ The simplest way to add navigation is to add menu items to existing sections. Th
 ```tsx title="src/plugins/my-plugin/dashboard/index.tsx"
 ```tsx title="src/plugins/my-plugin/dashboard/index.tsx"
 import { defineDashboardExtension } from '@vendure/dashboard';
 import { defineDashboardExtension } from '@vendure/dashboard';
 
 
-export default defineDashboardExtension({
+defineDashboardExtension({
     routes: [
     routes: [
         {
         {
             path: '/my-custom-page',
             path: '/my-custom-page',
@@ -55,7 +55,7 @@ You can create entirely new navigation sections with their own icons and orderin
 import { defineDashboardExtension } from '@vendure/dashboard';
 import { defineDashboardExtension } from '@vendure/dashboard';
 import { FileTextIcon, SettingsIcon } from 'lucide-react';
 import { FileTextIcon, SettingsIcon } from 'lucide-react';
 
 
-export default defineDashboardExtension({
+defineDashboardExtension({
     // Define custom navigation sections
     // Define custom navigation sections
     navSections: [
     navSections: [
         {
         {
@@ -111,7 +111,7 @@ The navigation sidebar is divided into two areas:
 ### Placement Examples
 ### Placement Examples
 
 
 ```tsx
 ```tsx
-export default defineDashboardExtension({
+defineDashboardExtension({
     navSections: [
     navSections: [
         {
         {
             id: 'reports',
             id: 'reports',
@@ -201,7 +201,7 @@ Here's a comprehensive example showing how to create a complete navigation struc
 import { defineDashboardExtension } from '@vendure/dashboard';
 import { defineDashboardExtension } from '@vendure/dashboard';
 import { FileTextIcon, ImageIcon, TagIcon, FolderIcon, SettingsIcon } from 'lucide-react';
 import { FileTextIcon, ImageIcon, TagIcon, FolderIcon, SettingsIcon } from 'lucide-react';
 
 
-export default defineDashboardExtension({
+defineDashboardExtension({
     // Create custom navigation sections
     // Create custom navigation sections
     navSections: [
     navSections: [
         {
         {

+ 52 - 7
docs/docs/guides/extending-the-dashboard/page-blocks/index.md

@@ -7,6 +7,10 @@ app (see [Dev Mode](/guides/extending-the-dashboard/extending-overview/#dev-mode
 
 
 You can also define your own blocks, which can be added to any page and can even replace the default blocks.
 You can also define your own blocks, which can be added to any page and can even replace the default blocks.
 
 
+:::info
+All available options are documented in the [DashboardPageBlockDefinition reference](/reference/dashboard/extensions-api/page-blocks#dashboardpageblockdefinition)
+:::
+
 ## Basic Page Block Example
 ## Basic Page Block Example
 
 
 Here's an example of how to define a custom page block:
 Here's an example of how to define a custom page block:
@@ -14,7 +18,7 @@ Here's an example of how to define a custom page block:
 ```tsx title="src/plugins/my-plugin/dashboard/index.tsx"
 ```tsx title="src/plugins/my-plugin/dashboard/index.tsx"
 import { defineDashboardExtension } from '@vendure/dashboard';
 import { defineDashboardExtension } from '@vendure/dashboard';
 
 
-export default defineDashboardExtension({
+defineDashboardExtension({
     pageBlocks: [
     pageBlocks: [
         {
         {
             id: 'related-articles',
             id: 'related-articles',
@@ -99,6 +103,50 @@ The `context` prop provides access to:
 - **`form`**: The React Hook Form instance for the current page (if applicable)
 - **`form`**: The React Hook Form instance for the current page (if applicable)
 - **`route`**: Route information and parameters
 - **`route`**: Route information and parameters
 
 
+## Block Visibility
+
+The visibility of a block can be dynamically controlled using the `shouldRender` function. This function receives the same
+context object as the block component, and should return a boolean to determine whether the block should be rendered.
+
+```ts
+import { defineDashboardExtension } from '@vendure/dashboard';
+
+import { AdvancedTaxInfo } from './advanced-tax-info.tsx';
+
+defineDashboardExtension({
+    pageBlocks: [
+        {
+            id: 'advanced-tax-info',
+            location: {
+                pageId: 'product-variant-detail',
+                column: 'side',
+                position: {
+                    blockId: 'facet-values',
+                    order: 'after',
+                },
+            },
+            component: AdvancedTaxInfo,
+            shouldRender: context => {
+                // You can use custom and build-in hooks
+                // in this function
+                const { activeChannel } = useChannel();
+
+                const hasTaxSettings = context.entity?.customFields?.taxSettings
+                // This block will only render if the entity has the
+                // expected custom field data, and the active channel has
+                // the given tax setting
+                return hasTaxSettings && activeChannel.pricesIncludeTax === false;
+            },
+        },
+    ],
+});
+```
+
+:::tip
+The `shouldRender` function can be used to hide built-in blocks by combining it with the "replace" position
+on an existing blockId.
+:::
+
 ## Advanced Example
 ## Advanced Example
 
 
 Here's a more complex example that shows different types of blocks:
 Here's a more complex example that shows different types of blocks:
@@ -107,7 +155,7 @@ Here's a more complex example that shows different types of blocks:
 import { defineDashboardExtension, Button } from '@vendure/dashboard';
 import { defineDashboardExtension, Button } from '@vendure/dashboard';
 import { useState } from 'react';
 import { useState } from 'react';
 
 
-export default defineDashboardExtension({
+defineDashboardExtension({
     pageBlocks: [
     pageBlocks: [
         // Analytics block for product page
         // Analytics block for product page
         {
         {
@@ -185,14 +233,11 @@ To find the `pageId` and `blockId` values for positioning your blocks:
 3. Hover over existing blocks to see their IDs
 3. Hover over existing blocks to see their IDs
 4. Use these IDs in your block positioning configuration
 4. Use these IDs in your block positioning configuration
 
 
-## TypeScript Support
-
-The dashboard provides full TypeScript support for page blocks. The `context` prop is typed based on the page you're targeting, giving you autocomplete and type safety for the entity properties.
-
-## Best Practices
+:::tip Best Practices
 
 
 1. **Use descriptive IDs**: Choose clear, unique IDs for your blocks
 1. **Use descriptive IDs**: Choose clear, unique IDs for your blocks
 2. **Position thoughtfully**: Consider the user experience when placing blocks
 2. **Position thoughtfully**: Consider the user experience when placing blocks
 3. **Handle loading states**: Show appropriate loading indicators for async operations
 3. **Handle loading states**: Show appropriate loading indicators for async operations
 4. **Follow design patterns**: Use the dashboard's existing UI components for consistency
 4. **Follow design patterns**: Use the dashboard's existing UI components for consistency
 5. **Test thoroughly**: Verify your blocks work correctly on different screen sizes
 5. **Test thoroughly**: Verify your blocks work correctly on different screen sizes
+:::

+ 1 - 0
docs/sidebars.js

@@ -154,6 +154,7 @@ const sidebars = {
                 'guides/extending-the-dashboard/navigation/index',
                 'guides/extending-the-dashboard/navigation/index',
                 'guides/extending-the-dashboard/page-blocks/index',
                 'guides/extending-the-dashboard/page-blocks/index',
                 'guides/extending-the-dashboard/action-bar-items/index',
                 'guides/extending-the-dashboard/action-bar-items/index',
+                'guides/extending-the-dashboard/data-fetching/index',
                 'guides/extending-the-dashboard/theming/index',
                 'guides/extending-the-dashboard/theming/index',
                 {
                 {
                     type: 'category',
                     type: 'category',