+
NocoBase
{props.children}
diff --git a/packages/client/src/route-switch/antd/index.ts b/packages/client/src/route-switch/antd/index.ts
index 1e732acc5..8c8df6eb7 100644
--- a/packages/client/src/route-switch/antd/index.ts
+++ b/packages/client/src/route-switch/antd/index.ts
@@ -1,2 +1,4 @@
export * from './admin-layout';
export * from './auth-layout';
+export * from './route-schema-component';
+
diff --git a/packages/client/src/route-switch/antd/route-schema-component/index.tsx b/packages/client/src/route-switch/antd/route-schema-component/index.tsx
new file mode 100644
index 000000000..50e591fc4
--- /dev/null
+++ b/packages/client/src/route-switch/antd/route-schema-component/index.tsx
@@ -0,0 +1,7 @@
+import React from 'react';
+import { RemoteSchemaComponent, useRoute } from '../../../';
+
+export function RouteSchemaComponent(props: any) {
+ const route = useRoute();
+ return
;
+}
diff --git a/packages/client/src/schema-component/antd/action/Action.tsx b/packages/client/src/schema-component/antd/action/Action.tsx
index a04d80ecf..180678f05 100644
--- a/packages/client/src/schema-component/antd/action/Action.tsx
+++ b/packages/client/src/schema-component/antd/action/Action.tsx
@@ -1,10 +1,10 @@
-import React, { useState } from 'react';
-import { Button, ButtonProps } from 'antd';
import { observer, RecursionField, useField, useFieldSchema } from '@formily/react';
-import { useA } from './hooks';
-import { VisibleContext } from './context';
-import { ComposedAction } from './types';
+import { Button } from 'antd';
+import React, { useState } from 'react';
import { ActionDrawer } from './Action.Drawer';
+import { VisibleContext } from './context';
+import { useA } from './hooks';
+import { ComposedAction } from './types';
export const Action: ComposedAction = observer((props) => {
const { useAction = useA, onClick, ...others } = props;
@@ -22,7 +22,7 @@ export const Action: ComposedAction = observer((props) => {
run();
}}
>
- {schema.title}
+ {field.title}
diff --git a/packages/client/src/system-settings/demos/demo1.tsx b/packages/client/src/system-settings/demos/demo1.tsx
new file mode 100644
index 000000000..5fb03052d
--- /dev/null
+++ b/packages/client/src/system-settings/demos/demo1.tsx
@@ -0,0 +1,55 @@
+import {
+ AntdSchemaComponentProvider,
+ APIClient,
+ APIClientProvider,
+ PluginManager,
+ PluginManagerProvider,
+ SchemaComponentProvider,
+ SystemSettingsProvider,
+ SystemSettingsShortcut,
+ useSystemSettings
+} from '@nocobase/client';
+import MockAdapter from 'axios-mock-adapter';
+import React from 'react';
+
+const apiClient = new APIClient();
+
+const mock = new MockAdapter(apiClient.axios);
+
+mock.onGet('/system_settings:get').reply(200, {
+ data: {
+ title: 'NocoBase',
+ },
+});
+
+const Demo = () => {
+ const { data } = useSystemSettings();
+ return
+
以下为测试内容
+ System title: {data?.data?.title}
+ ;
+};
+
+export default () => {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/packages/client/src/system-settings/index.md b/packages/client/src/system-settings/index.md
index eccd0bf7b..1978f7af1 100644
--- a/packages/client/src/system-settings/index.md
+++ b/packages/client/src/system-settings/index.md
@@ -5,11 +5,18 @@ group:
path: /client
---
-# SystemSettings
待定
+# SystemSettings
## SystemSettingsProvider
-## SystemSettingsAction
+## SystemSettingsShortcut
## useSystemSettings
+```ts
+const { data, loading, refresh } = useSystemSettings();
+```
+
+## Examples
+
+
diff --git a/packages/client/src/current-user/index.tsx b/packages/client/src/user/CurrentUser.tsx
similarity index 64%
rename from packages/client/src/current-user/index.tsx
rename to packages/client/src/user/CurrentUser.tsx
index 103358d05..7f36a358d 100644
--- a/packages/client/src/current-user/index.tsx
+++ b/packages/client/src/user/CurrentUser.tsx
@@ -1,11 +1,10 @@
import { Menu } from 'antd';
import React from 'react';
-import { MoreOutlined, DesktopOutlined } from '@ant-design/icons';
+import { useHistory } from 'react-router-dom';
import { ProfileAction } from './ProfileAction';
-export const CurrentUser = () => null;
-
-CurrentUser.Dropdown = () => {
+export const CurrentUser = () => {
+ const history = useHistory();
return (
diff --git a/packages/client/src/user/ProfileAction.tsx b/packages/client/src/user/ProfileAction.tsx
new file mode 100644
index 000000000..dd7f6c559
--- /dev/null
+++ b/packages/client/src/user/ProfileAction.tsx
@@ -0,0 +1,105 @@
+import { ISchema, useForm } from '@formily/react';
+import { uid } from '@formily/shared';
+import { Menu } from 'antd';
+import React, { useState } from 'react';
+import { SchemaComponent, useActionVisible, useRequest, VisibleContext } from '../';
+
+const useCloseAction = () => {
+ const { setVisible } = useActionVisible();
+ const form = useForm();
+ return {
+ async run() {
+ setVisible(false);
+ form.submit((values) => {
+ console.log(values);
+ });
+ },
+ };
+};
+
+const useCurrentUserValues = (props, options) => {
+ return useRequest(
+ () =>
+ Promise.resolve({
+ data: {},
+ }),
+ {
+ ...options,
+ },
+ );
+};
+
+const useSaveCurrentUserValues = () => {
+ const { setVisible } = useActionVisible();
+ const form = useForm();
+ return {
+ async run() {
+ form.submit((values) => {
+ setVisible(false);
+ console.log(values);
+ });
+ },
+ };
+};
+
+const schema: ISchema = {
+ type: 'object',
+ properties: {
+ [uid()]: {
+ 'x-decorator': 'Form',
+ 'x-decorator-props': {
+ useValues: '{{ useCurrentUserValues }}',
+ },
+ 'x-component': 'Action.Drawer',
+ type: 'void',
+ title: '个人资料',
+ properties: {
+ nickname: {
+ type: 'string',
+ title: "{{t('Nickname')}}",
+ 'x-decorator': 'FormItem',
+ 'x-component': 'Input',
+ required: true,
+ },
+ footer: {
+ 'x-component': 'Action.Drawer.Footer',
+ type: 'void',
+ properties: {
+ cancel: {
+ title: 'Cancel',
+ 'x-component': 'Action',
+ 'x-component-props': {
+ useAction: '{{ useCloseAction }}',
+ },
+ },
+ submit: {
+ title: 'Submit',
+ 'x-component': 'Action',
+ 'x-component-props': {
+ type: 'primary',
+ useAction: '{{ useSaveCurrentUserValues }}',
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+};
+
+export const ProfileAction = () => {
+ const [visible, setVisible] = useState(false);
+ return (
+
+ {
+ setVisible(true);
+ }}
+ >
+ 个人资料
+
+
+
+ );
+};
diff --git a/packages/client/src/user/SigninPage.tsx b/packages/client/src/user/SigninPage.tsx
new file mode 100644
index 000000000..10704efd6
--- /dev/null
+++ b/packages/client/src/user/SigninPage.tsx
@@ -0,0 +1,79 @@
+import { ISchema, useForm } from '@formily/react';
+import { uid } from '@formily/shared';
+import React from 'react';
+import { useHistory } from 'react-router-dom';
+import { SchemaComponent, useCurrentDocumentTitle } from '..';
+
+const schema: ISchema = {
+ type: 'object',
+ name: uid(),
+ 'x-component': 'Form',
+ properties: {
+ email: {
+ type: 'string',
+ required: true,
+ 'x-component': 'Input',
+ 'x-validator': 'email',
+ 'x-decorator': 'FormItem',
+ 'x-component-props': { placeholder: '{{t("Email")}}', style: {} },
+ },
+ password: {
+ type: 'string',
+ 'x-component': 'Password',
+ required: true,
+ 'x-decorator': 'FormItem',
+ 'x-component-props': { placeholder: '{{t("Password")}}', style: {} },
+ },
+ actions: {
+ type: 'void',
+ 'x-component': 'div',
+ properties: {
+ submit: {
+ title: '{{t("Sign in")}}',
+ type: 'void',
+ 'x-component': 'Action',
+ 'x-component-props': {
+ block: true,
+ type: 'primary',
+ useAction: '{{ useSignin }}',
+ style: { width: '100%' },
+ },
+ },
+ },
+ },
+ link: {
+ type: 'void',
+ 'x-component': 'div',
+ properties: {
+ link: {
+ title: '{{t("Create an account")}}',
+ type: 'void',
+ 'x-component': 'Link',
+ 'x-content': '{{t("Create an account")}}',
+ 'x-component-props': { to: '/signup' },
+ },
+ },
+ },
+ },
+};
+
+const useSignin = () => {
+ const history = useHistory();
+ const form = useForm();
+ return {
+ async run() {
+ await form.submit();
+ console.log(form.values);
+ history.push('/admin');
+ },
+ };
+};
+
+export const SigninPage = () => {
+ useCurrentDocumentTitle('Signin');
+ return (
+
+
+
+ );
+};
diff --git a/packages/client/src/user/SignupPage.tsx b/packages/client/src/user/SignupPage.tsx
new file mode 100644
index 000000000..68a5188a1
--- /dev/null
+++ b/packages/client/src/user/SignupPage.tsx
@@ -0,0 +1,101 @@
+import { ISchema, useForm } from '@formily/react';
+import { uid } from '@formily/shared';
+import React from 'react';
+import { useHistory } from 'react-router-dom';
+import { SchemaComponent, useCurrentDocumentTitle } from '..';
+
+const schema: ISchema = {
+ type: 'object',
+ name: uid(),
+ 'x-component': 'Form',
+ properties: {
+ email: {
+ type: 'string',
+ required: true,
+ 'x-component': 'Input',
+ 'x-validator': 'email',
+ 'x-decorator': 'FormItem',
+ 'x-component-props': { placeholder: '{{t("Email")}}', style: {} },
+ },
+ password: {
+ type: 'string',
+ required: true,
+ 'x-component': 'Password',
+ 'x-decorator': 'FormItem',
+ 'x-component-props': { placeholder: '{{t("Password")}}', checkStrength: true, style: {} },
+ 'x-reactions': [
+ {
+ dependencies: ['.confirm_password'],
+ fulfill: {
+ state: {
+ selfErrors: '{{$deps[0] && $self.value && $self.value !== $deps[0] ? t("Password mismatch") : ""}}',
+ },
+ },
+ },
+ ],
+ },
+ confirm_password: {
+ type: 'string',
+ required: true,
+ 'x-component': 'Password',
+ 'x-decorator': 'FormItem',
+ 'x-component-props': { placeholder: '{{t("Confirm password")}}', checkStrength: true, style: {} },
+ 'x-reactions': [
+ {
+ dependencies: ['.password'],
+ fulfill: {
+ state: {
+ selfErrors: '{{$deps[0] && $self.value && $self.value !== $deps[0] ? t("Password mismatch") : ""}}',
+ },
+ },
+ },
+ ],
+ },
+ actions: {
+ type: 'void',
+ 'x-component': 'div',
+ properties: {
+ submit: {
+ title: '{{t("Sign up")}}',
+ type: 'void',
+ 'x-component': 'Action',
+ 'x-component-props': {
+ block: true,
+ type: 'primary',
+ useAction: '{{ useSignup }}',
+ style: { width: '100%' },
+ },
+ },
+ },
+ },
+ link: {
+ type: 'void',
+ 'x-component': 'div',
+ properties: {
+ link: {
+ type: 'void',
+ 'x-component': 'Link',
+ 'x-component-props': { to: '/signin' },
+ 'x-content': '{{t("Log in with an existing account")}}',
+ },
+ },
+ },
+ },
+};
+
+const useSignup = () => {
+ const history = useHistory();
+ const form = useForm();
+ return {
+ async run() {
+ await form.submit();
+ console.log(form.values);
+ // history.push('/signin');
+ },
+ };
+};
+
+export const SignupPage = () => {
+ useCurrentDocumentTitle('Signup');
+ return
;
+};
diff --git a/packages/client/src/user/index.md b/packages/client/src/user/index.md
new file mode 100644
index 000000000..09337b9af
--- /dev/null
+++ b/packages/client/src/user/index.md
@@ -0,0 +1,23 @@
+---
+nav:
+ path: /client
+group:
+ title: Client
+ path: /client
+---
+
+# User
+
+`plugin-users` 插件的前端模块
+
+## CurrentUser
+
+当前用户
+
+## SigninPage
+
+登录页
+
+## SignupPage
+
+注册页
diff --git a/packages/client/src/user/index.ts b/packages/client/src/user/index.ts
new file mode 100644
index 000000000..196f02b78
--- /dev/null
+++ b/packages/client/src/user/index.ts
@@ -0,0 +1,4 @@
+export * from './CurrentUser';
+export * from './SigninPage';
+export * from './SignupPage';
+