From 8fdd2ffda4ba3b1478f4caf3ad4dac41bfcac672 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Thu, 18 Feb 2021 22:57:12 -0300 Subject: [PATCH] Added types to Emitters --- client/contexts/AuthorizationContext.ts | 8 ++-- client/lib/banners.ts | 5 ++- client/lib/createValueSubscription.ts | 4 +- client/lib/presence.ts | 42 +++++++++++++------ client/views/room/contexts/RoomContext.ts | 1 - .../views/room/lib/Toolbox/ToolboxContext.tsx | 8 ++-- client/views/room/lib/Toolbox/generator.tsx | 18 ++++---- client/views/room/lib/Toolbox/index.tsx | 4 +- .../views/room/providers/ToolboxProvider.tsx | 5 +-- package-lock.json | 37 +++++++++------- package.json | 8 ++-- 11 files changed, 88 insertions(+), 52 deletions(-) diff --git a/client/contexts/AuthorizationContext.ts b/client/contexts/AuthorizationContext.ts index 8429a08d7ef40..7abb4e44e44cb 100644 --- a/client/contexts/AuthorizationContext.ts +++ b/client/contexts/AuthorizationContext.ts @@ -1,13 +1,15 @@ import { createContext, useContext, useMemo, useCallback } from 'react'; import { useSubscription, Subscription, Unsubscribe } from 'use-subscription'; -import { Emitter, Handler } from '@rocket.chat/emitter'; +import { Emitter } from '@rocket.chat/emitter'; import { IRole } from '../../definition/IUser'; type IRoles = { [_id: string]: IRole } -export class RoleStore extends Emitter { +export class RoleStore extends Emitter<{ + change: IRoles; +}> { roles: IRoles = {}; } @@ -91,7 +93,7 @@ export const useRolesDescription = (): (ids: Array) => [string] => { const subscription = useMemo( () => ({ getCurrentValue: (): IRoles => roleStore.roles, - subscribe: (callback: Handler): () => void => { + subscribe: (callback: () => void): () => void => { roleStore.on('change', callback); return (): void => { roleStore.off('change', callback); diff --git a/client/lib/banners.ts b/client/lib/banners.ts index 7595658025f45..0afb3449f7cff 100644 --- a/client/lib/banners.ts +++ b/client/lib/banners.ts @@ -21,7 +21,10 @@ type BannerPayload = LegacyBannerPayload | UiKitBannerPayload; export const isLegacyPayload = (payload: BannerPayload): payload is LegacyBannerPayload => !('blocks' in payload); const queue: BannerPayload[] = []; -const emitter = new Emitter(); +const emitter = new Emitter<{ + update: undefined; + 'update-first': undefined; +}>(); export const firstSubscription: Subscription = { getCurrentValue: () => queue[0] ?? null, diff --git a/client/lib/createValueSubscription.ts b/client/lib/createValueSubscription.ts index b415b7f7c787f..9702f748e93a9 100644 --- a/client/lib/createValueSubscription.ts +++ b/client/lib/createValueSubscription.ts @@ -7,7 +7,9 @@ type ValueSubscription = Subscription & { export const createValueSubscription = (initialValue: T): ValueSubscription => { let value: T = initialValue; - const emitter = new Emitter(); + const emitter = new Emitter<{ + update: undefined; + }>(); return { getCurrentValue: (): T => value, diff --git a/client/lib/presence.ts b/client/lib/presence.ts index aedad7b8be75b..ec48f3f79b2a9 100644 --- a/client/lib/presence.ts +++ b/client/lib/presence.ts @@ -1,9 +1,22 @@ -import { Emitter, EventType, Handler } from '@rocket.chat/emitter'; +import { Emitter, EventHandlerOf } from '@rocket.chat/emitter'; import { APIClient } from '../../app/utils/client'; import { IUser } from '../../definition/IUser'; +import { USER_STATUS } from '../../definition/UserStatus'; -const emitter = new Emitter(); +type InternalEvents = { + remove: IUser['_id']; + reset: undefined; + restart: undefined; +}; + +type ExternalEvents = { + [key: string]: UserPresence | undefined; +}; + +type Events = InternalEvents & ExternalEvents; + +const emitter = new Emitter(); const store = new Map(); @@ -14,7 +27,7 @@ type UsersPresencePayload = { full: boolean; }; -const isUid = (eventType: EventType): eventType is UserPresence['_id'] => +const isUid = (eventType: keyof Events): eventType is UserPresence['_id'] => Boolean(eventType) && typeof eventType === 'string' && !['reset', 'restart', 'remove'].includes(eventType); const uids = new Set(); @@ -41,7 +54,7 @@ const getPresence = ((): ((uid: UserPresence['_id']) => void) => { }); currentUids.forEach((uid) => { - emitter.emit(uid, { _id: uid, status: 'offline' }); + emitter.emit(uid, { _id: uid, status: USER_STATUS.OFFLINE }); }); currentUids.clear(); @@ -68,6 +81,10 @@ const getPresence = ((): ((uid: UserPresence['_id']) => void) => { emitter.on('reset', () => { store.clear(); + emitter.events() + .filter(isUid).forEach((uid) => { + emitter.emit(uid, undefined); + }); emitter.once('restart', () => { emitter.events() .filter(isUid) @@ -78,36 +95,35 @@ const getPresence = ((): ((uid: UserPresence['_id']) => void) => { return get; })(); -const update: Handler = (update) => { +const update: EventHandlerOf = (update) => { if (update?._id) { store.set(update._id, update); uids.delete(update._id); } }; -const listen = (uid: UserPresence['_id'], handler: Handler): void => { +const listen = (uid: UserPresence['_id'], handler: EventHandlerOf | (() => void)): void => { emitter.on(uid, update); emitter.on(uid, handler); - emitter.on('reset', handler); - if (store.has(uid)) { - return handler(store.get(uid)); + const user = store.has(uid) && store.get(uid); + if (user) { + return handler(user); } getPresence(uid); }; -const stop = (uid: UserPresence['_id'], handler: Handler): void => { +const stop = (uid: UserPresence['_id'], handler: EventHandlerOf | (() => void)): void => { setTimeout(() => { emitter.off(uid, handler); emitter.off(uid, update); - emitter.off('reset', handler); emitter.emit('remove', uid); }, 5000); }; const reset = (): void => { - emitter.emit('reset', {}); + emitter.emit('reset'); store.clear(); }; @@ -126,7 +142,7 @@ const notify = (update: UserPresence): void => { }; const get = async (uid: UserPresence['_id']): Promise => new Promise((resolve) => { - const callback: Handler = (args): void => { + const callback: EventHandlerOf = (args): void => { resolve(args); stop(uid, callback); }; diff --git a/client/views/room/contexts/RoomContext.ts b/client/views/room/contexts/RoomContext.ts index a11e5faad5b66..cde7a321b762a 100644 --- a/client/views/room/contexts/RoomContext.ts +++ b/client/views/room/contexts/RoomContext.ts @@ -1,5 +1,4 @@ import { createContext } from 'react'; -// import { Handler } from '@rocket.chat/emitter'; import { IRoom } from '../../../../definition/IRoom'; diff --git a/client/views/room/lib/Toolbox/ToolboxContext.tsx b/client/views/room/lib/Toolbox/ToolboxContext.tsx index 75821941a7022..3cda75b67c3e9 100644 --- a/client/views/room/lib/Toolbox/ToolboxContext.tsx +++ b/client/views/room/lib/Toolbox/ToolboxContext.tsx @@ -1,13 +1,15 @@ import { createContext } from 'react'; -import { Handler } from '@rocket.chat/emitter'; +import { EventHandlerOf } from '@rocket.chat/emitter'; -import { actions, listen, ToolboxActionConfig, ToolboxAction } from '.'; +import { actions, listen, ToolboxActionConfig, ToolboxAction, Events } from '.'; import './defaultActions'; +export type ToolboxEventHandler = (handler: EventHandlerOf) => Function; + export type ChannelContextValue = { actions: Map; - listen: (handler: Handler) => Function; + listen: ToolboxEventHandler; tabBar?: any; context?: any; open: Function; diff --git a/client/views/room/lib/Toolbox/generator.tsx b/client/views/room/lib/Toolbox/generator.tsx index c1252e02baf95..5e22bdea9481c 100644 --- a/client/views/room/lib/Toolbox/generator.tsx +++ b/client/views/room/lib/Toolbox/generator.tsx @@ -1,18 +1,22 @@ -import { Emitter, Handler } from '@rocket.chat/emitter'; +import { Emitter, EventHandlerOf } from '@rocket.chat/emitter'; export type Store = Map; -export const generator = function generator(name?: string): -{ + +export type Events = { + change: Store; +}; + +export const generator = function generator(name?: string): ({ store: Store; add: (id: string, action: T) => Store; remove: (id: string) => boolean; - listen: (handler: Handler) => Function; + listen: (handler: EventHandlerOf, 'change'>) => Function; name: string | undefined; -} { +}) { const store: Store = new Map(); - const emitter = new Emitter(); + const emitter = new Emitter>(); const add = (id: string, action: T): Store => { store.set(id, action); @@ -26,7 +30,7 @@ export const generator = function generator(name?: string): return result; }; - const listen = (handler: Handler): Function => emitter.on('change', handler); + const listen = (handler: EventHandlerOf, 'change'>): Function => emitter.on('change', handler); return Object.freeze({ store, diff --git a/client/views/room/lib/Toolbox/index.tsx b/client/views/room/lib/Toolbox/index.tsx index 96e5cfef36f60..62ce552917add 100644 --- a/client/views/room/lib/Toolbox/index.tsx +++ b/client/views/room/lib/Toolbox/index.tsx @@ -2,7 +2,7 @@ import { FC, LazyExoticComponent, ReactNode, MouseEvent } from 'react'; import { BoxProps, OptionProps } from '@rocket.chat/fuselage'; import { IRoom } from '../../../../../definition/IRoom'; -import { generator } from './generator'; +import { generator, Events as GeneratorEvents } from './generator'; type ToolboxHook = ({ room }: { room: IRoom }) => ToolboxActionConfig | null @@ -38,4 +38,6 @@ export type ToolboxAction = ToolboxHook | ToolboxActionConfig; const { listen, add: addAction, remove: deleteAction, store: actions } = generator(); +export type Events = GeneratorEvents; + export { listen, addAction, deleteAction, actions }; diff --git a/client/views/room/providers/ToolboxProvider.tsx b/client/views/room/providers/ToolboxProvider.tsx index c07788e14e23e..a9f246f24c260 100644 --- a/client/views/room/providers/ToolboxProvider.tsx +++ b/client/views/room/providers/ToolboxProvider.tsx @@ -1,8 +1,7 @@ import React, { ReactNode, useContext, useMemo, useState, useCallback, useLayoutEffect } from 'react'; import { useDebouncedState, useMutableCallback, useSafely } from '@rocket.chat/fuselage-hooks'; -import { Handler } from '@rocket.chat/emitter'; -import { ToolboxContext } from '../lib/Toolbox/ToolboxContext'; +import { ToolboxContext, ToolboxEventHandler } from '../lib/Toolbox/ToolboxContext'; import { ToolboxAction, ToolboxActionConfig } from '../lib/Toolbox/index'; import { IRoom } from '../../../../definition/IRoom'; import { useCurrentRoute, useRoute } from '../../../contexts/RouterContext'; @@ -37,7 +36,7 @@ const VirtualAction = React.memo(({ handleChange, room, action, id }: { id: stri return null; }); -const useToolboxActions = (room: IRoom): { listen: (handler: Handler) => Function; actions: Array<[string, ToolboxAction]> } => { +const useToolboxActions = (room: IRoom): { listen: ToolboxEventHandler; actions: Array<[string, ToolboxAction]> } => { const { listen, actions } = useContext(ToolboxContext); const [state, setState] = useState>(Array.from(actions.entries())); diff --git a/package-lock.json b/package-lock.json index 3c47731c5942d..7ac98b455f557 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5927,11 +5927,12 @@ } }, "@rocket.chat/css-in-js": { - "version": "0.6.3-dev.178", - "resolved": "https://registry.npmjs.org/@rocket.chat/css-in-js/-/css-in-js-0.6.3-dev.178.tgz", - "integrity": "sha512-4cnyJx8TbZ8zKWfl1gYGfWZBtf9RWWbaDQpKClkN5myCAXE07QG/tP0z/A0nnGCiU0qSZDrsl/wcdxYwG47tEA==", + "version": "0.6.3-dev.180", + "resolved": "https://registry.npmjs.org/@rocket.chat/css-in-js/-/css-in-js-0.6.3-dev.180.tgz", + "integrity": "sha512-j34Yv+O7J0h7vG0wNe3zjteaCz3ZNJ4fyNldte5+ByiqS/LanQpQYA08+Srvtb2LCI177E9pJHQ4o0UBxIhPUg==", "requires": { "@emotion/hash": "^0.8.0", + "@rocket.chat/memo": "^0.6.3-dev.180+2425c045", "stylis": "^4.0.6" }, "dependencies": { @@ -5943,9 +5944,9 @@ } }, "@rocket.chat/emitter": { - "version": "0.6.3-dev.178", - "resolved": "https://registry.npmjs.org/@rocket.chat/emitter/-/emitter-0.6.3-dev.178.tgz", - "integrity": "sha512-wgmr7Yg6Hx7hPVpFhlOoQha8I/mLpSUb273y1MYQOItBBF58VOYwdC2r6gvBZRRbziGOZL95eOmP1N6odP4RCg==" + "version": "0.6.3-dev.185", + "resolved": "https://registry.npmjs.org/@rocket.chat/emitter/-/emitter-0.6.3-dev.185.tgz", + "integrity": "sha512-23TNzv+sS8cDT1MQl402QVsI4OEcnChtOhru6TyQqCndfpvBBObmiATgxFnClA6HQA5pXt8qMGxUl/UXDXKs0A==" }, "@rocket.chat/eslint-config": { "version": "0.3.0", @@ -5957,12 +5958,13 @@ } }, "@rocket.chat/fuselage": { - "version": "0.6.3-dev.179", - "resolved": "https://registry.npmjs.org/@rocket.chat/fuselage/-/fuselage-0.6.3-dev.179.tgz", - "integrity": "sha512-z4Wgk8J34NfriXuh00cJ+J3M7h1fxFtG9ily3cKhYIVNPHyhUR4o3h2MbvPKKE+mBPzuLsOV2kbcb49y4gm76g==", + "version": "0.6.3-dev.184", + "resolved": "https://registry.npmjs.org/@rocket.chat/fuselage/-/fuselage-0.6.3-dev.184.tgz", + "integrity": "sha512-wsZ5zajh7mZFBRsW2NU0IkED7SCYawlNKuw9AbEQ9tg7D0mjaMvxoRlMyxq5RDOfB1VtY7wn3sXRj0StXy9F0w==", "requires": { "@rocket.chat/css-in-js": "^0.21.0", "@rocket.chat/fuselage-tokens": "^0.21.0", + "@rocket.chat/memo": "^0.6.3-dev.180", "invariant": "^2.2.4", "react-keyed-flatten-children": "^1.2.0" }, @@ -6018,9 +6020,9 @@ "integrity": "sha512-gVzQHhUsZSLbIkwGi8f1KpsTepkmtwHs7hl1gGr0HrnI4eYhBWpMOEjdiH3czhPuoF/O4C8QjdpDrktIuwkVNQ==" }, "@rocket.chat/fuselage-ui-kit": { - "version": "0.6.3-dev.179", - "resolved": "https://registry.npmjs.org/@rocket.chat/fuselage-ui-kit/-/fuselage-ui-kit-0.6.3-dev.179.tgz", - "integrity": "sha512-xQpxwvpiZwTnANdNkaxRASsCZuP0yftHtz/Lq/K0CW9VQc3Ml+mkOp+FV1XImZlyv31bwfxW78SsdaQNmDkTAQ==", + "version": "0.6.3-dev.184", + "resolved": "https://registry.npmjs.org/@rocket.chat/fuselage-ui-kit/-/fuselage-ui-kit-0.6.3-dev.184.tgz", + "integrity": "sha512-xO1FuY9bCKTOKOANbRi189Uq0j6+pVSKaV3E5C3TYvWuMhwE2Lfq4gbiH/uEn5cnrVdR1HOJaaskCxkraGqTVg==", "requires": { "@rocket.chat/fuselage-polyfills": "^0.21.0" }, @@ -6094,6 +6096,11 @@ } } }, + "@rocket.chat/memo": { + "version": "0.6.3-dev.180", + "resolved": "https://registry.npmjs.org/@rocket.chat/memo/-/memo-0.6.3-dev.180.tgz", + "integrity": "sha512-3+zoOZW/f2/cwmjDAh8yXvGQvskopSR/QCAUmatqSAiMztFvkBljlVbSx1YUiq4y5t41dzM5m+MKYRZAEgAtLQ==" + }, "@rocket.chat/mp3-encoder": { "version": "0.6.3-dev.178", "resolved": "https://registry.npmjs.org/@rocket.chat/mp3-encoder/-/mp3-encoder-0.6.3-dev.178.tgz", @@ -20098,7 +20105,7 @@ }, "minimist": { "version": "0.0.8", - "resolved": false, + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true, "optional": true @@ -20126,7 +20133,7 @@ }, "mkdirp": { "version": "0.5.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, "optional": true, @@ -20299,7 +20306,7 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true, "optional": true diff --git a/package.json b/package.json index 69cb53a043cb1..eff9bf350c187 100644 --- a/package.json +++ b/package.json @@ -135,13 +135,13 @@ "@nivo/line": "^0.61.1", "@nivo/pie": "^0.61.1", "@rocket.chat/apps-engine": "1.22.2", - "@rocket.chat/css-in-js": "^0.6.3-dev.178", - "@rocket.chat/emitter": "^0.6.3-dev.178", - "@rocket.chat/fuselage": "^0.6.3-dev.179", + "@rocket.chat/css-in-js": "^0.6.3-dev.180", + "@rocket.chat/emitter": "^0.6.3-dev.185", + "@rocket.chat/fuselage": "^0.6.3-dev.184", "@rocket.chat/fuselage-hooks": "^0.6.3-dev.178", "@rocket.chat/fuselage-polyfills": "^0.6.3-dev.181", "@rocket.chat/fuselage-tokens": "^0.21.0", - "@rocket.chat/fuselage-ui-kit": "^0.6.3-dev.179", + "@rocket.chat/fuselage-ui-kit": "^0.6.3-dev.184", "@rocket.chat/icons": "^0.6.3-dev.179", "@rocket.chat/mp3-encoder": "^0.6.3-dev.178", "@rocket.chat/ui-kit": "^0.6.3-dev.178",