diff --git a/.changeset/six-emus-buy.md b/.changeset/six-emus-buy.md new file mode 100644 index 0000000000..1ef2a8e124 --- /dev/null +++ b/.changeset/six-emus-buy.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-signals-react': patch +'@backstage/plugin-signals-node': patch +'@backstage/plugin-signals': patch +--- + +Allow defining signal type to publish and receive diff --git a/plugins/signals-node/api-report.md b/plugins/signals-node/api-report.md index cbf4142daf..4c95891171 100644 --- a/plugins/signals-node/api-report.md +++ b/plugins/signals-node/api-report.md @@ -11,19 +11,23 @@ import { ServiceRef } from '@backstage/backend-plugin-api'; export class DefaultSignalService implements SignalService { // (undocumented) static create(options: SignalServiceOptions): DefaultSignalService; - publish(signal: SignalPayload): Promise; + publish( + signal: SignalPayload, + ): Promise; } // @public (undocumented) -export type SignalPayload = { +export type SignalPayload = { recipients: string[] | string | null; channel: string; - message: JsonObject; + message: SignalType; }; // @public (undocumented) export interface SignalService { - publish(signal: SignalPayload): Promise; + publish( + signal: SignalPayload, + ): Promise; } // @public (undocumented) diff --git a/plugins/signals-node/src/DefaultSignalService.ts b/plugins/signals-node/src/DefaultSignalService.ts index 2a234fe5d4..d99bae48ff 100644 --- a/plugins/signals-node/src/DefaultSignalService.ts +++ b/plugins/signals-node/src/DefaultSignalService.ts @@ -16,6 +16,7 @@ import { EventBroker } from '@backstage/plugin-events-node'; import { SignalPayload, SignalServiceOptions } from './types'; import { SignalService } from './SignalService'; +import { JsonObject } from '@backstage/types'; /** @public */ export class DefaultSignalService implements SignalService { @@ -31,12 +32,12 @@ export class DefaultSignalService implements SignalService { } /** - * Publishes a message to user refs to specific topic - * @param recipients - string or array of user ref strings to publish message to - * @param topic - message topic - * @param message - message to publish + * Publishes a signal to user refs to specific topic + * @param signal - Signal to publish */ - async publish(signal: SignalPayload) { + async publish( + signal: SignalPayload, + ) { await this.eventBroker?.publish({ topic: 'signals', eventPayload: signal, diff --git a/plugins/signals-node/src/SignalService.ts b/plugins/signals-node/src/SignalService.ts index 7d021ccf4e..383da51b4c 100644 --- a/plugins/signals-node/src/SignalService.ts +++ b/plugins/signals-node/src/SignalService.ts @@ -14,11 +14,15 @@ * limitations under the License. */ import { SignalPayload } from './types'; +import { JsonObject } from '@backstage/types'; /** @public */ export interface SignalService { /** - * Publishes a message to user refs to specific topic + * Publishes a signal to user refs to specific topic + * @param signal - Signal to publish */ - publish(signal: SignalPayload): Promise; + publish( + signal: SignalPayload, + ): Promise; } diff --git a/plugins/signals-node/src/types.ts b/plugins/signals-node/src/types.ts index 7e61aea320..bebee835ed 100644 --- a/plugins/signals-node/src/types.ts +++ b/plugins/signals-node/src/types.ts @@ -24,8 +24,8 @@ export type SignalServiceOptions = { }; /** @public */ -export type SignalPayload = { +export type SignalPayload = { recipients: string[] | string | null; channel: string; - message: JsonObject; + message: SignalType; }; diff --git a/plugins/signals-react/api-report.md b/plugins/signals-react/api-report.md index ef4bc1b7fc..0c555cd566 100644 --- a/plugins/signals-react/api-report.md +++ b/plugins/signals-react/api-report.md @@ -9,9 +9,9 @@ import { JsonObject } from '@backstage/types'; // @public (undocumented) export interface SignalApi { // (undocumented) - subscribe( + subscribe( channel: string, - onMessage: (message: JsonObject) => void, + onMessage: (message: SignalType) => void, ): SignalSubscriber; } @@ -25,8 +25,10 @@ export interface SignalSubscriber { } // @public (undocumented) -export const useSignal: (channel: string) => { - lastSignal: JsonObject | null; +export const useSignal: ( + channel: string, +) => { + lastSignal: SignalType | null; isSignalsAvailable: boolean; }; diff --git a/plugins/signals-react/src/api/SignalApi.ts b/plugins/signals-react/src/api/SignalApi.ts index b67b2ea0dc..f27c8d46ee 100644 --- a/plugins/signals-react/src/api/SignalApi.ts +++ b/plugins/signals-react/src/api/SignalApi.ts @@ -28,8 +28,8 @@ export interface SignalSubscriber { /** @public */ export interface SignalApi { - subscribe( + subscribe( channel: string, - onMessage: (message: JsonObject) => void, + onMessage: (message: SignalType) => void, ): SignalSubscriber; } diff --git a/plugins/signals-react/src/hooks/useSignal.ts b/plugins/signals-react/src/hooks/useSignal.ts index 084427e2cc..db65454e0b 100644 --- a/plugins/signals-react/src/hooks/useSignal.ts +++ b/plugins/signals-react/src/hooks/useSignal.ts @@ -19,18 +19,23 @@ import { JsonObject } from '@backstage/types'; import { useEffect, useMemo, useState } from 'react'; /** @public */ -export const useSignal = (channel: string) => { +export const useSignal = ( + channel: string, +): { lastSignal: SignalType | null; isSignalsAvailable: boolean } => { const apiHolder = useApiHolder(); // Use apiHolder instead useApi in case signalApi is not available in the // backstage instance this is used const signals = apiHolder.get(signalApiRef); - const [lastSignal, setLastSignal] = useState(null); + const [lastSignal, setLastSignal] = useState(null); useEffect(() => { let unsub: null | (() => void) = null; if (signals) { - const { unsubscribe } = signals.subscribe(channel, (msg: JsonObject) => { - setLastSignal(msg); - }); + const { unsubscribe } = signals.subscribe( + channel, + (msg: SignalType) => { + setLastSignal(msg); + }, + ); unsub = unsubscribe; } return () => { diff --git a/plugins/signals/api-report.md b/plugins/signals/api-report.md index 398d5fbfe6..180b3076ec 100644 --- a/plugins/signals/api-report.md +++ b/plugins/signals/api-report.md @@ -8,6 +8,7 @@ import { DiscoveryApi } from '@backstage/core-plugin-api'; import { IdentityApi } from '@backstage/core-plugin-api'; import { JsonObject } from '@backstage/types'; import { SignalApi } from '@backstage/plugin-signals-react'; +import { SignalSubscriber } from '@backstage/plugin-signals-react'; // @public (undocumented) export class SignalClient implements SignalApi { @@ -23,12 +24,10 @@ export class SignalClient implements SignalApi { // (undocumented) static readonly DEFAULT_RECONNECT_TIMEOUT_MS: number; // (undocumented) - subscribe( + subscribe( channel: string, - onMessage: (message: JsonObject) => void, - ): { - unsubscribe: () => void; - }; + onMessage: (message: SignalType) => void, + ): SignalSubscriber; } // @public (undocumented) diff --git a/plugins/signals/src/api/SignalClient.ts b/plugins/signals/src/api/SignalClient.ts index d6c4634264..806646c351 100644 --- a/plugins/signals/src/api/SignalClient.ts +++ b/plugins/signals/src/api/SignalClient.ts @@ -13,14 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { SignalApi } from '@backstage/plugin-signals-react'; +import { SignalApi, SignalSubscriber } from '@backstage/plugin-signals-react'; import { JsonObject } from '@backstage/types'; import { DiscoveryApi, IdentityApi } from '@backstage/core-plugin-api'; import { v4 as uuid } from 'uuid'; type Subscription = { channel: string; - callback: (message: JsonObject) => void; + callback: (message: any) => void; }; const WS_CLOSE_NORMAL = 1000; @@ -62,16 +62,16 @@ export class SignalClient implements SignalApi { private reconnectTimeout: number, ) {} - subscribe( + subscribe( channel: string, - onMessage: (message: JsonObject) => void, - ): { unsubscribe: () => void } { + onMessage: (message: SignalType) => void, + ): SignalSubscriber { const subscriptionId = uuid(); const exists = [...this.subscriptions.values()].find( sub => sub.channel === channel, ); this.subscriptions.set(subscriptionId, { - channel: channel, + channel, callback: onMessage, }); @@ -178,12 +178,14 @@ export class SignalClient implements SignalApi { private handleMessage(data: MessageEvent) { try { - const json = JSON.parse(data.data) as JsonObject; - if (json.channel) { - for (const sub of this.subscriptions.values()) { - if (sub.channel === json.channel) { - sub.callback(json.message as JsonObject); - } + const json = JSON.parse(data.data); + if (!json.channel) { + return; + } + + for (const sub of this.subscriptions.values()) { + if (sub.channel === json.channel) { + sub.callback(json.message); } } } catch (e) {