feat: add websocket block

This commit is contained in:
sealday 2024-03-29 17:09:07 +08:00
parent 1eda5609b7
commit 5d6a6e6450
14 changed files with 227 additions and 1 deletions

View File

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

View File

@ -0,0 +1 @@
# @hera/plugin-websocket

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,18 @@
{
"name": "@hera/plugin-websocket",
"version": "0.0.1",
"main": "dist/server/index.js",
"dependencies": {},
"devDependencies": {
"react-use-websocket": "^4.8.1",
"@formily/antd-v5": "1.x",
"@formily/core": "^2.2.27",
"@formily/react": "^2.2.27",
"@formily/shared": "^2.2.27"
},
"peerDependencies": {
"@nocobase/client": "0.x",
"@nocobase/server": "0.x",
"@nocobase/test": "0.x"
}
}

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,14 @@
import { Plugin } from '@nocobase/client';
import { WebsocketBlockHelper } from './schema-initializer/WebsocketBlockInitializer';
export class PluginWebsocketClient extends Plugin {
async afterAdd() {}
async beforeLoad() {}
async load() {
await new WebsocketBlockHelper(this.app).load();
}
}
export default PluginWebsocketClient;

View File

@ -0,0 +1,143 @@
import React, { useCallback, useEffect, useState } from 'react';
import { PrinterOutlined } from '@ant-design/icons';
import {
Application,
SchemaInitializer,
SchemaInitializerItem,
SchemaSettings,
SchemaToolbar,
useSchemaInitializer,
useSchemaInitializerItem,
} from '@nocobase/client';
import useWebSocket, { ReadyState } from 'react-use-websocket';
import { useFieldSchema } from '@formily/react';
export class WebsocketBlockHelper {
constructor(private app: Application) {}
async load() {
this.app.schemaInitializerManager.addItem('page:addBlock', 'dataBlocks.groupBlock', {
title: 'Websocket',
Component: 'WebsocketBlockInitializer',
});
this.app.schemaSettingsManager.add(websocketBlockSettings);
this.app.schemaInitializerManager.add(WebsocketActionInitializer);
this.app.addComponents({
WebsocketBlockInitializer,
WebsocketBlockToolbar,
WebsocketBlock,
});
const WebsocketBlockItem = {
title: 'Websocket',
name: 'websocketBlock',
Component: 'WebsocketBlockInitializer',
type: 'item',
};
this.app.schemaInitializerManager.get('popup:common:addBlock').add(WebsocketBlockItem.name, WebsocketBlockItem);
}
}
const WebsocketBlock: React.FC = () => {
//Public API that will echo messages sent to it back to the client
const [socketUrl, setSocketUrl] = useState('wss://echo.websocket.org');
const [messageHistory, setMessageHistory] = useState<MessageEvent<any>[]>([]);
const { sendMessage, lastMessage, readyState } = useWebSocket(socketUrl);
useEffect(() => {
if (lastMessage !== null) {
setMessageHistory((prev) => prev.concat(lastMessage));
}
}, [lastMessage]);
const handleClickChangeSocketUrl = useCallback(() => setSocketUrl('wss://demos.kaazing.com/echo'), []);
const handleClickSendMessage = useCallback(() => sendMessage('Hello'), []);
const connectionStatus = {
[ReadyState.CONNECTING]: 'Connecting',
[ReadyState.OPEN]: 'Open',
[ReadyState.CLOSING]: 'Closing',
[ReadyState.CLOSED]: 'Closed',
[ReadyState.UNINSTANTIATED]: 'Uninstantiated',
}[readyState];
return (
<div>
<button onClick={handleClickChangeSocketUrl}>Click Me to change Socket Url</button>
<button onClick={handleClickSendMessage} disabled={readyState !== ReadyState.OPEN}>
Click Me to send Hello
</button>
<span>The WebSocket is currently {connectionStatus}</span>
{lastMessage ? <span>Last message: {lastMessage.data}</span> : null}
<ul>
{messageHistory.map((message, idx) => (
<span key={idx}>{message ? message.data : null}</span>
))}
</ul>
</div>
);
};
const WebsocketActionInitializer = new SchemaInitializer({
name: 'WebsocketActionInitializer',
title: 'Configure actions',
icon: 'SettingOutlined',
style: {
marginLeft: 8,
},
items: [
{
name: 'enbaleActions',
type: 'itemGroup',
title: 'Enable actions',
children: [],
},
],
});
const WebsocketBlockInitializer = () => {
const { insert } = useSchemaInitializer();
const itemConfig = useSchemaInitializerItem();
return (
<SchemaInitializerItem
{...itemConfig}
icon={<PrinterOutlined />}
onClick={() => {
insert({
type: 'void',
'x-toolbar': 'WebsocketBlockToolbar',
'x-settings': 'websocketBlockSettings',
'x-component': 'CardItem',
properties: {
actions: {
type: 'void',
'x-initializer': 'WebsocketActionInitializer',
'x-component': 'ActionBar',
'x-component-props': {},
properties: {},
},
viewer: {
type: 'void',
'x-component': 'WebsocketBlock',
},
},
});
}}
/>
);
};
export const websocketBlockSettings = new SchemaSettings({
name: 'websocketBlockSettings',
items: [
{
name: 'remove',
type: 'remove',
},
],
});
export const WebsocketBlockToolbar = (props) => {
const fieldSchema = useFieldSchema();
return <SchemaToolbar title={fieldSchema.title} settings={fieldSchema['x-settings']} {...props} />;
};

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 '@nocobase/server';
export class PluginWebsocketServer extends Plugin {
async afterAdd() {}
async beforeLoad() {}
async load() {}
async install() {}
async afterEnable() {}
async afterDisable() {}
async remove() {}
}
export default PluginWebsocketServer;

