From 0b8ce83fb45e8dd4e88664ce6f82ba747e7fbaa1 Mon Sep 17 00:00:00 2001 From: David Matejka Date: Fri, 21 Jul 2023 14:14:18 +0200 Subject: [PATCH] add scopes, split routing pages --- docs/intro/interface.mdx | 6 +- docs/reference/admin/pages/links.md | 3 + docs/reference/admin/pages/overview.md | 34 +++ ...{defining-pages.md => pages-components.md} | 37 +-- docs/reference/admin/pages/routing.md | 89 ++++++ docs/reference/admin/pages/scopes.md | 257 ++++++++++++++++++ sidebars.js | 18 +- 7 files changed, 412 insertions(+), 32 deletions(-) create mode 100644 docs/reference/admin/pages/overview.md rename docs/reference/admin/pages/{defining-pages.md => pages-components.md} (87%) create mode 100644 docs/reference/admin/pages/routing.md create mode 100644 docs/reference/admin/pages/scopes.md diff --git a/docs/intro/interface.mdx b/docs/intro/interface.mdx index efcdbf33..bfeeb0e7 100644 --- a/docs/intro/interface.mdx +++ b/docs/intro/interface.mdx @@ -59,7 +59,7 @@ The naming of pages (and by extension, URL paths) is automated. The name given t For example, if you have a default export from a file named `post.tsx`, the resulting page name would be `post`. If there's a function within the same file that's exported as edit, the page name would be `post/edit`. - +

Understand how pages and routing works.

