feat: web notification (#1573)

Co-authored-by: sealday <sealday@gmail.com>
Reviewed-on: daoyoucloud/tachybase#1573
This commit is contained in:
sealday 2024-09-27 05:12:12 +08:00
parent 2425e43621
commit 4b5d09a3cf
23 changed files with 147 additions and 45 deletions

View File

@ -1,17 +0,0 @@
import { Plugin } from '../../application/Plugin';
export class PluginWebNotification extends Plugin {
async afterLoad() {
// ‌请求用户授予权限
if (Notification.permission !== 'denied') {
await Notification.requestPermission();
}
setTimeout(() => {
const notification = new Notification('通知标题:', {
body: '通知内容',
icon: 'https://www.example.com/icon.png', // 通知的图标 URL
});
}, 2000);
}
}

View File

@ -8,5 +8,4 @@ export * from './custom-components/CustomField';
export * from './fields/AssociatedField'; export * from './fields/AssociatedField';
export * from './fields/CalcResult'; export * from './fields/CalcResult';
export * from './fields/Expression'; export * from './fields/Expression';
export * from './system/OnlineUserProvider';
export * from './excel-table/ExcelFile'; export * from './excel-table/ExcelFile';

View File

@ -1,5 +1,5 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { css, useAPIClient, useApp } from '@tachybase/client'; import { PinnedPluginListProvider, SchemaComponentOptions, useAPIClient, useApp, useToken } from '@tachybase/client';
import { uid } from '@tachybase/schema'; import { uid } from '@tachybase/schema';
import { Button, Dropdown } from 'antd'; import { Button, Dropdown } from 'antd';
@ -9,6 +9,7 @@ const OnlineUserManger = () => {
const app = useApp(); const app = useApp();
const [onlineUserItems, setOnlineUserItems] = useState([]); const [onlineUserItems, setOnlineUserItems] = useState([]);
const api = useAPIClient(); const api = useAPIClient();
const { token } = useToken();
useEffect(() => { useEffect(() => {
app.ws.on('message', (event: MessageEvent) => { app.ws.on('message', (event: MessageEvent) => {
const data = JSON.parse(event.data); const data = JSON.parse(event.data);
@ -38,32 +39,21 @@ const OnlineUserManger = () => {
return ( return (
<Dropdown menu={{ items: onlineUserItems }}> <Dropdown menu={{ items: onlineUserItems }}>
<Button style={{ width: 'auto' }} type="text"> <Button style={{ width: 'auto', color: token.colorTextHeaderMenu }} type="text">
线 {_.size(onlineUserItems)} 线 {_.size(onlineUserItems)}
</Button> </Button>
</Dropdown> </Dropdown>
); );
}; };
export const OnlineUserDropdown = () => { export const OnlineUserProvider = (props) => {
return ( return (
<div <PinnedPluginListProvider
className={css` items={{
.ant-btn { ou: { order: 230, component: 'OnlineUserManger', pin: true, isPublic: true },
border: 0; }}
height: var(--tb-header-height);
width: 46px;
border-radius: 0;
background: none;
color: rgba(255, 255, 255, 0.65) !important;
&:hover {
background: rgba(255, 255, 255, 0.1);
}
}
`}
style={{ display: 'inline-block' }}
> >
<OnlineUserManger /> <SchemaComponentOptions components={{ OnlineUserManger }}>{props.children}</SchemaComponentOptions>
</div> </PinnedPluginListProvider>
); );
}; };

View File

@ -0,0 +1,9 @@
import { Plugin } from '@tachybase/client';
import { OnlineUserProvider } from './OnlineUserProvider';
export class PluginOnlineUsers extends Plugin {
async load() {
this.app.use(OnlineUserProvider);
}
}

View File

@ -20,6 +20,7 @@ import { DepartmentsPlugin } from './features/departments';
import { EmbedPlugin } from './features/embed'; import { EmbedPlugin } from './features/embed';
import { PluginFieldAppends } from './features/field-appends'; import { PluginFieldAppends } from './features/field-appends';
import { PluginHeraVersion } from './features/hera-version'; import { PluginHeraVersion } from './features/hera-version';
import { PluginOnlineUsers } from './features/online-users';
import { PluginOutbound } from './features/outbound'; import { PluginOutbound } from './features/outbound';
import { PluginPDF } from './features/pdf'; import { PluginPDF } from './features/pdf';
import { PluginSheet } from './features/sheet'; import { PluginSheet } from './features/sheet';
@ -62,6 +63,7 @@ export class PluginCoreClient extends Plugin {
await this.app.pm.add(PluginPDF); await this.app.pm.add(PluginPDF);
await this.app.pm.add(PluginOutbound); await this.app.pm.add(PluginOutbound);
// await this.app.pm.add(PluginModeHighlight); // await this.app.pm.add(PluginModeHighlight);
await this.app.pm.add(PluginOnlineUsers);
await this.app.pm.add(PluginFieldAppends); await this.app.pm.add(PluginFieldAppends);
await this.app.pm.add(PluginCustomComponents); await this.app.pm.add(PluginCustomComponents);
await this.app.pm.add(PluginSheet); await this.app.pm.add(PluginSheet);

View File

@ -10,6 +10,7 @@ import { MessageNotificationProvider } from './MessageNotificationProvider';
import { MessagePage } from './MessagePage'; import { MessagePage } from './MessagePage';
import { MessageProvider } from './MessageProvider'; import { MessageProvider } from './MessageProvider';
import { SubscriptionManager } from './SubscriptionManager'; import { SubscriptionManager } from './SubscriptionManager';
import { PluginWebNotification } from './web-notification/PluginWebNotification';
interface MessageType { interface MessageType {
title: string; title: string;
@ -20,7 +21,7 @@ export class PluginMessagesClient extends Plugin {
private _messageTypes: MessageType[] = []; private _messageTypes: MessageType[] = [];
async afterAdd() { async afterAdd() {
// await this.app.pm.add() await this.app.pm.add(PluginWebNotification, { name: 'message-web' });
} }
async beforeLoad() {} async beforeLoad() {}
@ -71,11 +72,6 @@ export class PluginMessagesClient extends Plugin {
Component: SubscriptionManager, Component: SubscriptionManager,
}); });
this.registe({
name: 'browser',
title: lang('Browser notification'),
});
this.registe({ this.registe({
name: 'sms', name: 'sms',
title: lang('SMS notification'), title: lang('SMS notification'),

View File

@ -0,0 +1,30 @@
import { Plugin } from '@tachybase/client';
import PluginMessagesClient from '..';
import { lang } from '../locale';
export class PluginWebNotification extends Plugin {
async afterLoad() {
// ‌请求用户授予权限
if (Notification.permission !== 'denied') {
await Notification.requestPermission();
}
}
async load() {
this.pm.get(PluginMessagesClient).registe({
name: 'browser',
title: lang('Browser notification'),
});
this.app.ws.on('message', (event: MessageEvent) => {
const data = JSON.parse(event.data);
if (data?.type === 'messages') {
const message = data.payload.message;
const notification = new Notification(message.title, {
body: message.content,
});
}
});
}
}

View File

@ -1,5 +1,6 @@
import { Model } from '@tachybase/database';
import { PluginWorkflow } from '@tachybase/plugin-workflow'; import { PluginWorkflow } from '@tachybase/plugin-workflow';
import { Plugin } from '@tachybase/server'; import { Gateway, Plugin } from '@tachybase/server';
import { MessageInstruction } from './instructions/message-instruction'; import { MessageInstruction } from './instructions/message-instruction';
@ -9,8 +10,20 @@ export class PluginMessagesServer extends Plugin {
async beforeLoad() {} async beforeLoad() {}
async load() { async load() {
const appName = this.app.name;
const workflowPlugin = this.app.getPlugin<PluginWorkflow>(PluginWorkflow); const workflowPlugin = this.app.getPlugin<PluginWorkflow>(PluginWorkflow);
workflowPlugin.registerInstruction('message-instruction', MessageInstruction); workflowPlugin.registerInstruction('message-instruction', MessageInstruction);
this.db.on('messages.afterCreate', async (message: Model, options) => {
const gateway = Gateway.getInstance();
const ws = gateway['wsServer'];
ws.sendToConnectionsByTag('app', appName, {
type: 'messages',
payload: {
message: message.toJSON(),
},
});
});
} }
async install() {} async install() {}

View File

@ -0,0 +1,2 @@
/node_modules
/src

View File

@ -0,0 +1 @@
# @tachybase/plugin-online-user

View File

@ -0,0 +1,2 @@
export * from './dist/client';
export { default } from './dist/client';

View File

@ -0,0 +1 @@
module.exports = require('./dist/client/index.js');

View File

@ -0,0 +1,11 @@
{
"name": "@tachybase/plugin-online-user",
"version": "0.22.4",
"main": "dist/server/index.js",
"dependencies": {},
"peerDependencies": {
"@tachybase/client": "workspace:*",
"@tachybase/server": "workspace:*",
"@tachybase/test": "workspace:*"
}
}

View File

@ -0,0 +1,2 @@
export * from './dist/server';
export { default } from './dist/server';

View File

@ -0,0 +1 @@
module.exports = require('./dist/server/index.js');

View File

@ -0,0 +1,21 @@
import { Plugin } from '@tachybase/client';
export class PluginOnlineUserClient extends Plugin {
async afterAdd() {
// await this.app.pm.add()
}
async beforeLoad() {}
// You can get and modify the app instance here
async load() {
console.log(this.app);
// this.app.addComponents({})
// this.app.addScopes({})
// this.app.addProvider()
// this.app.addProviders()
// this.app.router.add()
}
}
export default PluginOnlineUserClient;

View File

@ -0,0 +1,2 @@
export * from './server';
export { default } from './server';

View File

@ -0,0 +1 @@
export { default } from './plugin';

View File

@ -0,0 +1,19 @@
import { Plugin } from '@tachybase/server';
export class PluginOnlineUserServer extends Plugin {
async afterAdd() {}
async beforeLoad() {}
async load() {}
async install() {}
async afterEnable() {}
async afterDisable() {}
async remove() {}
}
export default PluginOnlineUserServer;

View File

@ -43,6 +43,7 @@
"@tachybase/plugin-multi-app-manager": "workspace:*", "@tachybase/plugin-multi-app-manager": "workspace:*",
"@tachybase/plugin-multi-app-share-collection": "workspace:*", "@tachybase/plugin-multi-app-share-collection": "workspace:*",
"@tachybase/plugin-oidc": "workspace:*", "@tachybase/plugin-oidc": "workspace:*",
"@tachybase/plugin-online-user": "workspace:*",
"@tachybase/plugin-saml": "workspace:*", "@tachybase/plugin-saml": "workspace:*",
"@tachybase/plugin-sequence-field": "workspace:*", "@tachybase/plugin-sequence-field": "workspace:*",
"@tachybase/plugin-sms-auth": "workspace:*", "@tachybase/plugin-sms-auth": "workspace:*",

View File

@ -18,6 +18,7 @@ export class PresetTachyBase extends Plugin {
'acl', 'acl',
'messages', 'messages',
// optional plugins, default enabled // optional plugins, default enabled
'online-user',
'action-bulk-edit', 'action-bulk-edit',
'action-bulk-update', 'action-bulk-update',
'action-duplicate', 'action-duplicate',

View File

@ -3656,6 +3656,18 @@ importers:
specifier: ^6.25.1 specifier: ^6.25.1
version: 6.25.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) version: 6.25.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
packages/plugins/@tachybase/plugin-online-user:
dependencies:
'@tachybase/client':
specifier: workspace:*
version: link:../../../core/client
'@tachybase/server':
specifier: workspace:*
version: link:../../../core/server
'@tachybase/test':
specifier: workspace:*
version: link:../../../core/test
packages/plugins/@tachybase/plugin-print-template: packages/plugins/@tachybase/plugin-print-template:
dependencies: dependencies:
'@bull-board/api': '@bull-board/api':
@ -4512,6 +4524,9 @@ importers:
'@tachybase/plugin-oidc': '@tachybase/plugin-oidc':
specifier: workspace:* specifier: workspace:*
version: link:../../plugins/@tachybase/plugin-oidc version: link:../../plugins/@tachybase/plugin-oidc
'@tachybase/plugin-online-user':
specifier: workspace:*
version: link:../../plugins/@tachybase/plugin-online-user
'@tachybase/plugin-saml': '@tachybase/plugin-saml':
specifier: workspace:* specifier: workspace:*
version: link:../../plugins/@tachybase/plugin-saml version: link:../../plugins/@tachybase/plugin-saml