docs(tutorials): add refine tutorial
@@ -73,6 +73,17 @@
|
||||
</p>
|
||||
</a>
|
||||
</li>
|
||||
<li class="is-mobile-col-span-2">
|
||||
<a href="/docs/tutorials/refine" class="aw-card is-normal">
|
||||
<header class="u-flex u-cross-baseline u-gap-4">
|
||||
<span class="icon-svelte aw-u-font-size-24" aria-hidden="true" />
|
||||
<h4 class="aw-sub-body-500 aw-u-color-text-primary">Refine</h4>
|
||||
</header>
|
||||
<p class="aw-sub-body-400 u-margin-block-start-4">
|
||||
Learn Appwrite Auth, Databases, and more with Refine.
|
||||
</p>
|
||||
</a>
|
||||
</li>
|
||||
<li class="is-mobile-col-span-2">
|
||||
<article class="aw-card is-full-color">
|
||||
<header class="u-flex u-cross-baseline u-gap-4">
|
||||
|
||||
10
src/routes/docs/tutorials/refine/+layout.svelte
Normal file
@@ -0,0 +1,10 @@
|
||||
<script lang="ts">
|
||||
import { globToTutorial } from '$lib/utils/tutorials.js';
|
||||
import { setContext } from 'svelte';
|
||||
|
||||
export let data;
|
||||
const tutorials = globToTutorial(data);
|
||||
setContext('tutorials', tutorials);
|
||||
</script>
|
||||
|
||||
<slot />
|
||||
11
src/routes/docs/tutorials/refine/+layout.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import type { LayoutLoad } from './$types';
|
||||
|
||||
export const load: LayoutLoad = ({ url }) => {
|
||||
const tutorials = import.meta.glob('./**/*.markdoc', {
|
||||
eager: true
|
||||
});
|
||||
return {
|
||||
tutorials,
|
||||
pathname: url.pathname
|
||||
};
|
||||
};
|
||||
6
src/routes/docs/tutorials/refine/+page.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { redirect } from '@sveltejs/kit';
|
||||
import type { PageLoad } from './$types';
|
||||
|
||||
export const load: PageLoad = async () => {
|
||||
throw redirect(303, '/docs/tutorials/refine/step-1');
|
||||
};
|
||||
31
src/routes/docs/tutorials/refine/step-1/+page.markdoc
Normal file
@@ -0,0 +1,31 @@
|
||||
---
|
||||
layout: tutorial
|
||||
title: Build an Admin Panel with Refine
|
||||
description: Learn to build a Refine app with no backend code using an Appwrite backend.
|
||||
step: 1
|
||||
difficulty: beginner
|
||||
readtime: 10
|
||||
---
|
||||
|
||||
**Blog admin panel**: a CRUD app to manage Blog content.
|
||||
In this tutorial, you will build admin panel app with Appwrite and [Refine](https://github.com/refinedev/refine).
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
# Concepts {% #concepts %}
|
||||
|
||||
This tutorial will introduce the following concepts:
|
||||
|
||||
1. Setting up your first project
|
||||
2. Authentication
|
||||
3. Databases and collections
|
||||
4. Queries and pagination
|
||||
5. Storage
|
||||
|
||||
|
||||
# Prerequisites {% #prerequisites %}
|
||||
|
||||
1. Basic knowledge of Typescript and React.
|
||||
2. Have [Node.js](https://nodejs.org/en) and [NPM](https://www.npmjs.com/) installed on your computer
|
||||
41
src/routes/docs/tutorials/refine/step-2/+page.markdoc
Normal file
@@ -0,0 +1,41 @@
|
||||
---
|
||||
layout: tutorial
|
||||
title: Create app
|
||||
description: Create a Refine app project and integrate with Appwrite.
|
||||
step: 2
|
||||
---
|
||||
|
||||
# Create Refine project {% #create-react-project %}
|
||||
|
||||
Create a Refine app with the `npm create` command.
|
||||
|
||||
```sh
|
||||
npm create refine-app@latest -- --preset refine-appwrite
|
||||
```
|
||||
|
||||
We're using the `refine-appwrite` preset that installs the [`@refinedev/appwrite`](https://github.com/refinedev/refine/tree/master/packages/appwrite) which already has the Appwrite dependency pre-configured.
|
||||
|
||||
To make this example more visual, we'll use the Ant Desing UI package which natively supported by Refine.
|
||||
|
||||
{% info title="Note" %}
|
||||
|
||||
No extra dependencies required for this tutorial. If you want to integrate Appwrite into an existing Refine app, use this command:
|
||||
```sh
|
||||
npm install @refinedev/appwrite
|
||||
```
|
||||
Then follow [this](https://refine.dev/docs/packages/documentation/data-providers/appwrite) guide.
|
||||
{% /info %}
|
||||
|
||||
|
||||
|
||||
You can start the development server to watch your app update in the browser as you make changes.
|
||||
|
||||
```sh
|
||||
npm run dev -- --open --port 3000
|
||||
```
|
||||
|
||||
Once the app is running, you should be greeted with the welcome screen.
|
||||
|
||||
|
||||

|
||||
|
||||
60
src/routes/docs/tutorials/refine/step-3/+page.markdoc
Normal file
@@ -0,0 +1,60 @@
|
||||
---
|
||||
layout: tutorial
|
||||
title: Set up Appwrite
|
||||
description: Import and initialize Appwrite for your react application.
|
||||
step: 3
|
||||
---
|
||||
|
||||
# Create project {% #create-project %}
|
||||
|
||||
Head to the [Appwrite Console](https://cloud.appwrite.io/console).
|
||||
|
||||
{% only_dark %}
|
||||

|
||||
{% /only_dark %}
|
||||
{% only_light %}
|
||||

|
||||
{% /only_light %}
|
||||
|
||||
If this is your first time using Appwrite, create an account and create your first project.
|
||||
|
||||
Then, under **Add a platform**, add a **Web app**. The **Hostname** should be localhost.
|
||||
|
||||
{% only_dark %}
|
||||

|
||||
{% /only_dark %}
|
||||
{% only_light %}
|
||||

|
||||
{% /only_light %}
|
||||
|
||||
You can skip optional steps.
|
||||
|
||||
# Initialize Appwrite SDK {% #init-sdk %}
|
||||
|
||||
To use Appwrite in our Refine app, we'll need to find our project ID. Find your project's ID in the **Settings** page.
|
||||
|
||||
{% only_dark %}
|
||||

|
||||
{% /only_dark %}
|
||||
{% only_light %}
|
||||

|
||||
{% /only_light %}
|
||||
|
||||
Navigate to `src/utility/appwriteClient.ts` and add your API credentials.
|
||||
|
||||
|
||||
```ts
|
||||
import { Account, Appwrite, Storage } from "@refinedev/appwrite";
|
||||
|
||||
const APPWRITE_URL = '<YOUR_API_ENDPOINT>'; // Replace with your Appwrite API Endpoint
|
||||
const APPWRITE_PROJECT = "<YOUR_PROJECT_ID>"; // Replace with your project ID
|
||||
|
||||
const appwriteClient = new Appwrite();
|
||||
|
||||
appwriteClient.setEndpoint(APPWRITE_URL).setProject(APPWRITE_PROJECT);
|
||||
const account = new Account(appwriteClient);
|
||||
const storage = new Storage(appwriteClient);
|
||||
|
||||
export { account, appwriteClient, storage };
|
||||
|
||||
```
|
||||
162
src/routes/docs/tutorials/refine/step-4/+page.markdoc
Normal file
@@ -0,0 +1,162 @@
|
||||
---
|
||||
layout: tutorial
|
||||
title: Add authentication
|
||||
description: Add authentication to your Refine application.
|
||||
step: 4
|
||||
---
|
||||
|
||||
# Authentication Provider {% #auth-provider %}
|
||||
|
||||
|
||||
Upon [creating a new project](https://refine.dev/docs/getting-started/quickstart/) with Appwrite preset, the CLI automatically creates [Auth Provider](https://refine.dev/docs/tutorial/understanding-authprovider/index/#what-is-auth-provider) file.
|
||||
|
||||
|
||||
You'll see a file named [`src/authProvider.ts`](https://github.com/refinedev/refine/blob/master/examples/data-provider-appwrite-tutorial-docs/src/utility/authProvider.ts) created by CLI. This auto-generated file contains pre-defined functions using Appwrite Auth methods internally to perform authentication and authorization operations.
|
||||
|
||||
|
||||
The auth provider registered to the Refine app by default in the `src/App.tsx`.
|
||||
```ts
|
||||
|
||||
import { authProvider } from './authProvider';
|
||||
...
|
||||
|
||||
<Refine
|
||||
...
|
||||
authProvider={authProvider}
|
||||
>
|
||||
```
|
||||
|
||||
Now, we can configure the routing and auth components to manage logins and sign ups.
|
||||
|
||||
|
||||
# Routing {% #routing %}
|
||||
|
||||
Refine offers router bindings and utilities for [React Router v6](https://reactrouter.com/en/main) and improves the user interface with the [routerProvider](https://refine.dev/docs/api-reference/core/components/refine-config/#routerprovider) prop.
|
||||
This allows the framework to identify resources from routes and efficiently handle query parameters and navigation tasks.
|
||||
|
||||
|
||||
```ts
|
||||
import { authProvider } from './authProvider';
|
||||
import routerProvider from '@refinedev/react-router-v6';
|
||||
...
|
||||
|
||||
<Refine
|
||||
...
|
||||
authProvider={authProvider}
|
||||
routerProvider={routerProvider}
|
||||
|
||||
>
|
||||
```
|
||||
|
||||
# Login page {% #login-page %}
|
||||
|
||||
|
||||
|
||||
|
||||
We'll use [Routes](https://reactrouter.com/en/main/components/routes) component to connect routing mechanisim along with [AuthPage](https://refine.dev/docs/api-reference/antd/components/antd-auth-page/#usage) component which returns ready-to-use authentication pages for login, register, update, and forgot password actions.
|
||||
|
||||
Update `src/App.tsx` to the following code.
|
||||
|
||||
```ts
|
||||
import { Authenticated, Refine } from '@refinedev/core';
|
||||
import { dataProvider, liveProvider } from '@refinedev/appwrite';
|
||||
import {
|
||||
AuthPage,
|
||||
ErrorComponent,
|
||||
RefineThemes,
|
||||
ThemedLayoutV2,
|
||||
useNotificationProvider,
|
||||
} from '@refinedev/antd';
|
||||
import routerProvider, {
|
||||
CatchAllNavigate,
|
||||
NavigateToResource,
|
||||
} from '@refinedev/react-router-v6';
|
||||
import '@refinedev/antd/dist/reset.css';
|
||||
|
||||
import { App as AntdApp, ConfigProvider } from 'antd';
|
||||
import { BrowserRouter, Outlet, Route, Routes } from 'react-router-dom';
|
||||
|
||||
import { appwriteClient } from './utility';
|
||||
import { authProvider } from './authProvider';
|
||||
|
||||
const App: React.FC = () => {
|
||||
return (
|
||||
<BrowserRouter>
|
||||
<ConfigProvider theme={RefineThemes.Blue}>
|
||||
<AntdApp>
|
||||
<Refine
|
||||
dataProvider={dataProvider(appwriteClient, {
|
||||
databaseId: '<APPWRITE_DATABASE_ID>',
|
||||
})}
|
||||
liveProvider={liveProvider(appwriteClient, {
|
||||
databaseId: '<APPWRITE_DATABASE_ID>',
|
||||
})}
|
||||
authProvider={authProvider}
|
||||
routerProvider={routerProvider}
|
||||
notificationProvider={useNotificationProvider}
|
||||
>
|
||||
<Routes>
|
||||
<Route
|
||||
element={
|
||||
<Authenticated
|
||||
fallback={
|
||||
<CatchAllNavigate to="/login" />
|
||||
}
|
||||
>
|
||||
<ThemedLayoutV2>
|
||||
<Outlet />
|
||||
</ThemedLayoutV2>
|
||||
</Authenticated>
|
||||
}
|
||||
></Route>
|
||||
|
||||
<Route
|
||||
element={
|
||||
<Authenticated fallback={<Outlet />}>
|
||||
<NavigateToResource resource="<APPWRITE_COLLECTION_ID>" />
|
||||
</Authenticated>
|
||||
}
|
||||
>
|
||||
<Route path="/login" element={<AuthPage />} />
|
||||
<Route
|
||||
path="/register"
|
||||
element={<AuthPage type="register" />}
|
||||
/>
|
||||
</Route>
|
||||
|
||||
<Route
|
||||
element={
|
||||
<Authenticated>
|
||||
<ThemedLayoutV2>
|
||||
<Outlet />
|
||||
</ThemedLayoutV2>
|
||||
</Authenticated>
|
||||
}
|
||||
>
|
||||
<Route path="*" element={<ErrorComponent />} />
|
||||
</Route>
|
||||
</Routes>
|
||||
</Refine>
|
||||
</AntdApp>
|
||||
</ConfigProvider>
|
||||
</BrowserRouter>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
```
|
||||
Key concepts to handle authentication and routing:
|
||||
|
||||
- The [`<AuthPage>`](https://refine.dev/docs/api-reference/antd/components/antd-auth-page) component in Refine includes pages for login, registration, password reset, and password update functionalities.
|
||||
- To manage authenticated routes effectively, the [`<Authenticated>`](https://refine.dev/docs/api-reference/core/components/auth/authenticated/) component using to determine the user's authentication status and accordingly directs them or displays relevant elements.
|
||||
- Within the `<Authenticated>` component, we use the `<Outlet>` component from `react-router-dom` to render secure routes that are accessible only to authenticated users.
|
||||
- We set up a `/login` route for redirecting unauthenticated users, using Refine's AuthPage components with a `type="login"` prop to create the login page efficiently.
|
||||
|
||||
When you refresh the page, the login screen appears.
|
||||
|
||||

|
||||
|
||||
|
||||
We'll activate the authentication mechanisim with Appwrite in the next section.
|
||||
|
||||
|
||||
83
src/routes/docs/tutorials/refine/step-5/+page.markdoc
Normal file
@@ -0,0 +1,83 @@
|
||||
---
|
||||
layout: tutorial
|
||||
title: Add database
|
||||
description: Add a database to your React application using Appwrite Web SDK.
|
||||
step: 5
|
||||
---
|
||||
# Create collection {% #create-collection %}
|
||||
In Appwrite, data is stored as a collection of documents. Create a collection in the [Appwrite Console](https://cloud.appwrite.io/) to store our ideas.
|
||||
|
||||
{% only_dark %}
|
||||

|
||||
{% /only_dark %}
|
||||
{% only_light %}
|
||||

|
||||
{% /only_light %}
|
||||
|
||||
Create a new collection with the following attributes:
|
||||
| Field | Type | Required |
|
||||
|-------------|--------|----------|
|
||||
| title | String | Yes |
|
||||
| content | String | Yes |
|
||||
|
||||
# Connect database to the Refine app {% #blog-context %}
|
||||
|
||||
Now that you have a collection to hold blog post contents, we can read and write to it from our app.
|
||||
|
||||
|
||||
|
||||
To integrate Appwrite API with the Refine App,
|
||||
- Add a resources array to the `<Refine />` component in `App.tsx`
|
||||
- Include your `Appwrite Database ID` in both `dataProvider` and `liveProvider`, and specify the `Appwrite Collection ID` in the resource name property.
|
||||
|
||||
|
||||
```ts
|
||||
import { dataProvider, liveProvider } from '@refinedev/appwrite';
|
||||
...
|
||||
|
||||
<Refine
|
||||
dataProvider={dataProvider(appwriteClient, {
|
||||
databaseId: "<APPWRITE_DATABASE_ID>",
|
||||
})}
|
||||
liveProvider={liveProvider(appwriteClient, {
|
||||
databaseId: "<APPWRITE_DATABASE_ID>",
|
||||
})}
|
||||
authProvider={authProvider}
|
||||
routerProvider={routerProvider}
|
||||
resources={[
|
||||
{
|
||||
name: "<APPWRITE_COLLECTION_ID>", // resource name must be the same as APPWRITE_COLLECTION_ID.
|
||||
list: "/posts", // Means that the list action of this resource will be available at /posts in your app
|
||||
create: "/posts/create", // create action of this resource will be available at /posts/create
|
||||
edit: "/posts/edit/:id", // edit action of this resource will be available at /posts/edit/:id
|
||||
show: "/posts/show/:id", // show action of this resource will be available at /posts/show/:id
|
||||
},
|
||||
]}
|
||||
...
|
||||
/>;
|
||||
```
|
||||
|
||||
Key concepts to performing CRUD operations:
|
||||
|
||||
- A [resource](https://refine.dev/docs/api-reference/core/components/refine-config/#name) connects an API endpoint's entity with the app's pages, enabling them to interact with the API data.
|
||||
In the resource configuration, path definitions allow Refine to automatically recognize the resource's available actions and identify it based on the current path, eliminating the need for manual specification in hooks and components.
|
||||
|
||||
- The [data provider](https://refine.dev/docs/tutorial/understanding-dataprovider/index/#using-data-providers-in-refine) serves as your app's data layer, handling HTTP requests and managing data retrieval. Refine uses this through data hooks.
|
||||
With built-in support for Appwrite in Refine, you only need to pass your Appwrite database ID to the `dataProvider` property.
|
||||
|
||||
|
||||
{% info title="Note" %}
|
||||
The [@refinedev/appwrite](https://www.npmjs.com/package/@refinedev/appwrite) package supports [Live/Realtime Provider](https://refine.dev/docs/api-reference/core/providers/live-provider/) natively.
|
||||
{% /info %}
|
||||
|
||||
|
||||
|
||||
|
||||
At this point, we created our Appwrite database and connected to the Refine App.
|
||||
|
||||
You can now register and login to the app.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
396
src/routes/docs/tutorials/refine/step-6/+page.markdoc
Normal file
@@ -0,0 +1,396 @@
|
||||
---
|
||||
layout: tutorial
|
||||
title: Create CRUD pages
|
||||
description: Add database queries and CRUD pages using Appwrite in your Refine application.
|
||||
step: 6
|
||||
---
|
||||
|
||||
We're going to add CRUD pages to our admin panel so you can list, create, and view blog posts records.
|
||||
|
||||
|
||||
# List page {% #list-page %}
|
||||
|
||||
|
||||
First, create a listing page to show Appwrite API data in a table by copying the code below into `src/pages/posts` and saving it as `list.tsx`.
|
||||
|
||||
```ts
|
||||
import { IResourceComponentsProps } from '@refinedev/core';
|
||||
import {
|
||||
List,
|
||||
useTable,
|
||||
EditButton,
|
||||
ShowButton,
|
||||
getDefaultSortOrder,
|
||||
DeleteButton,
|
||||
} from '@refinedev/antd';
|
||||
import { Table, Space } from 'antd';
|
||||
|
||||
import { IPost } from '../../interfaces';
|
||||
|
||||
export const PostList: React.FC<IResourceComponentsProps> = () => {
|
||||
const { tableProps, sorters } = useTable<IPost>({
|
||||
initialSorter: [
|
||||
{
|
||||
field: '$id',
|
||||
order: 'asc',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
return (
|
||||
<List>
|
||||
<Table {...tableProps} rowKey="id">
|
||||
<Table.Column
|
||||
dataIndex="id"
|
||||
title="ID"
|
||||
sorter
|
||||
width={100}
|
||||
defaultSortOrder={getDefaultSortOrder('id', sorters)}
|
||||
/>
|
||||
<Table.Column dataIndex="title" title="Title" sorter />
|
||||
|
||||
<Table.Column<IPost>
|
||||
title="Actions"
|
||||
dataIndex="actions"
|
||||
fixed="right"
|
||||
render={(_, record) => (
|
||||
<Space>
|
||||
<EditButton
|
||||
hideText
|
||||
size="small"
|
||||
recordItemId={record.id}
|
||||
/>
|
||||
<ShowButton
|
||||
hideText
|
||||
size="small"
|
||||
recordItemId={record.id}
|
||||
/>
|
||||
<DeleteButton
|
||||
hideText
|
||||
size="small"
|
||||
recordItemId={record.id}
|
||||
/>
|
||||
</Space>
|
||||
)}
|
||||
/>
|
||||
</Table>
|
||||
</List>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
# Create page {% #create-page %}
|
||||
|
||||
Create a new record page for the Appwrite API by copying the following code and saving it as `create.tsx`.
|
||||
|
||||
|
||||
```ts
|
||||
import { HttpError, IResourceComponentsProps } from '@refinedev/core';
|
||||
import { Create, useForm } from '@refinedev/antd';
|
||||
import { Form, Input } from 'antd';
|
||||
|
||||
import { IPost, IPostVariables } from '../../interfaces';
|
||||
|
||||
export const PostCreate: React.FC<IResourceComponentsProps> = () => {
|
||||
const { formProps, saveButtonProps } = useForm<
|
||||
IPost,
|
||||
HttpError,
|
||||
IPostVariables
|
||||
>();
|
||||
|
||||
return (
|
||||
<Create saveButtonProps={saveButtonProps}>
|
||||
<Form {...formProps} layout="vertical">
|
||||
<Form.Item
|
||||
label="Title"
|
||||
name="title"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label="Content"
|
||||
name="content"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input.TextArea rows={5} />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Create>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
# Edit page {% #edit-page %}
|
||||
|
||||
Create a page for editing a records with the following code and saving it as `edit.tsx`.
|
||||
|
||||
|
||||
```ts
|
||||
import React from 'react';
|
||||
import { HttpError, IResourceComponentsProps } from '@refinedev/core';
|
||||
import { Edit, useForm } from '@refinedev/antd';
|
||||
import { Form, Input } from 'antd';
|
||||
import { IPost, IPostVariables } from '../../interfaces';
|
||||
|
||||
export const PostEdit: React.FC<IResourceComponentsProps> = () => {
|
||||
const { formProps, saveButtonProps } = useForm<
|
||||
IPost,
|
||||
HttpError,
|
||||
IPostVariables
|
||||
>();
|
||||
|
||||
return (
|
||||
<Edit saveButtonProps={saveButtonProps}>
|
||||
<Form {...formProps} layout="vertical">
|
||||
<Form.Item
|
||||
label="Title"
|
||||
name="title"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="Content"
|
||||
name="content"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input.TextArea rows={5} />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Edit>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
# Show page {% #show-page %}
|
||||
|
||||
Create a page for showig the records with the following code and saving it as `edit.tsx`.
|
||||
|
||||
|
||||
```ts
|
||||
import { useShow, IResourceComponentsProps } from '@refinedev/core';
|
||||
|
||||
import { Show, MarkdownField } from '@refinedev/antd';
|
||||
import { Typography } from 'antd';
|
||||
import { IPost } from '../../interfaces';
|
||||
|
||||
const { Title, Text } = Typography;
|
||||
|
||||
export const PostShow: React.FC<IResourceComponentsProps> = () => {
|
||||
const { queryResult } = useShow<IPost>();
|
||||
const { data, isLoading } = queryResult;
|
||||
const record = data?.data;
|
||||
|
||||
return (
|
||||
<Show isLoading={isLoading}>
|
||||
<Title level={5}>Id</Title>
|
||||
<Text>{record?.id}</Text>
|
||||
|
||||
<Title level={5}>Title</Title>
|
||||
<Text>{record?.title}</Text>
|
||||
|
||||
<Title level={5}>Content</Title>
|
||||
<MarkdownField value={record?.content} />
|
||||
</Show>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
# Interfaces {% #interfaces %}
|
||||
|
||||
We need to add interfaces to `src/interfaces/index.d.ts` file.
|
||||
|
||||
|
||||
```ts
|
||||
export interface IFile {
|
||||
name: string;
|
||||
percent: number;
|
||||
size: number;
|
||||
status: 'error' | 'success' | 'done' | 'uploading' | 'removed';
|
||||
type: string;
|
||||
uid: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export interface IPost {
|
||||
id: string;
|
||||
title: string;
|
||||
content: string;
|
||||
}
|
||||
|
||||
export interface IPostVariables {
|
||||
id: string;
|
||||
title: string;
|
||||
content: string;
|
||||
}
|
||||
```
|
||||
|
||||
# Connect pages to the App
|
||||
|
||||
Finally, import the pages into `App.tsx` and define them in the `<Route>` components.
|
||||
|
||||
Simply, paste the following into `App.tsx`.
|
||||
|
||||
|
||||
```ts
|
||||
import { Authenticated, Refine } from '@refinedev/core';
|
||||
import { dataProvider, liveProvider } from '@refinedev/appwrite';
|
||||
import {
|
||||
AuthPage,
|
||||
ErrorComponent,
|
||||
RefineThemes,
|
||||
ThemedLayoutV2,
|
||||
useNotificationProvider,
|
||||
} from '@refinedev/antd';
|
||||
import routerProvider, {
|
||||
CatchAllNavigate,
|
||||
DocumentTitleHandler,
|
||||
NavigateToResource,
|
||||
UnsavedChangesNotifier,
|
||||
} from '@refinedev/react-router-v6';
|
||||
import '@refinedev/antd/dist/reset.css';
|
||||
|
||||
import { App as AntdApp, ConfigProvider } from 'antd';
|
||||
import { BrowserRouter, Outlet, Route, Routes } from 'react-router-dom';
|
||||
|
||||
import { appwriteClient } from './utility';
|
||||
import { authProvider } from './authProvider';
|
||||
import { PostCreate, PostEdit, PostList, PostShow } from './pages/posts';
|
||||
|
||||
const App: React.FC = () => {
|
||||
return (
|
||||
<BrowserRouter>
|
||||
<ConfigProvider theme={RefineThemes.Blue}>
|
||||
<AntdApp>
|
||||
<Refine
|
||||
dataProvider={dataProvider(appwriteClient, {
|
||||
databaseId: '<APPWRITE_DATABASE_ID>',
|
||||
})}
|
||||
liveProvider={liveProvider(appwriteClient, {
|
||||
databaseId: '<APPWRITE_DATABASE_ID>',
|
||||
})}
|
||||
authProvider={authProvider}
|
||||
routerProvider={routerProvider}
|
||||
resources={[
|
||||
{
|
||||
name: '<APPWRITE_COLLECTION_ID>',
|
||||
list: '/posts',
|
||||
create: '/posts/create',
|
||||
edit: '/posts/edit/:id',
|
||||
show: '/posts/show/:id',
|
||||
meta: {
|
||||
label: 'Posts',
|
||||
},
|
||||
},
|
||||
]}
|
||||
notificationProvider={useNotificationProvider}
|
||||
options={{
|
||||
liveMode: 'auto',
|
||||
syncWithLocation: true,
|
||||
warnWhenUnsavedChanges: true,
|
||||
}}
|
||||
>
|
||||
<Routes>
|
||||
<Route
|
||||
element={
|
||||
<Authenticated
|
||||
fallback={
|
||||
<CatchAllNavigate to="/login" />
|
||||
}
|
||||
>
|
||||
<ThemedLayoutV2>
|
||||
<Outlet />
|
||||
</ThemedLayoutV2>
|
||||
</Authenticated>
|
||||
}
|
||||
>
|
||||
<Route
|
||||
index
|
||||
element={
|
||||
<NavigateToResource resource="<APPWRITE_COLLECTION_ID>" />
|
||||
}
|
||||
/>
|
||||
|
||||
<Route path="/posts">
|
||||
<Route index element={<PostList />} />
|
||||
<Route
|
||||
path="create"
|
||||
element={<PostCreate />}
|
||||
/>
|
||||
<Route
|
||||
path="edit/:id"
|
||||
element={<PostEdit />}
|
||||
/>
|
||||
<Route
|
||||
path="show/:id"
|
||||
element={<PostShow />}
|
||||
/>
|
||||
</Route>
|
||||
</Route>
|
||||
|
||||
<Route
|
||||
element={
|
||||
<Authenticated fallback={<Outlet />}>
|
||||
<NavigateToResource resource="<APPWRITE_COLLECTION_ID>" />
|
||||
</Authenticated>
|
||||
}
|
||||
>
|
||||
<Route
|
||||
path="/login"
|
||||
element={
|
||||
<AuthPage
|
||||
forgotPasswordLink={false}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/register"
|
||||
element={<AuthPage type="register" />}
|
||||
/>
|
||||
</Route>
|
||||
|
||||
<Route
|
||||
element={
|
||||
<Authenticated>
|
||||
<ThemedLayoutV2>
|
||||
<Outlet />
|
||||
</ThemedLayoutV2>
|
||||
</Authenticated>
|
||||
}
|
||||
>
|
||||
<Route path="*" element={<ErrorComponent />} />
|
||||
</Route>
|
||||
</Routes>
|
||||
<UnsavedChangesNotifier />
|
||||
<DocumentTitleHandler />
|
||||
</Refine>
|
||||
</AntdApp>
|
||||
</ConfigProvider>
|
||||
</BrowserRouter>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
|
||||
|
||||
|
||||
```
|
||||
|
||||
30
src/routes/docs/tutorials/refine/step-7/+page.markdoc
Normal file
@@ -0,0 +1,30 @@
|
||||
---
|
||||
layout: tutorial
|
||||
title: Next steps
|
||||
description: Run your Refine project built with Appwrite
|
||||
step: 7
|
||||
---
|
||||
|
||||
|
||||
|
||||
# Test your project {% #test-project %}
|
||||
Run your project with `npm run dev -- --open --port 3000` and open [http://localhost:3000](http://localhost:3000) in your browser.
|
||||
|
||||
Now, we are able to listing the records retrieved from Appwrite backend on table, show the each record, edit the existing records, and delete functionality on records.
|
||||
|
||||
|
||||
- List Page
|
||||
|
||||

|
||||
|
||||
- Create Page
|
||||
|
||||

|
||||
|
||||
- Edit Page
|
||||
|
||||

|
||||
|
||||
- Show Page
|
||||
|
||||

|
||||
BIN
static/images/docs/tutorials/refine/blog-admin-panel.png
Normal file
|
After Width: | Height: | Size: 52 KiB |
BIN
static/images/docs/tutorials/refine/posts-collection-dark.png
Normal file
|
After Width: | Height: | Size: 125 KiB |
BIN
static/images/docs/tutorials/refine/posts-collection-light.png
Normal file
|
After Width: | Height: | Size: 126 KiB |
BIN
static/images/docs/tutorials/refine/refine-create-page.png
Normal file
|
After Width: | Height: | Size: 9.9 KiB |
BIN
static/images/docs/tutorials/refine/refine-edit-page.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
static/images/docs/tutorials/refine/refine-list-page.png
Normal file
|
After Width: | Height: | Size: 43 KiB |
BIN
static/images/docs/tutorials/refine/refine-login-page.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
static/images/docs/tutorials/refine/refine-show-page.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
static/images/docs/tutorials/refine/refine-welcome-page.png
Normal file
|
After Width: | Height: | Size: 140 KiB |