@@ -135,7 +135,7 @@ export default () => ( This is done with `redirectOnSuccess` prop where we specify link to page where user should be redirected. This is our first encounter with Contember Interface query language. Now if you create a new article you're automatically redirected to the edit page. - +

Explanation of all pages components.

@@ -204,4 +204,4 @@ And that's it! You have just created a simple data model and created custom inte

How to deploy Contember project.

-
\ No newline at end of file + diff --git a/docs/reference/admin/pages/links.md b/docs/reference/admin/pages/links.md index 45c83213..d38d7ca7 100644 --- a/docs/reference/admin/pages/links.md +++ b/docs/reference/admin/pages/links.md @@ -2,6 +2,9 @@ title: Links and redirects --- +Contember's `Link` component and `useRedirect` hook offer powerful navigation capabilities within your application. The `Link` component creates hyperlinks to various routes, with support for both static and dynamic route parameters. The `useRedirect` hook, on the other hand, provides programmable navigation, letting you change routes based on application logic. These tools facilitate a highly navigable and interactive user interface. Further details can be found in the main documentation +section. + ## Links The `Link` component allows you to create a link to a specific route in your application. The `to` prop specifies the destination page: diff --git a/docs/reference/admin/pages/overview.md b/docs/reference/admin/pages/overview.md new file mode 100644 index 00000000..2b4a34b0 --- /dev/null +++ b/docs/reference/admin/pages/overview.md @@ -0,0 +1,34 @@ +--- +title: Routing and pages overview +--- + + +In order to define pages in Contember Interface, you need to export function components from files in the `admin/pages` directory (or its subdirectory). + +In the functions exported from page components, you will usually use one of the prepared [scope](./scopes.md) or [page](./pages-components) components provided by Contember. + +```typescript jsx +export default () => { + return ( + <> +

Page content here

+ + ) +} +``` + +## [Routing](./routing) + +Contember's routing system allows flexible structuring of your interface based on exported components from your files. You can create pages, subpages or nested pages based on your project's needs. This approach offers an intuitive way to design the navigation flow in your application. For more details, refer to the [routing section](./routing) in our documentation. + +## [Links and redirects](./links.md) + +In Contember, navigating through your application is made easy and intuitive through a range of dedicated components and hooks. These tools simplify the creation of hyperlinks, support static and dynamic parameters, and allow for programmable route changes based on your application's logic. This enables you to build a highly interactive and user-friendly interface, enhancing the overall user experience. For more specific information, please refer to the [links chapter](./links.md). + +## Interface 1.2+ [Scopes](./scopes) + +Contember provides several prepared scope components to help you quickly set up common pages in your admin panel. These scope components handle common tasks like loading and saving data, rendering form fields and displaying entity lists. + +## [Pages](./pages-components) + +While page components were once the standard for defining individual pages in Contember, they now represent a legacy approach. In new applications, we highly recommend utilizing [scopes](./scopes) for enhanced flexibility and efficiency. diff --git a/docs/reference/admin/pages/defining-pages.md b/docs/reference/admin/pages/pages-components.md similarity index 87% rename from docs/reference/admin/pages/defining-pages.md rename to docs/reference/admin/pages/pages-components.md index 43179809..e598a67a 100644 --- a/docs/reference/admin/pages/defining-pages.md +++ b/docs/reference/admin/pages/pages-components.md @@ -1,32 +1,14 @@ --- -title: Pages +title: Legacy pages --- -In order to define pages in Contember Interface, you need to export function components from files in the `admin/pages` directory (or its subdirectory). +Contember provides several prepared page components to help you quickly set up common page types in your interface. These page components handle common tasks like loading and saving data, rendering form fields, and displaying entity lists. -In the functions exported from page components, you will usually use one of the prepared page components provided by Contember. The most simple is the `GenericPage`: +:::caution Page components are deprecated -```typescript jsx -export default () => { - return ( - - Content goes here - - ) -} -``` - -## Routing - -Page names (and basically URL path) are constructed automatically. The resulting page name for the page will be determined by the file and function name, with slashes separating them. For example, the `default` export from a file named `post.tsx` will have the page name `post`, while a function exported as `edit` from a same file will be named `post/edit`. If a function is in a subdirectory, its path will also include the subdirectory name. For instance, a function named `edit` exported from -`post/category.tsx` will have the name `post/category/edit`. +The use of page components in Contember to define individual pages is now deemed a legacy approach. Although it served its purpose in earlier applications, it lacks the flexibility and efficiency that modern applications require. For any new developments, we strongly recommend transitioning towards using [scope components](./scopes). -See how to [create links](./links.md). - - -## Pages - -Contember provides several prepared page components to help you quickly set up common page types in your admin panel. These page components handle common tasks like loading and saving data, rendering form fields, and displaying entity lists. +::: ### GenericPage @@ -35,6 +17,7 @@ The most basic page component in Contember. It simply renders its children insid For more details on these props and their usage, see the [API reference](../api/v1.2/Pages/GenericPage.mdx). #### Example how to use GenericPage + ```typescript jsx import { GenericPage } from '@contember/admin' @@ -90,6 +73,7 @@ The `redirectOnSuccess` prop allows you to specify a target page to navigate to For more details on EditPage props and their usage, see the [API reference](../api/v1.2/Pages/EditPage.mdx). #### Example how to use EditPage + ```typescript jsx import { EditPage } from '@contember/admin' @@ -120,6 +104,7 @@ A `rendererProps` prop can be used to modify the layout of the page, such as add For more details on DetailPage props and their usage, see the [API reference](../api/v1.2/Pages/DetailPage.mdx). #### Example how to use DetailPage + ```typescript jsx import { DetailPage, Field } from '@contember/admin' @@ -158,7 +143,6 @@ export default () => { } ``` - ### DataGridPage `DataGridPage` is a page component that wraps a `DataGrid` component. It allows you to display a list of specified entities in a more advanced way, with features such as pagination and filtering. @@ -194,18 +178,17 @@ export default () => { } ``` - ### MultiEditPage `MultiEditPage` is a page component in Contember that allows you to edit multiple entities on a single page. It is essentially a wrapper around the `Repeater` component, which means that you can use it to add, remove, and sort items within the page. -To use` MultiEditPage`, you must specify the entities you want to edit using the `entities` prop (of type [qualified entity list](../data-binding/query-language#qualified-entity-list)). To control the behavior of the `Repeater`, you can pass props such as `sortableBy` through the `rendererProps` prop of `MultiEditPage`. This will allow you to specify which fields should be used to sort the items in the `Repeater`. You can also pass custom props to modify the layout of the page using the `rendererProps` prop. +To use` MultiEditPage`, you must specify the entities you want to edit using the `entities` prop (of type [qualified entity list](../data-binding/query-language#qualified-entity-list)). To control the behavior of the `Repeater`, you can pass props such as `sortableBy` through the `rendererProps` prop of `MultiEditPage`. This will allow you to specify which fields should be used to sort the items in the `Repeater`. You can also pass custom props to modify the layout of the page using +the `rendererProps` prop. `MultiEditPage` should only be used for editing a small number of entities, as it does not support advanced features such as pagination or filtering. For more details on MultiEditPage props and their usage, see the [API reference](../api/v1.2/Pages/EditPage.mdx). - #### Example how to use MultiEditPage ```typescript jsx diff --git a/docs/reference/admin/pages/routing.md b/docs/reference/admin/pages/routing.md new file mode 100644 index 00000000..0bf21105 --- /dev/null +++ b/docs/reference/admin/pages/routing.md @@ -0,0 +1,89 @@ +--- +title: Routing +--- + +Page names (and basically URL path) are constructed automatically. The resulting page name for the page will be determined by the file and function name, with slashes separating them. For example, the `default` export from a file named `post.tsx` will have the page name `post`, while a function exported as `edit` from a same file will be named `post/edit`. If a function is in a subdirectory, its path will also include the subdirectory name. For instance, a function named `edit` exported from +`post/category.tsx` will have the name `post/category/edit`. + +## Routing options + +To define pages in Contember, you can use different exports. Each function exported from a page component defines a separate page. If you're looking for more advanced routing setups, understanding how to leverage different exports will be beneficial. + +### Default Export + +The `default` export is used to create the base page. It is given the name of the file. + +```typescript jsx +export default () => { + return ( + <> +

