Skip to content

Commit

Permalink
feat(v4): new router bindings (#3591)
Browse files Browse the repository at this point in the history
* feat(router-picker): add a context value for legacy and new router switch

* feat(routing): rename router to `legacy-router`

* feat(router): add new router context

* feat(router): update router bindings types

* feat(resource): update resource types in bindings

* refactor(resource): memoize values inside context

* feat(core): update refine wrapper with new router

* chore(querykeys): nullable id in detail

* chore(exports): update router exports as legacy

* chore(exports): export resource context

* test(mocks): update to legacy router

* feat(helpers): add legacy transform for resources

* chore(helpers): add resource sanitize helpers

* chore(pick-resource): add pick resource helper

* chore(redirect): handle undefined cases

* chore(route-generator): update legacy helper

* chore(router): add route matching and generation helpers

* feat(router): add new way of route matching helpers

* feat(react-router-v6): update bundle config for `/legacy` exports

* chore(react-router-v6): export legacy router from `/legacy` subpath

* feat(react-router-v6): add `<RefineRoutes />` component

* feat(react-router-v6): add and export bindings

* chore(use-navigation): update hook for backward compability and internal use

* feat(router): add new router hooks and deprecate legacy

* feat(router): update redirection logic in form

* feat(router): update use-resource with new bindings

* feat(router): update use breadcrumb for new bindings

* feat(use-table): update sync with location with new bindings

* chore(router): update hooks for undefined resources

* test(examples): add test setup for new router bindings

* chore(codemod): add router to legacy router codemod

* chore(router): add missing exports

* feat(codemod): add legacy router option

* test(examples): transform all to legacy router

* feat(ui-types): add `meta` to buttons

* chore(ui-types): remove deprecated access control prop

* feat(remix): add new bindings and move to legacy

* feat(react-router-v6): update bindings with components

* feat(nextjs): move existing routers to legacy

* feat(nextjs): add new router bindings for app and pages

* feat(core): add `link` to router bindings

* feat(core): add new useResource overload

* feat(core): update hooks with new bindings

* feat(core): add `useToPath` and `useLink` hooks

* feat(antd): update components with new router bindings

* feat(codemod): update legacy router transformation for all

* feat(codemod): add move-deprecated-access-control transformation

* feat(codemod): rename to legacy router provider prop

* test(inferred-params): add inferred params test

* test(core-router): add router helper unit tests

* refactor(core): update use-resource usage

* chore(core): remove deprecated props

* feat(antd): update with new routing

* feat(chakra): update with new routing

* feat(mantine): update with new routing

* feat(mui): update with new routing

* feat(hook-form): update with new routing

* feat(kbar): update with new routing

* chore(inferencer): update with deprecated values

* chore(core): remove warnings

* test(core): update test wrapper for routers

* feat(react-router-v6): add show segment

* feat(core): add show segment to default paths

* test(core): update hook tests for routers

* feat(core): update `useMenu`

* chore(core): update type export

* chore(core): update route composer

* feat(core): update auth hooks for new routing

* feat(core): add redirect with new router in authenticated component

* chore(core): fix backward compatibly

* test(core): fix auth hook tests

* chore(core): remove unused mocks

* chore(core): remove `react-router-dom` from devDeps

* fix(remix): move `qs` to deps

* feat(router): add unsaved-changes-notifier comps

* feat(core): deprecate layout props

* chore(core): replace params to meta

* feat(ui): add `meta` to breadcrumbs

* fix(core): update router bindings

* feat(core): create route on legacy even if not exists

* chore(core): replace type export

* test(core): transform resources at tests

* test(ui-tests): update router

* test(core): remove `fit`

* test(ui-tests): update button tests

* chore(core): allow deprecated options in meta

* fix(core): check for route in legacy

* fix(antd): update selected key in antd sider

* test(antd): update test setup

* fix(mui): selectedKey in sider

* fix(mui): fix broken show title

* fix(core): legacy resource can be undefined

* test(mui): update test setup

* fix(chakra-ui): variable name

* test(chakra-ui): update test setup

* fix(mantine): update sider key

* test(mantine): update test setup

* chore(core): fix lint error

* fix(core): update conflicting types

* fix(live-previews): rename to legacy

* chore(examples): remove obsolete props

* test(inferencer): update test setup

* test(inferencer): update snapshots

* test(ui-tests): fix clone button tests

* test(kbar): fix test setup

* chore(react-router-dom): upgrade version

* fix(react-router-v6): remove unused argument

* fix(react-router-v6): fix legacy looping

* chore(examples): remove unused import

* chore(examples): rename `routerProvider` prop

* chore(react-location): mark as private

* build: ignore refine-react-location at bootstrapping

* build(codemod): fix versions

* fix(codemod): update to matching versions

* build: remove codemod case

* chore(examples): fix undefined error

* chore(examples): fix import path

* chore(examples): update react-router imports

* chore(examples): update `Link`

* fix(codemod): add export rename for routers

* build(codemod): add `start` script

* chore(examples): fix export paths

* chore(examples): add fallback

* fix(core): use menu return type

* chore: exclude react-location

* chore(react-location): fix type error

* chore: update bootstrap script

* chore(examples): fix unknown prop name

* chore(examples): fix unexported import

* fix(core): useIsAuthenticated hook

* fix(core): `Authenticated` component

* test(core): update tests

* test(react-table): add resource

* test(antd): add route inference

* test(auth): fix test setups

* fix(core): handle undefined return in query function

* fix(react-router-v6): skip authentication if not provided

* refactor(core): move `patname` in bindings to response

* fix(core): authenticated component calls

* fix(core): do not include parent prefix in new routing system

* fix(core): use table link creation with new routing

* fix(core): always pick parent in breadcrumb

* fix(antd): use link by router type

* feat(sider): add `meta` to sider for menu creation

* chore(examples): add new routing example

* fix(core): allow additional nested params in parse

* feat(core): add form sync with location param type

* fix(core): remove console

* feat(antd): add `syncWithLocation` to `useDrawerForm`

* feat(antd): add `syncWithLocation` to `useModalForm`

* feat(mantine): add `syncWithLocation` to `useModalForm`

* feat(hook-form): add `syncWithLocation` to `useModalForm`

* chore(examples): note `routerBindings` as optional

* feat(remix): add `navigate-to-resource` component

* fix(nextjs): fix multiple calls in NavigateToResource

* refactor(syncWithLocation): use `identifier` when possible

* chore(examples): fix lint issue

* test(core): parent prefix on legacy and new

* chore(examples): remove commented authProvider

* chore(examples): fix wrong name

* chore(core): remove deprecation mark

* fix(react-router-v6): better workaround for usePrompt

* fix(core): remove repeated params

* fix(nextjs-router): type issue (vercel/next.js#46360)

* fix(nextjs): pathname issue

* fix(nextjs): wait for router to settle

* chore(live-previews): move demo components to legacy router

* chore(core): warn users for unknown properties in router provider

* chore: add changesets

* chore(core): add `identifier`

* chore(kbar): add changeset

* chore(examples): upgrade `with-nextjs-auth`

* chore(changeset): update changesets

* chore(examples): fix legacy type import

* chore(examples): fix build changes

* feat(live-previews): add react-router-dom

* chore(live-previews): add memory router replacement
  • Loading branch information
aliemir authored Feb 28, 2023
1 parent 2b4002d commit 3f10c6e
Show file tree
Hide file tree
Showing 587 changed files with 10,644 additions and 17,007 deletions.
28 changes: 28 additions & 0 deletions .changeset/chilly-bobcats-rhyme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
"@pankod/refine-remix-router": major
---


We're releasing a new way to connect your router to **refine**.

The legacy `routerProvider` and its exports are now deprecated but accessible at `@pankod/refine-remix-router/legacy` path.

The new `routerBindings` are smaller and more flexible than the previos one.

## New `routerBindings` export

New `routerBindings` contains following properties;

- `go`: Which returns a function to handle the navigation in `@remix-run/react`. It accepts a config object and navigates to the given path. Uses `useNavigate` hook under the hood.
- `back`: Which returns a function to handle the navigation in `@remix-run/react`. It navigates back to the previous page. Uses `useNavigate` hook under the hood.
- `parse`: Which returns a function to parse the given path and returns the `resource`, `id`, `action` and additional `params`. Uses `useParams` and `useLocation` hooks under the hood.
- `Link`: A component that accepts `to` prop and renders a link to the given path. Uses `Link` component from `@remix-run/react` under the hood.

## Complemetary Components

- `RefineRoutes` - A component that renders the routes for the resources when the actions are defined as components. This can be used to achieve the legacy behavior of `routerProvider` prop. `RefineRoutes` component accepts a render function as a child and passes `JSX.Element` if there's a match for the given path, `undefined` is passed otherwise. You can use this in `$` splat route to render the matching action component for a resource. We're encouraging our users to use file based routing instead of `$` splat route which provides more flexibility and a better development experience with its performance benefits.

- `NavigateToResource` - A component that navigates to the first `list` action of the `resources` array of `<Refine>`. Optionally, you can pass a `resource` prop to navigate to `list` action of the resource. This can be placed at the `index` route of your app to redirect to the first resource.

- `UnsavedChangesNotifier` - This component handles the prompt when the user tries to leave the page with unsaved changes. It can be placed under the `Refine` component.

185 changes: 185 additions & 0 deletions .changeset/clever-beans-pretend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
---
"@pankod/refine-core": major
---

We're releasing a new way to connect routers to **refine**. Now the `routerProvider` prop is marked as optional in `<Refine>` component.

New `routerProvider` property is smaller and more flexible than the previous one which is now can be used with `legacyRouterProvider` property.

We've redesigned our bindings to the router libraries. Instead of handling the route creation process, now **refine** leaves this to the user and only uses a way to communicate with the router and the routes through the bindings provided to `routerProvider` property.

The changes in routing system comes with a new way to define resource actions as well. Actions now can be defined as paths, components or both. We're encouraging our users to use paths, which enables our users to use all the optimizations that the router libraries provide without giving up any features of **refine**.

Router libraries are also comes with components like `RefineRoutes` which can be used to define routes for resources when you pass components to the actions of the resources. Please refer to the documentation for more information.

## Changes in `resources`

Now you can define actions in multiple ways;

1. As a path

```tsx
<Refine
resources={[
{
name: "posts",
list: "/posts",
},
]}
>
...
</Refine>
```

2. As a component

```tsx
import { PostList } from "src/posts";

<Refine
resources={[
{
name: "posts",
list: PostList,
},
]}
>
...
</Refine>
```

3. As both

```tsx
import { PostList } from "src/posts";

<Refine
resources={[
{
name: "posts",
list: {
path: "/posts",
component: PostList,
},
},
]}
>
...
</Refine>
```

This also comes with some additional changes;

- `options` property is renamed to `meta` for consistency.
- `parentName` is now defined with `parent` property in `meta` object.
- `auditLog` is renamed to `audit`.
- `route` in `options` is now deprecated for the new routing system. If you want to define a custom route for a resource, you can define such routes in action definitions.
- Parents are not included in the routes by default. If you want to inclue parents in the routes, you need to define action paths explicitly.
- `identifier` can be passed to the resource definition to distinguish between resources with the same name. This is useful when you have multiple resources with the same name.

### Nested routes

Now, **refine** supports nested routes with parameters. You can define the action paths for a resource with parameters. Parameters will be filled with the current ones in the URL and additional ones can be provided via `meta` properties in hooks and components.

```tsx
<Refine
resources={[
{
name: "posts",
list: "users/:authorId/posts",
show: "users/:authorId/posts/:id",
},
]}
>
```

When you're in the `list` page of the `posts` resource, assuming you already have the `authorId` parameter present in the URL, the `show` action will be rendered with the `authorId` parameter filled with the current one in the URL. If you want to use a different `authorId`, you can pass `meta` properties to the components or hooks, such as `useGetToPath` hook to get the navigation path.

```tsx
const { go } = useGo();
const getToPath = useGetToPath();

const to = getToPath({
resource: "posts",
action: "show",
meta: {
id: 1,
authorId: 2,
},
});
// "to" will be "/users/2/posts/1"

go({ to, type: "push" });
```

## Changes in `routerProvider`

`routerProvider` is now smaller and more flexible. It only contains the following properties;

- `Link`: A component that accepts `to` prop and renders a link to the given path.
- `go`: A function that returns a function that accepts a config object and navigates to the given path.
- `back`: A function that returns a function that navigates back to the previous page.
- `parse`: A function that returns a function that returns the `resource`, `id`, `action` and additional `params` from the given path. This is the **refine**'s way to communicate with the router library.

None of the properties are required. Missing properties may result in some features not working but it won't break **refine**.

Our users are able to provide different implementations for the router bindings, such as handling the search params in the path with a different way or customizing the navigation process.

**Note**: Existing `routerProvider` implementation is preserved as `legacyRouterProvider` and will continue working as before. We're planning to remove it in the next major version.

**Note**: New routing system do not handle the authentication process. You can now wrap your components with `Authenticated` component or handle the authentication check inside your components through `useIsAuthenticated` hook to provide more flexible auth concepts in your app.

## Changes in hooks

We're now providing new hooks for the new routing system. You're free to use them or use the ones provided by your router library.

- `useGo`
- `useBack`
- `useParsed`
- `useLink`
- `useGetToPath`

are provided by **refine** to use the properties of `routerProvider` in a more convenient way.

- `useResourceWithRoute` is now deprecated and only works with the legacy routing system.
- `useResource` has changed its definition and now accepts a single argument which is the `resource` name. It returns the `resource` object depending on the current route or the given `resource` name. If `resource` is provided but not found, it will create a temporary one to use with the given `resource` name.
- `useNavigation`'s functions in its return value are now accepting `meta` object as an argument. This can be used to provide parameters to the target routes. For example, if your path for the `edit` action of a resource is `/:userId/posts/:id/edit`, you can provide `userId` parameter in `meta` object and it will be used in the path.
- Hooks using routes, redirection etc. are now accepts `meta` property in their arguments. This can be used to provide parameters to the target routes. This change includes `useMenu` and `useBreadcrumb` which are creating paths to the resources for their purposes.
- `selectedKey` in `useMenu` hook's return type now can be `undefined` if the current route is not found in the menu items.

## `warnWhenUnsavedChanges` prop

In earlier versions, **refine** was handling this feature in `beforeunload` event. This was causing unintended dependencies to the `window` and was not customizable. Now, **refine** is leaving this to the router libraries. Router packages `@pankod/refine-react-router-v6`, `@pankod/refine-nextjs-router` and `@pankod/refine-remix-router` are now exporting a component `UnsavedChangesNotifier` which can be placed under the `<Refine>` component and registers a listener to the necessary events to handle the `warnWhenUnsavedChanges` feature.

## Changes in `Authenticated` component.

`<Authenticated>` component now accepts `redirectOnFail` to override the redirection path on authentication failure. This can be used to redirect to a different page when the user is not authenticated. This property only works if the `fallback` prop is not provided.

`redirectOnFail` also respects the newly introduced `appendCurrentPathToQuery` prop which can be used to append the current path to the query string of the redirection path. This can be used to redirect the user to the page they were trying to access after they logged in.

## Changes in `<Refine>`

We've removed the long deprecated props from `<Refine />` component and deprecated some more to encourage users to use the new routing system.

In earlier versions, we've accepted layout related props such as `Layout`, `Sider`, `Header`, `Footer`, `OffLayoutArea` and `Title`. All these props were used in the route creation process while wrapping the components to the `Layout` and others were passed to the `Layout` for configuration. Now, we've deprecated these props and we're encouraging users to use `Layout` prop and its props in the `children` of `<Refine />` component. This will allow users to customize the layout easily and provide custom layouts per route.

We've also deprecated the route related props such as;

- `catchAll`, which was used in rendering 404 pages and was unclear to the user when its going to be rendered in the app.
- `LoginPage`, which was rendered at `/login` path and was not customizable enough.
- `DashboardPage`, which wass rendered at `/` path and was limiting our users to handle the index page just with a single prop.
- `ReadyPage`, which was shown when `<Refine>` had no resources defined. Now, we're accepting empty resources array and rendering nothing in this case.

We're encouraging our users to create their own routes for the above props and give them the flexibility to use the full potential of the router library they're using.

## Integration with existing apps

We've made the changes to the routing system, the resource definitions and some additional changes to make the integration with existing apps possible.

Now you can migrate your existing apps to **refine** with ease and incrementally adopt **refine**'s features.

## Backward compatibility

We've made all the changes in a backward compatible way. You can continue using the old routing system and the old props of `<Refine />` component. Migrating to the new behaviors are optional but encouraged.

We're planning to keep the support for the deprecated props and the old behaviors until the next major version.
45 changes: 45 additions & 0 deletions .changeset/curvy-pianos-carry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
---
"@pankod/refine-antd": major
---

Updated the components to match the changes in routing system of `@pankod/refine-core`.

## `meta` property in components

This includes `meta` props in buttons and `Sider` component. `meta` property can be used to pass additional parameters to the navigation paths.

For a `posts` resource definition like this:

```tsx
<Refine
resources={[
{
name: "posts",
list: "/posts",
show: "/:authorId/posts/:id",
}
]}
>
```

You can pass `authorId` to the `ShowButton` component like this:

```tsx
<ShowButton resource="posts" id="1" meta={{ authorId: 123 }}>
```

This will navigate to `/123/posts/1` path.

## `syncWithLocation` support in `useDrawerForm` and `useModalForm` hooks

`useDrawerForm` and `useModalForm` hooks now support `syncWithLocation` prop. This prop can be used to sync the visibility state of them with the location via query params.

You can pass a boolean or an object with `key` and `syncId` properties.

- `key` is used to define the query param key. Default value is inferred from the resource and the action. For example `posts-create` for `posts` resource and `create` action.

- `syncId` is used to include the `id` property in the query param key. Default value is `false`. This is useful for `edit` and `clone` actions.

## Removed props

`ignoreAccessControlProvider` prop is removed from buttons.
27 changes: 27 additions & 0 deletions .changeset/eleven-nails-drum.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
"@pankod/refine-nextjs-router": major
---


We're releasing a new way to connect your router to **refine**.

The legacy `routerProvider` and its exports are now deprecated but accessible at `@pankod/refine-nextjs-router/legacy-app` and `@pankod/refine-nextjs-router/legacy-pages`.

The new `routerBindings` are smaller and more flexible than the previos one.

## New `routerBindings` export

New `routerBindings` contains following properties;

- `go`: Which returns a function to handle the navigation in `next`. It accepts a config object and navigates to the given path. Uses `useRouter` hook under the hood.
- `back`: Which returns a function to handle the navigation in `next`. It navigates back to the previous page. Uses `useRouter` hook under the hood.
- `parse`: Which returns a function to parse the given path and returns the `resource`, `id`, `action` and additional `params`. Uses `useRouter` for `/pages` dir and `usePathname` and `useSearchParams` for `/app` dir.
- `Link`: A component that accepts `to` prop and renders a link to the given path. Uses `Link` component from `next/link` under the hood.

## Complemetary Components

- `RefineRoutes` - A component that renders the routes for the resources when the actions are defined as components. This can be used to achieve the legacy behavior of `routerProvider` prop. `RefineRoutes` component accepts a render function as a child and passes `JSX.Element` if there's a match for the given path, `undefined` is passed otherwise. You can use this in `[[...refine]]` route to render the matching action component for a resource. We're encouraging our users to use file based routing instead of `[[...refine]]` route which provides more flexibility and a better development experience with its performance benefits.

- `NavigateToResource` - A component that navigates to the first `list` action of the `resources` array of `<Refine>`. Optionally, you can pass a `resource` prop to navigate to `list` action of the resource. This can be placed at the `index` route of your app to redirect to the first resource.

- `UnsavedChangesNotifier` - This component handles the prompt when the user tries to leave the page with unsaved changes. It can be placed under the `Refine` component.
45 changes: 45 additions & 0 deletions .changeset/hip-phones-lie.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
---
"@pankod/refine-mantine": major
---

Updated the components to match the changes in routing system of `@pankod/refine-core`.

## `meta` property in components

This includes `meta` props in buttons and `Sider` component. `meta` property can be used to pass additional parameters to the navigation paths.

For a `posts` resource definition like this:

```tsx
<Refine
resources={[
{
name: "posts",
list: "/posts",
show: "/:authorId/posts/:id",
}
]}
>
```

You can pass `authorId` to the `ShowButton` component like this:

```tsx
<ShowButton resource="posts" id="1" meta={{ authorId: 123 }}>
```

This will navigate to `/123/posts/1` path.

## `syncWithLocation` support in `useModalForm` hook

`useModalForm` hook now support `syncWithLocation` prop. This prop can be used to sync the visibility state of them with the location via query params.

You can pass a boolean or an object with `key` and `syncId` properties.

- `key` is used to define the query param key. Default value is inferred from the resource and the action. For example `posts-create` for `posts` resource and `create` action.

- `syncId` is used to include the `id` property in the query param key. Default value is `false`. This is useful for `edit` and `clone` actions.

## Removed props

`ignoreAccessControlProvider` prop is removed from buttons.
5 changes: 5 additions & 0 deletions .changeset/lazy-pugs-love.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@pankod/refine-react-location": major
---

Adjustments made to match the changes in `@pankod/refine-core` and `resource` definitions.
5 changes: 5 additions & 0 deletions .changeset/orange-phones-melt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@pankod/refine-kbar": major
---

Updated the action creation logic to match the changes in routing system of `@pankod/refine-core`.
36 changes: 36 additions & 0 deletions .changeset/perfect-masks-confess.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
"@pankod/refine-mui": major
---

Updated the components to match the changes in routing system of `@pankod/refine-core`.

## `meta` property in components

This includes `meta` props in buttons and `Sider` component. `meta` property can be used to pass additional parameters to the navigation paths.

For a `posts` resource definition like this:

```tsx
<Refine
resources={[
{
name: "posts",
list: "/posts",
show: "/:authorId/posts/:id",
}
]}
>
```

You can pass `authorId` to the `ShowButton` component like this:

```tsx
<ShowButton resource="posts" id="1" meta={{ authorId: 123 }}>
```

This will navigate to `/123/posts/1` path.

## Removed props

- `ignoreAccessControlProvider` prop is removed from buttons.
- `cardProps`, `cardHeaderProps`, `cardContentProps`, `cardActionsProps` and `actionButtons` props are removed from CRUD component.
Loading

0 comments on commit 3f10c6e

Please sign in to comment.