diff --git a/packages/plugins/@nocobase/plugin-notification-example/.npmignore b/packages/plugins/@nocobase/plugin-notification-example/.npmignore
new file mode 100644
index 0000000000..65f5e8779f
--- /dev/null
+++ b/packages/plugins/@nocobase/plugin-notification-example/.npmignore
@@ -0,0 +1,2 @@
+/node_modules
+/src
diff --git a/packages/plugins/@nocobase/plugin-notification-example/README.md b/packages/plugins/@nocobase/plugin-notification-example/README.md
new file mode 100644
index 0000000000..5083c8fccd
--- /dev/null
+++ b/packages/plugins/@nocobase/plugin-notification-example/README.md
@@ -0,0 +1 @@
+# @nocobase/plugin-notification-example
diff --git a/packages/plugins/@nocobase/plugin-notification-example/client.d.ts b/packages/plugins/@nocobase/plugin-notification-example/client.d.ts
new file mode 100644
index 0000000000..6c459cbac4
--- /dev/null
+++ b/packages/plugins/@nocobase/plugin-notification-example/client.d.ts
@@ -0,0 +1,2 @@
+export * from './dist/client';
+export { default } from './dist/client';
diff --git a/packages/plugins/@nocobase/plugin-notification-example/client.js b/packages/plugins/@nocobase/plugin-notification-example/client.js
new file mode 100644
index 0000000000..b6e3be70e6
--- /dev/null
+++ b/packages/plugins/@nocobase/plugin-notification-example/client.js
@@ -0,0 +1 @@
+module.exports = require('./dist/client/index.js');
diff --git a/packages/plugins/@nocobase/plugin-notification-example/package.json b/packages/plugins/@nocobase/plugin-notification-example/package.json
new file mode 100644
index 0000000000..c83e497d02
--- /dev/null
+++ b/packages/plugins/@nocobase/plugin-notification-example/package.json
@@ -0,0 +1,12 @@
+{
+ "name": "@nocobase/plugin-notification-example",
+ "version": "1.4.0-alpha",
+ "main": "dist/server/index.js",
+ "dependencies": {},
+ "peerDependencies": {
+ "@nocobase/client": "1.x",
+ "@nocobase/server": "1.x",
+ "@nocobase/test": "1.x",
+ "react-i18next": "11.x"
+ }
+}
diff --git a/packages/plugins/@nocobase/plugin-notification-example/server.d.ts b/packages/plugins/@nocobase/plugin-notification-example/server.d.ts
new file mode 100644
index 0000000000..c41081ddc6
--- /dev/null
+++ b/packages/plugins/@nocobase/plugin-notification-example/server.d.ts
@@ -0,0 +1,2 @@
+export * from './dist/server';
+export { default } from './dist/server';
diff --git a/packages/plugins/@nocobase/plugin-notification-example/server.js b/packages/plugins/@nocobase/plugin-notification-example/server.js
new file mode 100644
index 0000000000..972842039a
--- /dev/null
+++ b/packages/plugins/@nocobase/plugin-notification-example/server.js
@@ -0,0 +1 @@
+module.exports = require('./dist/server/index.js');
diff --git a/packages/plugins/@nocobase/plugin-notification-example/src/client/ChannelConfigForm.tsx b/packages/plugins/@nocobase/plugin-notification-example/src/client/ChannelConfigForm.tsx
new file mode 100644
index 0000000000..0d93e53cef
--- /dev/null
+++ b/packages/plugins/@nocobase/plugin-notification-example/src/client/ChannelConfigForm.tsx
@@ -0,0 +1,40 @@
+/**
+ * This file is part of the NocoBase (R) project.
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
+ * Authors: NocoBase Team.
+ *
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
+ * For more information, please refer to: https://www.nocobase.com/agreement.
+ */
+
+import React from 'react';
+import { SchemaComponent } from '@nocobase/client';
+import useLocalTranslation from './useLocalTranslation';
+
+const ChannelConfigForm = () => {
+ const { t } = useLocalTranslation();
+ return (
+
+ );
+};
+
+export default ChannelConfigForm;
diff --git a/packages/plugins/@nocobase/plugin-notification-example/src/client/MessageConfigForm.tsx b/packages/plugins/@nocobase/plugin-notification-example/src/client/MessageConfigForm.tsx
new file mode 100644
index 0000000000..ecc4fa303e
--- /dev/null
+++ b/packages/plugins/@nocobase/plugin-notification-example/src/client/MessageConfigForm.tsx
@@ -0,0 +1,82 @@
+/**
+ * This file is part of the NocoBase (R) project.
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
+ * Authors: NocoBase Team.
+ *
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
+ * For more information, please refer to: https://www.nocobase.com/agreement.
+ */
+
+import React from 'react';
+import { SchemaComponent } from '@nocobase/client';
+import useLocalTranslation from './useLocalTranslation';
+
+const MessageConfigForm = ({ variableOptions }) => {
+ const { t } = useLocalTranslation();
+ return (
+
+ );
+};
+
+export default MessageConfigForm;
diff --git a/packages/plugins/@nocobase/plugin-notification-example/src/client/client.d.ts b/packages/plugins/@nocobase/plugin-notification-example/src/client/client.d.ts
new file mode 100644
index 0000000000..4e96f83fa1
--- /dev/null
+++ b/packages/plugins/@nocobase/plugin-notification-example/src/client/client.d.ts
@@ -0,0 +1,249 @@
+/**
+ * This file is part of the NocoBase (R) project.
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
+ * Authors: NocoBase Team.
+ *
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
+ * For more information, please refer to: https://www.nocobase.com/agreement.
+ */
+
+// CSS modules
+type CSSModuleClasses = { readonly [key: string]: string };
+
+declare module '*.module.css' {
+ const classes: CSSModuleClasses;
+ export default classes;
+}
+declare module '*.module.scss' {
+ const classes: CSSModuleClasses;
+ export default classes;
+}
+declare module '*.module.sass' {
+ const classes: CSSModuleClasses;
+ export default classes;
+}
+declare module '*.module.less' {
+ const classes: CSSModuleClasses;
+ export default classes;
+}
+declare module '*.module.styl' {
+ const classes: CSSModuleClasses;
+ export default classes;
+}
+declare module '*.module.stylus' {
+ const classes: CSSModuleClasses;
+ export default classes;
+}
+declare module '*.module.pcss' {
+ const classes: CSSModuleClasses;
+ export default classes;
+}
+declare module '*.module.sss' {
+ const classes: CSSModuleClasses;
+ export default classes;
+}
+
+// CSS
+declare module '*.css' { }
+declare module '*.scss' { }
+declare module '*.sass' { }
+declare module '*.less' { }
+declare module '*.styl' { }
+declare module '*.stylus' { }
+declare module '*.pcss' { }
+declare module '*.sss' { }
+
+// Built-in asset types
+// see `src/node/constants.ts`
+
+// images
+declare module '*.apng' {
+ const src: string;
+ export default src;
+}
+declare module '*.png' {
+ const src: string;
+ export default src;
+}
+declare module '*.jpg' {
+ const src: string;
+ export default src;
+}
+declare module '*.jpeg' {
+ const src: string;
+ export default src;
+}
+declare module '*.jfif' {
+ const src: string;
+ export default src;
+}
+declare module '*.pjpeg' {
+ const src: string;
+ export default src;
+}
+declare module '*.pjp' {
+ const src: string;
+ export default src;
+}
+declare module '*.gif' {
+ const src: string;
+ export default src;
+}
+declare module '*.svg' {
+ const src: string;
+ export default src;
+}
+declare module '*.ico' {
+ const src: string;
+ export default src;
+}
+declare module '*.webp' {
+ const src: string;
+ export default src;
+}
+declare module '*.avif' {
+ const src: string;
+ export default src;
+}
+
+// media
+declare module '*.mp4' {
+ const src: string;
+ export default src;
+}
+declare module '*.webm' {
+ const src: string;
+ export default src;
+}
+declare module '*.ogg' {
+ const src: string;
+ export default src;
+}
+declare module '*.mp3' {
+ const src: string;
+ export default src;
+}
+declare module '*.wav' {
+ const src: string;
+ export default src;
+}
+declare module '*.flac' {
+ const src: string;
+ export default src;
+}
+declare module '*.aac' {
+ const src: string;
+ export default src;
+}
+declare module '*.opus' {
+ const src: string;
+ export default src;
+}
+declare module '*.mov' {
+ const src: string;
+ export default src;
+}
+declare module '*.m4a' {
+ const src: string;
+ export default src;
+}
+declare module '*.vtt' {
+ const src: string;
+ export default src;
+}
+
+// fonts
+declare module '*.woff' {
+ const src: string;
+ export default src;
+}
+declare module '*.woff2' {
+ const src: string;
+ export default src;
+}
+declare module '*.eot' {
+ const src: string;
+ export default src;
+}
+declare module '*.ttf' {
+ const src: string;
+ export default src;
+}
+declare module '*.otf' {
+ const src: string;
+ export default src;
+}
+
+// other
+declare module '*.webmanifest' {
+ const src: string;
+ export default src;
+}
+declare module '*.pdf' {
+ const src: string;
+ export default src;
+}
+declare module '*.txt' {
+ const src: string;
+ export default src;
+}
+
+// wasm?init
+declare module '*.wasm?init' {
+ const initWasm: (options?: WebAssembly.Imports) => Promise;
+ export default initWasm;
+}
+
+// web worker
+declare module '*?worker' {
+ const workerConstructor: {
+ new(options?: { name?: string }): Worker;
+ };
+ export default workerConstructor;
+}
+
+declare module '*?worker&inline' {
+ const workerConstructor: {
+ new(options?: { name?: string }): Worker;
+ };
+ export default workerConstructor;
+}
+
+declare module '*?worker&url' {
+ const src: string;
+ export default src;
+}
+
+declare module '*?sharedworker' {
+ const sharedWorkerConstructor: {
+ new(options?: { name?: string }): SharedWorker;
+ };
+ export default sharedWorkerConstructor;
+}
+
+declare module '*?sharedworker&inline' {
+ const sharedWorkerConstructor: {
+ new(options?: { name?: string }): SharedWorker;
+ };
+ export default sharedWorkerConstructor;
+}
+
+declare module '*?sharedworker&url' {
+ const src: string;
+ export default src;
+}
+
+declare module '*?raw' {
+ const src: string;
+ export default src;
+}
+
+declare module '*?url' {
+ const src: string;
+ export default src;
+}
+
+declare module '*?inline' {
+ const src: string;
+ export default src;
+}
diff --git a/packages/plugins/@nocobase/plugin-notification-example/src/client/index.tsx b/packages/plugins/@nocobase/plugin-notification-example/src/client/index.tsx
new file mode 100644
index 0000000000..250dba80aa
--- /dev/null
+++ b/packages/plugins/@nocobase/plugin-notification-example/src/client/index.tsx
@@ -0,0 +1,34 @@
+/**
+ * This file is part of the NocoBase (R) project.
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
+ * Authors: NocoBase Team.
+ *
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
+ * For more information, please refer to: https://www.nocobase.com/agreement.
+ */
+
+import { Plugin } from '@nocobase/client';
+import PluginNotificationManagerClient from '@nocobase/plugin-notification-manager/client';
+import { tval } from '@nocobase/utils/client';
+import ChannelConfigForm from './ChannelConfigForm';
+import MessageConfigForm from './MessageConfigForm';
+
+export class PluginNotificationExampleClient extends Plugin {
+ async afterAdd() {}
+
+ async beforeLoad() {}
+
+ async load() {
+ const notification = this.pm.get(PluginNotificationManagerClient);
+ notification.registerChannelType({
+ title: tval('Example SMS', { ns: '@nocobase/plugin-notification-example' }),
+ type: 'example-sms',
+ components: {
+ ChannelConfigForm,
+ MessageConfigForm,
+ },
+ });
+ }
+}
+
+export default PluginNotificationExampleClient;
diff --git a/packages/plugins/@nocobase/plugin-notification-example/src/client/locale.ts b/packages/plugins/@nocobase/plugin-notification-example/src/client/locale.ts
new file mode 100644
index 0000000000..84797b7d1b
--- /dev/null
+++ b/packages/plugins/@nocobase/plugin-notification-example/src/client/locale.ts
@@ -0,0 +1,21 @@
+/**
+ * This file is part of the NocoBase (R) project.
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
+ * Authors: NocoBase Team.
+ *
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
+ * For more information, please refer to: https://www.nocobase.com/agreement.
+ */
+
+// @ts-ignore
+import pkg from './../../package.json';
+import { useApp } from '@nocobase/client';
+
+export function useT() {
+ const app = useApp();
+ return (str: string) => app.i18n.t(str, { ns: [pkg.name, 'client'] });
+}
+
+export function tStr(key: string) {
+ return `{{t(${JSON.stringify(key)}, { ns: ['${pkg.name}', 'client'], nsMode: 'fallback' })}}`;
+}
diff --git a/packages/plugins/@nocobase/plugin-notification-example/src/client/useLocalTranslation.ts b/packages/plugins/@nocobase/plugin-notification-example/src/client/useLocalTranslation.ts
new file mode 100644
index 0000000000..2ebaa3c961
--- /dev/null
+++ b/packages/plugins/@nocobase/plugin-notification-example/src/client/useLocalTranslation.ts
@@ -0,0 +1,15 @@
+/**
+ * This file is part of the NocoBase (R) project.
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
+ * Authors: NocoBase Team.
+ *
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
+ * For more information, please refer to: https://www.nocobase.com/agreement.
+ */
+
+import { useTranslation } from 'react-i18next';
+export default function useLocalTranslation() {
+ return useTranslation(['@nocobase/plugin-notification-example', 'client'], {
+ nsMode: 'fallback',
+ });
+}
diff --git a/packages/plugins/@nocobase/plugin-notification-example/src/index.ts b/packages/plugins/@nocobase/plugin-notification-example/src/index.ts
new file mode 100644
index 0000000000..be99a2ff1a
--- /dev/null
+++ b/packages/plugins/@nocobase/plugin-notification-example/src/index.ts
@@ -0,0 +1,11 @@
+/**
+ * This file is part of the NocoBase (R) project.
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
+ * Authors: NocoBase Team.
+ *
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
+ * For more information, please refer to: https://www.nocobase.com/agreement.
+ */
+
+export * from './server';
+export { default } from './server';
diff --git a/packages/plugins/@nocobase/plugin-notification-example/src/locale/en-US.json b/packages/plugins/@nocobase/plugin-notification-example/src/locale/en-US.json
new file mode 100644
index 0000000000..0967ef424b
--- /dev/null
+++ b/packages/plugins/@nocobase/plugin-notification-example/src/locale/en-US.json
@@ -0,0 +1 @@
+{}
diff --git a/packages/plugins/@nocobase/plugin-notification-example/src/locale/zh-CN.json b/packages/plugins/@nocobase/plugin-notification-example/src/locale/zh-CN.json
new file mode 100644
index 0000000000..0967ef424b
--- /dev/null
+++ b/packages/plugins/@nocobase/plugin-notification-example/src/locale/zh-CN.json
@@ -0,0 +1 @@
+{}
diff --git a/packages/plugins/@nocobase/plugin-notification-example/src/server/collections/.gitkeep b/packages/plugins/@nocobase/plugin-notification-example/src/server/collections/.gitkeep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/packages/plugins/@nocobase/plugin-notification-example/src/server/example-server.ts b/packages/plugins/@nocobase/plugin-notification-example/src/server/example-server.ts
new file mode 100644
index 0000000000..6714fa141e
--- /dev/null
+++ b/packages/plugins/@nocobase/plugin-notification-example/src/server/example-server.ts
@@ -0,0 +1,17 @@
+/**
+ * This file is part of the NocoBase (R) project.
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
+ * Authors: NocoBase Team.
+ *
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
+ * For more information, please refer to: https://www.nocobase.com/agreement.
+ */
+
+import { BaseNotificationChannel } from '@nocobase/plugin-notification-manager';
+
+export class ExampleSever extends BaseNotificationChannel {
+ async send(args): Promise {
+ console.log('ExampleSever send', args);
+ return { status: 'success', message: args.message };
+ }
+}
diff --git a/packages/plugins/@nocobase/plugin-notification-example/src/server/index.ts b/packages/plugins/@nocobase/plugin-notification-example/src/server/index.ts
new file mode 100644
index 0000000000..be989de7c3
--- /dev/null
+++ b/packages/plugins/@nocobase/plugin-notification-example/src/server/index.ts
@@ -0,0 +1,10 @@
+/**
+ * This file is part of the NocoBase (R) project.
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
+ * Authors: NocoBase Team.
+ *
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
+ * For more information, please refer to: https://www.nocobase.com/agreement.
+ */
+
+export { default } from './plugin';
diff --git a/packages/plugins/@nocobase/plugin-notification-example/src/server/plugin.ts b/packages/plugins/@nocobase/plugin-notification-example/src/server/plugin.ts
new file mode 100644
index 0000000000..4130d24987
--- /dev/null
+++ b/packages/plugins/@nocobase/plugin-notification-example/src/server/plugin.ts
@@ -0,0 +1,20 @@
+/**
+ * This file is part of the NocoBase (R) project.
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
+ * Authors: NocoBase Team.
+ *
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
+ * For more information, please refer to: https://www.nocobase.com/agreement.
+ */
+
+import PluginNotificationManagerServer from '@nocobase/plugin-notification-manager';
+import { Plugin } from '@nocobase/server';
+import { ExampleSever } from './example-server';
+export class PluginNotificationExampleServer extends Plugin {
+ async load() {
+ const notificationServer = this.pm.get(PluginNotificationManagerServer) as PluginNotificationManagerServer;
+ notificationServer.registerChannelType({ type: 'example-sms', Channel: ExampleSever });
+ }
+}
+
+export default PluginNotificationExampleServer;