Post overview here

+ + ) +} +``` + +In the above example, if this was the `default` export from a file named `post.tsx`, the page name would be `post`. + +### Named Exports + +Named exports allow you to define subpages. The name of the function you export will be added to the URL path after a slash. For example: + +```typescript jsx +export const Edit = () => { + return ( + <> +

Edit post here

+ + ) +} +``` + +In this case, if the `Edit` function was exported from a file named `post.tsx`, the page name would be `post/edit`. + +### Exports from Subdirectories + +If your function is within a subdirectory, its path will also include the subdirectory name. This allows you to further nest your pages and organize your interface. For example, if you have a function named `Edit` exported from `post/category.tsx`, the page name would be `post/category/edit`. + +```typescript jsx +export const Edit = () => { + return ( + <> +

Edit post category here

+ + ) +} +``` + +### Multiple Named Exports from a Single File + +Building upon the routing options provided by Contember, you can define multiple pages from a single file using multiple named exports. + +Consider the following example from a file named `post.tsx`, where we're exporting two different components: `Create` and `Edit`. + +```typescript jsx +// This is the Create Post page +export const Create = () => { + return ( + <> +

Here is where you can create a new post.

+ + ) +} + +// This is the Edit Post page +export const Edit = () => { + return ( + <> +

Here is where you can edit an existing post.