View File

@ -18023,7 +18023,22 @@ matchdep@^2.0.0:
resolve "^1.4.0" resolve "^1.4.0"
stack-trace "0.0.10" stack-trace "0.0.10"
"mathjs2@npm:mathjs@^10.6.0", mathjs@^10.6.0, mathjs@^10.6.1: "mathjs2@npm:mathjs@^10.6.0":
version "10.6.4"
resolved "https://registry.npmmirror.com/mathjs/-/mathjs-10.6.4.tgz#1b87a1268781d64f0c8b4e5e1b36cf7ecf58bb05"
integrity sha512-omQyvRE1jIy+3k2qsqkWASOcd45aZguXZDckr3HtnTYyXk5+2xpVfC3kATgbO2Srjxlqww3TVdhD0oUdZ/hiFA==
dependencies:
"@babel/runtime" "^7.18.6"
complex.js "^2.1.1"
decimal.js "^10.3.1"
escape-latex "^1.2.0"
fraction.js "^4.2.0"
javascript-natural-sort "^0.7.1"
seedrandom "^3.0.5"
tiny-emitter "^2.1.0"
typed-function "^2.1.0"
mathjs@^10.6.0, mathjs@^10.6.1:
version "10.6.4" version "10.6.4"
resolved "https://registry.npmmirror.com/mathjs/-/mathjs-10.6.4.tgz#1b87a1268781d64f0c8b4e5e1b36cf7ecf58bb05" resolved "https://registry.npmmirror.com/mathjs/-/mathjs-10.6.4.tgz#1b87a1268781d64f0c8b4e5e1b36cf7ecf58bb05"
integrity sha512-omQyvRE1jIy+3k2qsqkWASOcd45aZguXZDckr3HtnTYyXk5+2xpVfC3kATgbO2Srjxlqww3TVdhD0oUdZ/hiFA== integrity sha512-omQyvRE1jIy+3k2qsqkWASOcd45aZguXZDckr3HtnTYyXk5+2xpVfC3kATgbO2Srjxlqww3TVdhD0oUdZ/hiFA==
@ -22633,6 +22648,11 @@ react-to-print@^2.14.7:
resolved "https://registry.npmmirror.com/react-to-print/-/react-to-print-2.14.15.tgz#edb4ce8a92205cf37fd8c3d57de829034aa5c911" resolved "https://registry.npmmirror.com/react-to-print/-/react-to-print-2.14.15.tgz#edb4ce8a92205cf37fd8c3d57de829034aa5c911"
integrity sha512-SKnwOzU2cJ8eaAkoJO7+gNhvfEDmm+Y34IdcHsjtHioUevUPhprqbVtvNJlZ2JkGJ8ExK2QNWM9pXECTDR5D8w== integrity sha512-SKnwOzU2cJ8eaAkoJO7+gNhvfEDmm+Y34IdcHsjtHioUevUPhprqbVtvNJlZ2JkGJ8ExK2QNWM9pXECTDR5D8w==
react-use-websocket@^4.8.1:
version "4.8.1"
resolved "https://registry.npmmirror.com/react-use-websocket/-/react-use-websocket-4.8.1.tgz#be06a0bc956c6d56391a29cbe2caa6ae8edb5615"
integrity sha512-FTXuG5O+LFozmu1BRfrzl7UIQngECvGJmL7BHsK4TYXuVt+mCizVA8lT0hGSIF0Z0TedF7bOo1nRzOUdginhDw==
react@18.*, react@18.1.0, react@18.x, react@^18.0.0, react@^18.2.0: react@18.*, react@18.1.0, react@18.x, react@^18.0.0, react@^18.2.0:
version "18.2.0" version "18.2.0"
resolved "https://registry.npmmirror.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5" resolved "https://registry.npmmirror.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5"