Parcourir la source

docs(dashboard): Update getting started and extension guide

David Höck il y a 5 mois
Parent
commit
1679113905

+ 0 - 0
docs/docs/guides/extending-the-dashboard/getting-started/dev-mode.webp → docs/docs/guides/extending-the-dashboard/extending-overview/dev-mode.webp


+ 240 - 0
docs/docs/guides/extending-the-dashboard/extending-overview/index.md

@@ -0,0 +1,240 @@
+---
+title: 'Extending the Dashboard'
+---
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
+This guide covers the core concepts and best practices for extending the Vendure Dashboard. Understanding these fundamentals will help you build robust and maintainable dashboard extensions.
+
+## Dev Mode
+
+Once you have logged in to the dashboard, you can toggle on "Dev Mode" using the user menu in the bottom left:
+
+![Dev Mode](./dev-mode.webp)
+
+In Dev Mode, hovering any block in the dashboard will allow you to find the corresponding `pageId` and `blockId` values, which you can later use when customizing the dashboard. This is essential for:
+
+- Identifying where to place custom page blocks
+- Finding action bar locations
+- Understanding the page structure
+- Debugging your extensions
+
+![Finding the location ids](./location-id.webp)
+
+## Recommended Folder Structure
+
+While you can organize your dashboard extensions however you prefer (it's a standard React application), we recommend following this convention for consistency and maintainability:
+
+```
+src/plugins/my-plugin/
+└── dashboard/
+    ├── index.tsx           # Main entrypoint linked in plugin decorator
+    ├── pages/              # Top-level page components
+    ├── routes/             # Route definitions
+    ├── form-components/    # Input, custom fields, and display components
+    ├── detail-forms/       # Detail form definitions
+    └── action-bar/         # Action bar items
+```
+
+### Entry Point (index.tsx)
+
+The main entry point that is linked in your plugin decorator:
+
+```tsx title="src/plugins/my-plugin/dashboard/index.tsx"
+import { defineDashboardExtension } from '@vendure/dashboard';
+
+export default defineDashboardExtension({
+    routes: [],
+    navSections: [],
+    pageBlocks: [],
+    actionBarItems: [],
+    alerts: [],
+    widgets: [],
+    customFormComponents: {},
+    dataTables: [],
+    detailForms: [],
+    login: {},
+});
+```
+
+:::tip
+This folder structure is particularly important when open-sourcing Vendure plugins. Following the official conventions makes it easier for other developers to understand and contribute to your plugin.
+:::
+
+## Form Handling
+
+Form handling in the dashboard is powered by [react-hook-form](https://react-hook-form.com/), which is also the foundation for Shadcn's form components. This provides:
+
+- Excellent performance with minimal re-renders
+- Built-in validation
+- TypeScript support
+- Easy integration with the dashboard's UI components
+
+### Basic Form Example
+
+```tsx
+import { useForm } from 'react-hook-form';
+import { FormFieldWrapper, Input, Button } from '@vendure/dashboard';
+
+function MyForm() {
+    const form = useForm({
+        defaultValues: {
+            name: '',
+            email: '',
+        },
+    });
+
+    const onSubmit = data => {
+        console.log(data);
+    };
+
+    return (
+        <form onSubmit={form.handleSubmit(onSubmit)}>
+            <FormFieldWrapper
+                control={form.control}
+                name="name"
+                label="Name"
+                render={({ field }) => <Input {...field} />}
+            />
+            <FormFieldWrapper
+                control={form.control}
+                name="email"
+                label="Email"
+                render={({ field }) => <Input type="email" {...field} />}
+            />
+            <Button type="submit">Submit</Button>
+        </form>
+    );
+}
+```
+
+### Advanced Example
+
+For a comprehensive example of advanced form handling, including complex validation, dynamic fields, and custom components, check out the [order detail page implementation](https://github.com/vendure-ecommerce/vendure/blob/master/packages/dashboard/src/app/routes/_authenticated/_orders/orders_.%24id.tsx) in the Vendure source code.
+
+## 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.
+
+### Importing the API Client
+
+```tsx
+import { api } from '@vendure/dashboard';
+```
+
+The API client exposes two main methods:
+
+- `query` - For GraphQL queries
+- `mutate` - For GraphQL mutations
+
+### Using with TanStack Query
+
+The API client is designed to work seamlessly with TanStack Query for optimal data fetching and caching:
+
+#### Query Example
+
+```tsx
+import { useQuery } from '@tanstack/react-query';
+import { api } from '@vendure/dashboard';
+import { graphql } from '@/gql';
+
+const getProductsQuery = graphql(`
+    query GetProducts($options: ProductListOptions) {
+        products(options: $options) {
+            items {
+                id
+                name
+                slug
+            }
+            totalItems
+        }
+    }
+`);
+
+function ProductList() {
+    const { data, isLoading, error } = useQuery({
+        queryKey: ['products'],
+        queryFn: () =>
+            api.query(getProductsQuery, {
+                options: {
+                    take: 10,
+                    skip: 0,
+                },
+            }),
+    });
+
+    if (isLoading) return <div>Loading...</div>;
+    if (error) return <div>Error: {error.message}</div>;
+
+    return <ul>{data?.products.items.map(product => <li key={product.id}>{product.name}</li>)}</ul>;
+}
+```
+
+#### Mutation Example
+
+```tsx
+import { useMutation, useQueryClient } from '@tanstack/react-query';
+import { api } from '@vendure/dashboard';
+import { graphql } from '@/gql';
+import { toast } from 'sonner';
+
+const updateProductMutation = graphql(`
+    mutation UpdateProduct($input: UpdateProductInput!) {
+        updateProduct(input: $input) {
+            id
+            name
+            slug
+        }
+    }
+`);
+
+function ProductForm({ product }) {
+    const queryClient = useQueryClient();
+
+    const mutation = useMutation({
+        mutationFn: input => api.mutate(updateProductMutation, { input }),
+        onSuccess: () => {
+            // Invalidate and refetch product queries
+            queryClient.invalidateQueries({ queryKey: ['products'] });
+            toast.success('Product updated successfully');
+        },
+        onError: error => {
+            toast.error('Failed to update product', {
+                description: error.message,
+            });
+        },
+    });
+
+    const handleSubmit = data => {
+        mutation.mutate({
+            id: product.id,
+            ...data,
+        });
+    };
+
+    return (
+        // Form implementation
+        <form onSubmit={handleSubmit}>{/* Form fields */}</form>
+    );
+}
+```
+
+## Best Practices
+
+1. **Follow the folder structure**: It helps maintain consistency, especially when sharing plugins
+2. **Use TypeScript**: Take advantage of the generated GraphQL types for type safety
+3. **Leverage TanStack Query**: Use it for all data fetching to benefit from caching and optimistic updates
+4. **Handle errors gracefully**: Always provide user feedback for both success and error states
+5. **Use the dashboard's UI components**: Maintain visual consistency with the rest of the dashboard
+6. **Test in Dev Mode**: Use Dev Mode to verify your extensions are placed correctly
+
+## What's Next?
+
+Now that you understand the fundamentals of extending the dashboard, explore these specific guides:
+
+- [Navigation](/guides/extending-the-dashboard/navigation/) - Add custom navigation sections
+- [Page Blocks](/guides/extending-the-dashboard/page-blocks/) - Enhance existing pages
+- [Action Bar Items](/guides/extending-the-dashboard/action-bar-items/) - Add custom actions
+- [Custom Form Components](/guides/extending-the-dashboard/custom-form-components/) - Build specialized inputs
+- [CMS Tutorial](/guides/extending-the-dashboard/cms-tutorial/) - Complete walkthrough example

+ 0 - 0
docs/docs/guides/extending-the-dashboard/getting-started/location-id.webp → docs/docs/guides/extending-the-dashboard/extending-overview/location-id.webp


+ 35 - 37
docs/docs/guides/extending-the-dashboard/getting-started/index.md

@@ -6,7 +6,7 @@ import Tabs from '@theme/Tabs';
 import TabItem from '@theme/TabItem';
 import TabItem from '@theme/TabItem';
 
 
 :::warning
 :::warning
-The `@vendure/dashboard` package is currently **beta** and is not yet recommended for production use. The API may change in future releases. **The first stable release is targeted for the end of July 2025.**
+The `@vendure/dashboard` package is currently **RC.1** (release candiate) and can be used in production. There won't be any _major_ breaking API changes anymore. **The official release is targeted for the end of August 2025.**
 :::
 :::
 
 
 Our new React-based dashboard is currently in beta, and you can try it out now!
 Our new React-based dashboard is currently in beta, and you can try it out now!
@@ -34,7 +34,7 @@ First install the `@vendure/dashboard` package:
 npm install @vendure/dashboard
 npm install @vendure/dashboard
 ```
 ```
 
 
-Then create a `vite.config.mts` file in the root of your project with the following content:
+Then create a `vite.config.mts` file in the root of your project (on the same level as your `package.json`) with the following content:
 
 
 ```ts title="vite.config.mts"
 ```ts title="vite.config.mts"
 import { vendureDashboardPlugin } from '@vendure/dashboard/vite';
 import { vendureDashboardPlugin } from '@vendure/dashboard/vite';
@@ -54,7 +54,7 @@ export default defineConfig({
             // and custom fields that are configured.
             // and custom fields that are configured.
             vendureConfigPath: pathToFileURL('./src/vendure-config.ts'),
             vendureConfigPath: pathToFileURL('./src/vendure-config.ts'),
             // Points to the location of your Vendure server.
             // Points to the location of your Vendure server.
-            adminUiConfig: { apiHost: 'http://localhost', apiPort: 3000 },
+            uiConfig: { host: 'http://localhost', port: 3000 },
             // When you start the Vite server, your Admin API schema will
             // When you start the Vite server, your Admin API schema will
             // be introspected and the types will be generated in this location.
             // be introspected and the types will be generated in this location.
             // These types can be used in your dashboard extensions to provide
             // These types can be used in your dashboard extensions to provide
@@ -72,44 +72,52 @@ export default defineConfig({
 });
 });
 ```
 ```
 
 
-You should also add the following to your `tsconfig.json` file to allow your IDE
-to correctly resolve imports of GraphQL types & interpret JSX in your dashboard extensions:
+You should also add the following to your existing `tsconfig.json` file to exclude the dashboard extensions and Vite config
+from your build.
 
 
 ```json title="tsconfig.json"
 ```json title="tsconfig.json"
 {
 {
-    "compilerOptions": {
+    // ... existing options
+    "exclude": [
+        "node_modules",
+        "migration.ts",
+        "src/plugins/**/ui/*",
+        "admin-ui",
         // highlight-start
         // highlight-start
+        "src/plugins/**/dashboard/*",
+        "vite.*.*ts"
+        // highlight-end
+    ],
+    "references": [
+        {
+            "path": "./tsconfig.dashboard.json"
+        }
+    ]
+}
+```
+
+Now create a new `tsconfig.dashboard.json` to allow your IDE
+to correctly resolve imports of GraphQL types & interpret JSX in your dashboard extensions:
+
+```json title="tsconfig.dashboard.json"
+{
+    "compilerOptions": {
         "module": "nodenext",
         "module": "nodenext",
         "moduleResolution": "nodenext",
         "moduleResolution": "nodenext",
-        // highlight-end
-        // ... existing options
-        // highlight-start
         "jsx": "react-jsx",
         "jsx": "react-jsx",
         "paths": {
         "paths": {
-            "@/gql": [
-                "./src/gql/graphql.ts"
-            ],
+            // Import alias for the GraphQL types
+            // Please adjust to the location that you have set in your `vite.config.mts`
+            "@/gql": ["./src/gql/graphql.ts"],
             // This line allows TypeScript to properly resolve internal
             // This line allows TypeScript to properly resolve internal
             // Vendure Dashboard imports, which is necessary for
             // Vendure Dashboard imports, which is necessary for
             // type safety in your dashboard extensions.
             // type safety in your dashboard extensions.
             // This path assumes a root-level tsconfig.json file.
             // This path assumes a root-level tsconfig.json file.
             // You may need to adjust it if your project structure is different.
             // You may need to adjust it if your project structure is different.
-            "@/vdb/*": [
-                "./node_modules/@vendure/dashboard/src/lib/*"
-            ]
+            "@/vdb/*": ["./node_modules/@vendure/dashboard/src/lib/*"]
         }
         }
-        // highlight-end
     },
     },
-    "exclude": [
-        "node_modules",
-        "migration.ts",
-        "src/plugins/**/ui/*",
-        "admin-ui",
-        // highlight-start
-        "src/plugins/**/dashboard/*",
-        "vite.*.*ts"
-        // highlight-end
-    ]
+    "include": ["src/plugins/**/dashboard/*", "src/gql/**/*.ts"]
 }
 }
 ```
 ```
 
 
@@ -123,21 +131,11 @@ npx vite
 
 
 To stop the running dashboard, type `q` and hit enter.
 To stop the running dashboard, type `q` and hit enter.
 
 
-## Dev Mode
-
-Once you have logged in to the dashboard, you can toggle on "Dev Mode" using the user menu in the bottom left:
-
-![Dev Mode](./dev-mode.webp)
-
-In Dev Mode, hovering any block in the dashboard will allow you to find the corresponding `pageId` and `blockId` values,
-which you can later use when customizing the dashboard.
-
-![Finding the location ids](./location-id.webp)
-
 ## What's Next?
 ## What's Next?
 
 
 Now that you have the dashboard up and running, you can start extending it:
 Now that you have the dashboard up and running, you can start extending it:
 
 
+- [Extending the Dashboard](/guides/extending-the-dashboard/extending-overview/) - Core concepts and best practices
 - [Navigation](/guides/extending-the-dashboard/navigation/) - Add custom navigation sections and menu items
 - [Navigation](/guides/extending-the-dashboard/navigation/) - Add custom navigation sections and menu items
 - [Page Blocks](/guides/extending-the-dashboard/page-blocks/) - Add custom blocks to existing pages
 - [Page Blocks](/guides/extending-the-dashboard/page-blocks/) - Add custom blocks to existing pages
 - [Action Bar Items](/guides/extending-the-dashboard/action-bar-items/) - Add custom buttons to page action bars
 - [Action Bar Items](/guides/extending-the-dashboard/action-bar-items/) - Add custom buttons to page action bars

+ 1 - 0
docs/sidebars.js

@@ -140,6 +140,7 @@ const sidebars = {
             },
             },
             items: [
             items: [
                 'guides/extending-the-dashboard/getting-started/index',
                 'guides/extending-the-dashboard/getting-started/index',
+                'guides/extending-the-dashboard/extending-overview/index',
                 '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',