+ + ) +} +``` + +With this setup, you're defining two new pages within your Contember interface: + +1. `post/create` - This page is rendered when the `Create` component is called. +2. `post/edit` - This page is rendered when the `Edit` component is called. + +The names used for the exports, in this case, `Create` and `Edit`, will be reflected in the URL path for their respective pages. It's beneficial to use descriptive names as they give the user an understanding of the page's content or function. diff --git a/docs/reference/admin/pages/scopes.md b/docs/reference/admin/pages/scopes.md new file mode 100644 index 00000000..0ea5a56b --- /dev/null +++ b/docs/reference/admin/pages/scopes.md @@ -0,0 +1,257 @@ +--- +title: Scopes +--- + +# Interface 1.2+ Scopes + +Contember provides several prepared scope components to help you quickly set up common pages in your interface. These scope components handle common tasks like loading and saving data, rendering form fields and displaying entity lists. + +:::note Pages vs Scopes +Before introduction of Scopes, Contember used to have a different approach that was tied to `LayoutPage` component which caused troubles with reusability and flexibility. + +Scopes are now separated from layout, which means more declarative approach to writing pages and more flexibility for your layouts. + +**This also means that the persist button or title components are not automatically rendered anymore.** When re-writing pages to support Scopes, e.g. you must add the `PersistButton` component to render it manually and it must be placed within the Scope component. + +The [old approach](./pages-components) is still supported, but it is not recommended to use it for new pages. +::: + +### Page content + +The most basic page content is rendered as children inside a layout content area. With help of [Slots](/reference/admin/layouts/slots) you can render content into layout pre-defined areas such as `Title`, `Sidebar`, `Navigation`, or `Actions` even though they are defined outside of the content area. customize the page's title, add content to the sidebar, add navigation elements or actions to the page for the current route. + +#### Example how to use Slots with page content + +```tsx +import { GenericPage } from '@contember/admin' +import { SlotSources } from '../components/Slots' + +const { Title } = SlotSources + +export default () => { + return ( + <> + Page title +

Content here

+ + ) +} +``` + +### CreateScope + +CreateScope is a component used for creating a new entity. It requires an `entity` prop (of type [unconstrained qualified single entity](../data-binding/query-language#unconstrained0qualified-single-entity)) which specifies the entity type being created. The form fields are defined using its children. + +The `redirectOnSuccess` prop allows you to specify the target page after the entity has been successfully created. If no redirect target is defined, you will be able to create another entity. + +Additionally, you can use [Slots](/reference/admin/layouts/slots) to render title, actions or sidebar content of the current route to the other areas of the layout. + +If you set the `orderField` prop, the specified field will be automatically filled with the next available value. This is useful for entities that have an order field, as it allows you to easily specify the order in which the entities should be displayed. + +For more details on CreateScope props and their usage, see the [API reference](../api/v1.2/Scopes/CreateScope.mdx). + +#### Example how to use CreateScope + +```tsx +import { CreatePage, PersistButton, TextField } from '@contember/admin' +import { SlotSources } from '../components/Slots' + +const { Actions, Title } = SlotSources + +export default () => { + return ( + <> + Create new article + + + {/* .... */} + + + + + + ) +} +``` + +This page will allow you to create a new article and will redirect to the list of articles after the entity has been successfully created. The `Title` slot is being used to set the title of the document to "Create new article", `Actions` slot to add `PersistButton` to the dedicated layout area and it will automatically fill the order field with the next available value. + +### EditScope + +EditScope is a component used for editing a specific entity. It requires an `entity` prop (of type [qualified single entity](../data-binding/query-language#qualified-single-entity)) which specifies the entity type and its id (or other unique identifier) being edited. The form fields are defined using its children. + +The `redirectOnSuccess` prop allows you to specify a target page to navigate to after the entity has been successfully edited. Additionally, you can use [Slots](/reference/admin/layouts/slots) to render title, actions or sidebar content of the current route to the other areas of the layout. + +For more details on `EditScope` props and their usage, see the [API reference](../api/v1.2/Scopes/EditScope.mdx). + +#### Example how to use EditScope + +```tsx +import { EditScope } from '@contember/admin' +import { SlotSources } from '../components/Slots' + +const { Actions, Title } = SlotSources + +export default () => { + return ( + <> + Edit article + + + {/* .... */} + + + + + + ) +} +``` + +In this example, the `EditScope` component is being used to edit an `Article` entity with an ID that matches the `id` parameter from the URL. When the form is successfully submitted, the user will be redirected to the `articles/list` page. The `Title` slot is being used to set the title of the document to "Edit article", `Actions` slot to add `PersistButton` to the dedicated layout area. + +### DetailScope + +The `DetailScope` displays the details of a single entity. It takes an `entity` prop (of type [qualified single entity](../data-binding/query-language#qualified-single-entity)) which specifies the entity to display. The displayed fields are defined using its children. + +Additionally, you can use [Slots](/reference/admin/layouts/slots) to render title, actions or sidebar content of the current route to the other areas of the layout. + +For more details on DetailScope props and their usage, see the [API reference](../api/v1.2/Scopes/DetailScope.mdx). + +#### Example how to use DetailScope + +```tsx +import { DetailScope, Field } from '@contember/admin' +import { SlotSources } from '../components/Slots' + +const { Title } = SlotSources + +export default () => { + return ( + <> + Article details + + + {/* .... */} + + + ) +} +``` + +In this example, the `DetailScope` component will display the details of the Article entity with an id that matches the `id` parameter from the URL. The `Title` slot is being used to set the title of the document to "Article details". + +Note that the `DetailScope` component should not include a persist button by default, as it is primarily used for displaying data rather than editing it. If you need to edit the entity, you should use the `EditScope` component instead. + +### ListScope + +The `ListScope` displays a simple list of specified entities. It requires an `entities` prop (of type [qualified entity list](../data-binding/query-language#qualified-entity-list)) which specifies the entity type being listed. It also allows defining fields using its children. The `ListScope` does not provide advanced features such as pagination or filtering. If you need this functionality, you can use the `DataGridScope` component instead. + +Additionally, you can use [Slots](/reference/admin/layouts/slots) to render title, actions or sidebar content of the current route to the other areas of the layout. + +For more details on ListScope props and their usage, see the [API reference](../api/v1.2/Scopes/ListScope.mdx). + +```tsx +import { ListScope, Field } from '@contember/admin' +import { SlotSources } from '../components/Slots' + +const { Actions, Title } = SlotSources + +export default () => { + return ( + <> + Articles + + + {/* ... */} + + + ) +} +``` + +### DataGridScope + +`DataGridScope` wraps a `DataGrid` component. It allows you to display a list of specified entities in a more advanced way, with features such as pagination and filtering. + +To use `DataGridScope`, you need to pass the `entities` prop (of type [qualified entity list](../data-binding/query-language#qualified-entity-list)) with the name of the entity you want to display in the grid. You can also pass any props that the `DataGrid` component accepts, such as `itemsPerPage` to customize the behavior of the grid. + +To define the cells of the grid, you pass them as children to the `DataGridScope` component. These will be rendered as columns in the grid. Additionally, you can use [Slots](/reference/admin/layouts/slots) to render title, actions or sidebar content of the current route to the other areas of the layout. + +For more details on DataGridScope props and their usage, see the [API reference](../api/v1.2/Scopes/DataGridScope.mdx). + +#### Example how to use DataGridScope + +```tsx +import { DataGridScope, HasOneSelectCell, LinkButton, TextCell, GenericCell } from '@contember/admin' +import { SlotSources } from '../components/Slots' + +const { Actions, Title } = SlotSources + +export default () => { + return ( + <> + Articles + + + Create + + + + + + + Edit + + + + ) +} +``` + +### MultiEditScope + +`MultiEditScope` is a component in Contember that allows you to edit multiple entities on a single page. It is essentially a wrapper around the `Repeater` component, which means that you can use it to add, remove, and sort items within the page. + +To use` MultiEditScope`, you must specify the entities you want to edit using the `entities` prop (of type [qualified entity list](../data-binding/query-language#qualified-entity-list)). To control the behavior of the `Repeater`, you can pass props such as `sortableBy` through the `listProps` prop of `MultiEditScope`. This will allow you to specify which fields should be used to sort the items in the `Repeater`. Additionally, you can use [Slots](/reference/admin/layouts/slots) to render title, +actions or sidebar content of the current route to the other areas of the layout. + +`MultiEditScope` should only be used for editing a small number of entities, as it does not support advanced features such as pagination or filtering. + +For more details on MultiEditScope props and their usage, see the [API reference](../api/v1.2/Scopes/EditScope.mdx). + +#### Example how to use MultiEditScope + +```typescript jsx +import { MultiEditScope, TextField } from '@contember/admin' +import { SlotSources } from '../components/Slots' + +const { Actions, Title } = SlotSources + +export default () => ( + <> + Categories + , + sortableBy: 'order' + }}> + + {/*...*/} + + +) +``` + +:::tip Placing the Persist button +The `PersistButton` component is used to persist the changes made to the entities and it must be placed within a component that provides Contember data binding context. The Scope components provide this context so the `PersistButton` component must be placed within the Scope component. Slots can help you place the `PersistButton` component in the specific area of your layout. +::: diff --git a/sidebars.js b/sidebars.js index 02fa1b3a..92a923b6 100644 --- a/sidebars.js +++ b/sidebars.js @@ -50,8 +50,22 @@ module.exports = { collapsed: true, items: [ 'reference/admin/introduction', - 'reference/admin/pages/defining-pages', - 'reference/admin/pages/links', + { + type: "category", + label: "Pages, routing and scopes", + collapsed: true, + items: [ + { + type: "doc", + id: "reference/admin/pages/overview", + label: "Overview", + }, + 'reference/admin/pages/routing', + 'reference/admin/pages/links', + 'reference/admin/pages/scopes', + 'reference/admin/pages/pages-components', + ], + }, 'reference/admin/data-binding/overview', 'reference/admin/data-binding/query-language', {