From b9c2419c1ba0309629429daee1e970def2fc2902 Mon Sep 17 00:00:00 2001 From: Christopher Berge Hove Date: Tue, 14 Nov 2023 10:14:33 +0100 Subject: [PATCH 1/7] feat: scope service messages by current applications in context --- client/packages/core/src/apps/hooks/index.ts | 1 + .../core/src/apps/hooks/use-current-apps.ts | 13 +++ client/packages/core/src/apps/index.ts | 1 + client/packages/core/src/index.ts | 1 + client/packages/core/tsconfig.json | 2 +- .../components/portal-frame/PortalFrame.tsx | 2 + .../ServiceMessageFilter.tsx | 15 +++ .../src/queries/hooks/use-app-groups-query.ts | 16 +-- .../src/queries/portal/getAppGroups.ts | 4 +- .../portal-core/src/queries/portal/index.ts | 1 + .../service-message/components/index.ts | 4 +- client/packages/service-message/index.ts | 7 +- .../provider/ServiceMessageProvider.tsx | 26 ++++- .../query/use-service-message.ts | 110 +++++++++--------- 14 files changed, 127 insertions(+), 76 deletions(-) create mode 100644 client/packages/core/src/apps/hooks/index.ts create mode 100644 client/packages/core/src/apps/hooks/use-current-apps.ts create mode 100644 client/packages/core/src/apps/index.ts create mode 100644 client/packages/portal-client/src/components/service-message-filter/ServiceMessageFilter.tsx diff --git a/client/packages/core/src/apps/hooks/index.ts b/client/packages/core/src/apps/hooks/index.ts new file mode 100644 index 000000000..a32e978d3 --- /dev/null +++ b/client/packages/core/src/apps/hooks/index.ts @@ -0,0 +1 @@ +export * from './use-current-apps'; diff --git a/client/packages/core/src/apps/hooks/use-current-apps.ts b/client/packages/core/src/apps/hooks/use-current-apps.ts new file mode 100644 index 000000000..35842e033 --- /dev/null +++ b/client/packages/core/src/apps/hooks/use-current-apps.ts @@ -0,0 +1,13 @@ +import { useAppGroupsQuery, App } from '@equinor/portal-core'; +import { useMemo } from 'react'; + +export const useCurrentApps = (shouldFilter?: boolean) => { + const { data } = useAppGroupsQuery(); + if (!shouldFilter) return undefined; + return useMemo(() => { + if (!data) return []; + return data.reduce((acc, app) => { + return [...acc, ...app.apps]; + }, [] as App[]); + }, [data]); +}; diff --git a/client/packages/core/src/apps/index.ts b/client/packages/core/src/apps/index.ts new file mode 100644 index 000000000..4cc90d02b --- /dev/null +++ b/client/packages/core/src/apps/index.ts @@ -0,0 +1 @@ +export * from './hooks'; diff --git a/client/packages/core/src/index.ts b/client/packages/core/src/index.ts index e5abc8565..eebc66414 100644 --- a/client/packages/core/src/index.ts +++ b/client/packages/core/src/index.ts @@ -1 +1,2 @@ export * from './user'; +export * from './apps'; diff --git a/client/packages/core/tsconfig.json b/client/packages/core/tsconfig.json index 2336d7a34..ac03e84c6 100644 --- a/client/packages/core/tsconfig.json +++ b/client/packages/core/tsconfig.json @@ -13,7 +13,7 @@ "outDir": "../../dist/out-tsc", }, "files": [], - "include": ["**/*.tsx"] + "include": ["**/*.tsx", "./src"] } diff --git a/client/packages/portal-client/src/components/portal-frame/PortalFrame.tsx b/client/packages/portal-client/src/components/portal-frame/PortalFrame.tsx index 9a538cb5a..858b40480 100644 --- a/client/packages/portal-client/src/components/portal-frame/PortalFrame.tsx +++ b/client/packages/portal-client/src/components/portal-frame/PortalFrame.tsx @@ -9,6 +9,7 @@ import { useBookmarkNavigate } from '@equinor/fusion-framework-react-module-book import { BookmarkProvider } from '@equinor/fusion-framework-react-components-bookmark'; import { HasContext } from '../context/HasContext'; import { css } from '@emotion/css'; +import { ServiceMessageFilter } from '../service-message-filter/ServiceMessageFilter'; const style = css` width: 100vw; @@ -32,6 +33,7 @@ export const PortalFrame = () => {
+ diff --git a/client/packages/portal-client/src/components/service-message-filter/ServiceMessageFilter.tsx b/client/packages/portal-client/src/components/service-message-filter/ServiceMessageFilter.tsx new file mode 100644 index 000000000..d5306ddb4 --- /dev/null +++ b/client/packages/portal-client/src/components/service-message-filter/ServiceMessageFilter.tsx @@ -0,0 +1,15 @@ +import { useCurrentApps } from '@portal/core'; +import { useEffect } from 'react'; +import { useServiceMessage } from '@equinor/service-message'; + +export const ServiceMessageFilter = () => { + const currentApps = useCurrentApps(true)?.map((app) => app.appKey); + const { registerCurrentApps } = useServiceMessage(); + + useEffect(() => { + if (currentApps) { + registerCurrentApps(currentApps); + } + }, [currentApps]); + return null; +}; diff --git a/client/packages/portal-core/src/queries/hooks/use-app-groups-query.ts b/client/packages/portal-core/src/queries/hooks/use-app-groups-query.ts index 00bce17b1..d17912666 100644 --- a/client/packages/portal-core/src/queries/hooks/use-app-groups-query.ts +++ b/client/packages/portal-core/src/queries/hooks/use-app-groups-query.ts @@ -5,14 +5,14 @@ import { useViewController } from '../../providers'; import { AppGroup } from '../../types'; import { getAppGroups } from '../portal/getAppGroups'; -export const useAppGroupsQuery = (): UseQueryResult<[] | AppGroup[]> => { - const id = useViewController().currentView?.id; - const currentContext = useFrameworkCurrentContext(); +export const useAppGroupsQuery = (): UseQueryResult => { + const id = useViewController().currentView?.id; + const currentContext = useFrameworkCurrentContext(); - const client = usePortalClient(); + const client = usePortalClient(); - return useQuery({ - queryKey: ['appGroups', { id, externalId: currentContext?.externalId }], - queryFn: () => getAppGroups(client, id, currentContext?.externalId), - }); + return useQuery({ + queryKey: ['appGroups', { id, externalId: currentContext?.externalId }], + queryFn: () => getAppGroups(client, id, currentContext?.externalId), + }); }; diff --git a/client/packages/portal-core/src/queries/portal/getAppGroups.ts b/client/packages/portal-core/src/queries/portal/getAppGroups.ts index 3101ea661..08ac3d068 100644 --- a/client/packages/portal-core/src/queries/portal/getAppGroups.ts +++ b/client/packages/portal-core/src/queries/portal/getAppGroups.ts @@ -6,12 +6,12 @@ export async function getAppGroups( client: IHttpClient, viewId?: string, contextExternalId?: string -): Promise { +): Promise { try { if (!viewId || !contextExternalId) return []; const res = await client.fetch(getAppGroupsURI(viewId, contextExternalId)); if (!res.ok) throw res; - const data = (await res.json()) as AppGroup[]; + const data = await res.json(); return data || []; } catch (error) { console.error(error); diff --git a/client/packages/portal-core/src/queries/portal/index.ts b/client/packages/portal-core/src/queries/portal/index.ts index 30567d3ff..d568cf5d1 100644 --- a/client/packages/portal-core/src/queries/portal/index.ts +++ b/client/packages/portal-core/src/queries/portal/index.ts @@ -1,2 +1,3 @@ export * from './getViewById'; export * from './getViews'; +export * from './getAppGroups'; diff --git a/client/packages/service-message/components/index.ts b/client/packages/service-message/components/index.ts index 4d8d972c7..06b05d60a 100644 --- a/client/packages/service-message/components/index.ts +++ b/client/packages/service-message/components/index.ts @@ -1,2 +1,2 @@ -export * from "./NotificationService" -export * from "./ServiceMessageIcon" \ No newline at end of file +export * from './NotificationService'; +export * from './ServiceMessageIcon'; diff --git a/client/packages/service-message/index.ts b/client/packages/service-message/index.ts index 554ca3e8f..3788201f1 100644 --- a/client/packages/service-message/index.ts +++ b/client/packages/service-message/index.ts @@ -1,3 +1,4 @@ -export * from "./components/ServiceMessage" -export * from "./components" -export * from "./provider/ServiceMessageProvider" \ No newline at end of file +export * from './components/ServiceMessage'; +export * from './components'; +export * from './provider/ServiceMessageProvider'; +export * from './query/use-service-message'; diff --git a/client/packages/service-message/provider/ServiceMessageProvider.tsx b/client/packages/service-message/provider/ServiceMessageProvider.tsx index a35fd77da..90475bdf0 100644 --- a/client/packages/service-message/provider/ServiceMessageProvider.tsx +++ b/client/packages/service-message/provider/ServiceMessageProvider.tsx @@ -1,6 +1,6 @@ import { useSignalR } from '@equinor/fusion-framework-react/signalr'; -import { createContext, FC, PropsWithChildren, useEffect, useLayoutEffect } from 'react'; +import { createContext, FC, PropsWithChildren, useEffect, useLayoutEffect, useState } from 'react'; import { BehaviorSubject, combineLatestWith, map, Observable } from 'rxjs'; import { useServiceMessageQuery } from '../query/use-service-message-query'; @@ -8,6 +8,7 @@ import { AppReference, ServiceMessage } from '../types/types'; interface IServiceMessageContext { serviceMessages: ServiceMessages; + registerCurrentApps: (apps: string[]) => void; } export const ServiceMessageContext = createContext(null); @@ -112,12 +113,25 @@ const serviceMessages = new ServiceMessages([]); export const ServiceMessageProvider: FC = ({ children }) => { const { data } = useServiceMessageQuery(); + const [apps, setApps] = useState(); + + const registerCurrentApps = (apps?: string[]) => { + setApps(apps); + }; useEffect(() => { - if (data) { + if (!data) return; + + if (apps) { + const filteredMessages = data.filter((message) => { + return message.relevantApps ? message.relevantApps.some((app) => apps.includes(app.key)) : true; + }); + + serviceMessages.next(filteredMessages); + } else { serviceMessages.next(data); } - }, [data]); + }, [data, apps]); const topic = useSignalR('portal', 'portal'); @@ -129,5 +143,9 @@ export const ServiceMessageProvider: FC = ({ children }) => { }; }, [topic]); - return {children}; + return ( + + {children} + + ); }; diff --git a/client/packages/service-message/query/use-service-message.ts b/client/packages/service-message/query/use-service-message.ts index 75fcef369..06e439299 100644 --- a/client/packages/service-message/query/use-service-message.ts +++ b/client/packages/service-message/query/use-service-message.ts @@ -1,59 +1,57 @@ +import { useContext, useEffect, useState } from 'react'; +import { AppServiceMessage, ServiceMessageContext } from '../provider/ServiceMessageProvider'; -import { useContext, useEffect, useState } from "react"; -import { AppServiceMessage, ServiceMessageContext } from "../provider/ServiceMessageProvider"; - -import { ServiceMessage } from "../types/types"; +import { ServiceMessage } from '../types/types'; export const useServiceMessage = (appKey?: string) => { - const context = useContext(ServiceMessageContext); - - if (!context) { - throw new Error("ServiceMessageContext context used out of bounds"); - } - - useEffect(() => { - if (appKey) context.serviceMessages.setCurrentApp(appKey) - }, [appKey]) - - const [messages, setMessages] = useState([]); - const [appsMessages, setAppsMessages] = useState([]); - const [portalMessages, setPortalMessages] = useState([]); - const [currentMessages, setCurrentMessages] = useState([]); - - useEffect(() => { - const sub = context.serviceMessages.messages$.subscribe(setMessages); - return () => { - sub.unsubscribe() - } - }, [context]); - - useEffect(() => { - const sub = context.serviceMessages.appMessages$.subscribe(setAppsMessages); - return () => { - sub.unsubscribe() - } - }, [context]); - - useEffect(() => { - const sub = context.serviceMessages.currentAppMessages$.subscribe(setCurrentMessages); - return () => { - sub.unsubscribe() - } - }, [context]); - - - useEffect(() => { - const sub = context.serviceMessages.portal$.subscribe(setPortalMessages); - return () => { - sub.unsubscribe() - } - }, [context]); - - - return { - appsMessages, - portalMessages, - currentMessages, - messages - } -} \ No newline at end of file + const context = useContext(ServiceMessageContext); + + if (!context) { + throw new Error('ServiceMessageContext context used out of bounds'); + } + + useEffect(() => { + if (appKey) context.serviceMessages.setCurrentApp(appKey); + }, [appKey]); + + const [messages, setMessages] = useState([]); + const [appsMessages, setAppsMessages] = useState([]); + const [portalMessages, setPortalMessages] = useState([]); + const [currentMessages, setCurrentMessages] = useState([]); + + useEffect(() => { + const sub = context.serviceMessages.messages$.subscribe(setMessages); + return () => { + sub.unsubscribe(); + }; + }, [context]); + + useEffect(() => { + const sub = context.serviceMessages.appMessages$.subscribe(setAppsMessages); + return () => { + sub.unsubscribe(); + }; + }, [context]); + + useEffect(() => { + const sub = context.serviceMessages.currentAppMessages$.subscribe(setCurrentMessages); + return () => { + sub.unsubscribe(); + }; + }, [context]); + + useEffect(() => { + const sub = context.serviceMessages.portal$.subscribe(setPortalMessages); + return () => { + sub.unsubscribe(); + }; + }, [context]); + + return { + appsMessages, + portalMessages, + currentMessages, + messages, + registerCurrentApps: context.registerCurrentApps, + }; +}; From 5228fba9acad01bb6870b69aa2d130e644dacc9c Mon Sep 17 00:00:00 2001 From: Noggling Date: Tue, 14 Nov 2023 09:22:03 +0000 Subject: [PATCH 2/7] chore: create pr-449-1600350490.md --- .changeset/pr-449-1600350490.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/pr-449-1600350490.md diff --git a/.changeset/pr-449-1600350490.md b/.changeset/pr-449-1600350490.md new file mode 100644 index 000000000..e947a0455 --- /dev/null +++ b/.changeset/pr-449-1600350490.md @@ -0,0 +1,5 @@ + +--- +"fusion-project-portal": minor +--- +Service messages are now specifically tailored to the selected project's application. Only service messages relevant to the chosen application will be displayed, ensuring that users are not confused by messages unrelated to their concerns. From d4c50037e207b1a5ec7d59ca7160b7c1b603efd7 Mon Sep 17 00:00:00 2001 From: Christopher Berge Hove Date: Tue, 14 Nov 2023 10:25:44 +0100 Subject: [PATCH 3/7] feat: filter app service messages when using WebSockets --- .../provider/ServiceMessageProvider.tsx | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/client/packages/service-message/provider/ServiceMessageProvider.tsx b/client/packages/service-message/provider/ServiceMessageProvider.tsx index 90475bdf0..df765a10b 100644 --- a/client/packages/service-message/provider/ServiceMessageProvider.tsx +++ b/client/packages/service-message/provider/ServiceMessageProvider.tsx @@ -136,12 +136,22 @@ export const ServiceMessageProvider: FC = ({ children }) => { const topic = useSignalR('portal', 'portal'); useLayoutEffect(() => { - const sub = topic.pipe(map((x) => x.shift() as ServiceMessage[])).subscribe(serviceMessages); + const sub = topic.pipe(map((x) => x.shift() as ServiceMessage[])).subscribe((messages) => { + if (apps) { + const filteredMessages = messages.filter((message) => { + return message.relevantApps ? message.relevantApps.some((app) => apps.includes(app.key)) : true; + }); + + serviceMessages.next(filteredMessages); + } else { + serviceMessages.next(messages); + } + }); return () => { sub.unsubscribe(); }; - }, [topic]); + }, [topic, apps]); return ( From c8e92bb228130093ac1dbdf3b6fe8b55204208e8 Mon Sep 17 00:00:00 2001 From: Christopher Berge Hove Date: Tue, 14 Nov 2023 21:14:53 +0100 Subject: [PATCH 4/7] feat: scoping apps and portal service message --- .../ServiceMessageFilter.tsx | 10 +- .../components/ServiceMessage.tsx | 19 ++- .../provider/ServiceMessageProvider.tsx | 138 +++++++++++++----- .../query/use-service-message.ts | 7 +- .../packages/service-message/types/types.ts | 36 +++-- 5 files changed, 144 insertions(+), 66 deletions(-) diff --git a/client/packages/portal-client/src/components/service-message-filter/ServiceMessageFilter.tsx b/client/packages/portal-client/src/components/service-message-filter/ServiceMessageFilter.tsx index d5306ddb4..669fcf435 100644 --- a/client/packages/portal-client/src/components/service-message-filter/ServiceMessageFilter.tsx +++ b/client/packages/portal-client/src/components/service-message-filter/ServiceMessageFilter.tsx @@ -3,13 +3,17 @@ import { useEffect } from 'react'; import { useServiceMessage } from '@equinor/service-message'; export const ServiceMessageFilter = () => { - const currentApps = useCurrentApps(true)?.map((app) => app.appKey); - const { registerCurrentApps } = useServiceMessage(); + const currentApps = useCurrentApps(true); + const { registerCurrentApps, registerPortals } = useServiceMessage(); useEffect(() => { if (currentApps) { - registerCurrentApps(currentApps); + registerCurrentApps(currentApps.map((app) => app.appKey)); } }, [currentApps]); + + useEffect(() => { + registerPortals(['Project execution portal']); + }, []); return null; }; diff --git a/client/packages/service-message/components/ServiceMessage.tsx b/client/packages/service-message/components/ServiceMessage.tsx index b0a00e54d..ee5605afc 100644 --- a/client/packages/service-message/components/ServiceMessage.tsx +++ b/client/packages/service-message/components/ServiceMessage.tsx @@ -5,7 +5,6 @@ import { useParams } from 'react-router-dom'; import styled from 'styled-components'; import { ServiceMessageList } from './ServiceMessageList'; -import { ServiceMessageCard } from './ServiceMessageCard'; import { AppServiceMessage } from '../provider/ServiceMessageProvider'; import { useServiceMessage } from '../query/use-service-message'; import { PortalActionProps } from '@equinor/portal-core'; @@ -36,6 +35,11 @@ const StyledWrapper = styled.div` flex-direction: column; `; +const portalNameMapper = (identifier: string) => { + if (identifier === 'Project execution portal') return 'Project Portal'; + return identifier; +}; + export const ServiceMessageWidget: FC = ({ appKey }) => { const { appsMessages, portalMessages, messages } = useServiceMessage(); const [compact] = useState(false); @@ -44,9 +48,16 @@ export const ServiceMessageWidget: FC = ({ appKey }) <> Portal ({portalMessages.length}) - {portalMessages.length > 0 - ? portalMessages.map((message) => ) - : null} + {portalMessages.length > 0 && + portalMessages.map((portal) => ( + + ))} App Status ({messages.filter((a) => a.scope === 'App').length}) diff --git a/client/packages/service-message/provider/ServiceMessageProvider.tsx b/client/packages/service-message/provider/ServiceMessageProvider.tsx index df765a10b..c981b93c3 100644 --- a/client/packages/service-message/provider/ServiceMessageProvider.tsx +++ b/client/packages/service-message/provider/ServiceMessageProvider.tsx @@ -1,14 +1,15 @@ import { useSignalR } from '@equinor/fusion-framework-react/signalr'; -import { createContext, FC, PropsWithChildren, useEffect, useLayoutEffect, useState } from 'react'; +import { createContext, FC, PropsWithChildren, useCallback, useEffect, useLayoutEffect } from 'react'; import { BehaviorSubject, combineLatestWith, map, Observable } from 'rxjs'; import { useServiceMessageQuery } from '../query/use-service-message-query'; -import { AppReference, ServiceMessage } from '../types/types'; +import { AppReference, PortalReference, ServiceMessage } from '../types/types'; interface IServiceMessageContext { serviceMessages: ServiceMessages; registerCurrentApps: (apps: string[]) => void; + registerPortals: (portals: string[]) => void; } export const ServiceMessageContext = createContext(null); @@ -16,23 +17,62 @@ export const ServiceMessageContext = createContext; + messages$: Observable; + + #messages$: BehaviorSubject; + + #portalsFilter$: BehaviorSubject; + + #appsFilter$: BehaviorSubject; appMessages$: Observable; - currentAppMessages$: Observable; + currentPortalAndAppMessages$: Observable; - portal$: Observable; + portal$: Observable; currentAppKey$: BehaviorSubject; constructor(_initial: ServiceMessage[]) { - this.messages$ = new BehaviorSubject(_initial); this.currentAppKey$ = new BehaviorSubject(''); + + this.#portalsFilter$ = new BehaviorSubject(undefined); + this.#appsFilter$ = new BehaviorSubject(undefined); + + this.#messages$ = new BehaviorSubject(_initial); + this.messages$ = this.#messages$ + .pipe( + combineLatestWith(this.#appsFilter$), + map(([messages, apps]) => + messages.filter( + (message) => + message.scope === 'Portal' || + message.relevantApps?.some((app) => (apps ? apps?.includes(app.key) : true)) + ) + ) + ) + .pipe( + combineLatestWith(this.#portalsFilter$), + map(([messages, portals]) => + messages.filter( + (message) => + message.scope === 'App' || + message.relevantPortals?.some((portal) => + portals ? portals?.includes(portal.identifier) : true + ) + ) + ) + ) + .pipe(map((messages) => messages.filter((message) => true))); + this.appMessages$ = this.messages$.pipe(map((messages) => this.#appServiceMessageMapper(messages))); - this.currentAppMessages$ = this.messages$.pipe( + + this.currentPortalAndAppMessages$ = this.messages$.pipe( combineLatestWith(this.currentAppKey$), map(([messages, appKey]) => messages.filter( @@ -40,7 +80,7 @@ class ServiceMessages { ) ) ); - this.portal$ = this.messages$.pipe(map((messages) => messages.filter((message) => message.scope === 'Portal'))); + this.portal$ = this.messages$.pipe(map((messages) => this.#portalServiceMessageMapper(messages))); } #appServiceMessageMapper = (serviceMessages: ServiceMessage[]): AppServiceMessage[] => { @@ -50,6 +90,12 @@ class ServiceMessages { return Object.keys(currentAppMessageRecord).map((key) => currentAppMessageRecord[key]); }; + #portalServiceMessageMapper = (serviceMessages: ServiceMessage[]): PortalServiceMessage[] => { + return Object.values( + serviceMessages.filter((message) => message.scope === 'Portal').reduce(this.#reducePortalServiceMessage, {}) + ); + }; + // eslint-disable-next-line class-methods-use-this #sortMessages = (serviceMessages: ServiceMessage[]): ServiceMessage[] => { return serviceMessages @@ -86,8 +132,35 @@ class ServiceMessages { return acc; }; + #reducePortalServiceMessage = ( + acc: Record, + message: ServiceMessage + ): Record => { + if (!message.relevantPortals) return acc; + message.relevantPortals.forEach((portal) => { + if (acc[portal.identifier]) { + acc[portal.identifier].messages.push(message); + acc[portal.identifier].messages = this.#sortMessages(acc[portal.identifier].messages); + } else { + acc[portal.identifier] = { + ...portal, + messages: [message], + }; + } + }); + return acc; + }; + next(value: ServiceMessage[]) { - this.messages$.next(value); + this.#messages$.next(value); + } + + registerAppsFilter(value?: string[]) { + this.#appsFilter$.next(value); + } + + registerPortalFilter(value?: string[]) { + this.#portalsFilter$.next(value); } setCurrentApp(appKey: string) { @@ -95,17 +168,17 @@ class ServiceMessages { } get appMessages() { - return this.#appServiceMessageMapper(this.messages$.value); + return this.#appServiceMessageMapper(this.#messages$.value); } get currentAppMessages() { - return this.messages$.value.filter((message) => + return this.#messages$.value.filter((message) => message.relevantApps?.some((app) => app.key === this.currentAppKey$.value) ); } get portalMessages() { - return this.messages$.value.filter((message) => message.scope === 'Portal'); + return this.#messages$.value.filter((message) => message.scope === 'Portal'); } } @@ -113,48 +186,33 @@ const serviceMessages = new ServiceMessages([]); export const ServiceMessageProvider: FC = ({ children }) => { const { data } = useServiceMessageQuery(); - const [apps, setApps] = useState(); - const registerCurrentApps = (apps?: string[]) => { - setApps(apps); - }; + const registerCurrentApps = useCallback((apps?: string[]) => { + serviceMessages.registerAppsFilter(apps); + }, []); + + const registerPortals = useCallback((portals?: string[]) => { + serviceMessages.registerPortalFilter(portals); + }, []); useEffect(() => { if (!data) return; - if (apps) { - const filteredMessages = data.filter((message) => { - return message.relevantApps ? message.relevantApps.some((app) => apps.includes(app.key)) : true; - }); - - serviceMessages.next(filteredMessages); - } else { - serviceMessages.next(data); - } - }, [data, apps]); + serviceMessages.next(data); + }, [data]); - const topic = useSignalR('portal', 'portal'); + const topic = useSignalR('portal', 'service-messages'); useLayoutEffect(() => { - const sub = topic.pipe(map((x) => x.shift() as ServiceMessage[])).subscribe((messages) => { - if (apps) { - const filteredMessages = messages.filter((message) => { - return message.relevantApps ? message.relevantApps.some((app) => apps.includes(app.key)) : true; - }); - - serviceMessages.next(filteredMessages); - } else { - serviceMessages.next(messages); - } - }); + const sub = topic.pipe(map((x) => x.shift() as ServiceMessage[])).subscribe(serviceMessages); return () => { sub.unsubscribe(); }; - }, [topic, apps]); + }, [topic]); return ( - + {children} ); diff --git a/client/packages/service-message/query/use-service-message.ts b/client/packages/service-message/query/use-service-message.ts index 06e439299..086bd0a7d 100644 --- a/client/packages/service-message/query/use-service-message.ts +++ b/client/packages/service-message/query/use-service-message.ts @@ -1,5 +1,5 @@ import { useContext, useEffect, useState } from 'react'; -import { AppServiceMessage, ServiceMessageContext } from '../provider/ServiceMessageProvider'; +import { AppServiceMessage, PortalServiceMessage, ServiceMessageContext } from '../provider/ServiceMessageProvider'; import { ServiceMessage } from '../types/types'; @@ -16,7 +16,7 @@ export const useServiceMessage = (appKey?: string) => { const [messages, setMessages] = useState([]); const [appsMessages, setAppsMessages] = useState([]); - const [portalMessages, setPortalMessages] = useState([]); + const [portalMessages, setPortalMessages] = useState([]); const [currentMessages, setCurrentMessages] = useState([]); useEffect(() => { @@ -34,7 +34,7 @@ export const useServiceMessage = (appKey?: string) => { }, [context]); useEffect(() => { - const sub = context.serviceMessages.currentAppMessages$.subscribe(setCurrentMessages); + const sub = context.serviceMessages.currentPortalAndAppMessages$.subscribe(setCurrentMessages); return () => { sub.unsubscribe(); }; @@ -53,5 +53,6 @@ export const useServiceMessage = (appKey?: string) => { currentMessages, messages, registerCurrentApps: context.registerCurrentApps, + registerPortals: context.registerPortals, }; }; diff --git a/client/packages/service-message/types/types.ts b/client/packages/service-message/types/types.ts index 605dd4e1a..8a6a8a5f0 100644 --- a/client/packages/service-message/types/types.ts +++ b/client/packages/service-message/types/types.ts @@ -1,20 +1,24 @@ export type ServiceMessage = { - id: string, - type: "Issue" | "Maintenance" | "Info", - title: string | null, - content: string | null, - scope: "Portal" | "App", - relevantApps?: AppReference[] | null, - timestamp: Date, - appliesFrom?: Date | null, - appliesTo?: Date | null, - notifyUser: boolean -} + id: string; + type: 'Issue' | 'Maintenance' | 'Info'; + title: string | null; + content: string | null; + scope: 'Portal' | 'App'; + relevantApps?: AppReference[] | null; + relevantPortals?: PortalReference[] | null; + timestamp: Date; + appliesFrom?: Date | null; + appliesTo?: Date | null; + notifyUser: boolean; +}; export type AppReference = { - key: string, - name: string | null, - shortName: string | null -} + key: string; + name: string | null; + shortName: string | null; +}; +export type PortalReference = { + identifier: string; +}; -export type ServiceMessages = Record; \ No newline at end of file +export type ServiceMessages = Record; From 9b986712be66c00034fb41c23d451e52636b7bad Mon Sep 17 00:00:00 2001 From: Christopher Berge Hove Date: Tue, 14 Nov 2023 23:45:56 +0100 Subject: [PATCH 5/7] chore: remove unused code --- .../service-message/provider/ServiceMessageProvider.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/client/packages/service-message/provider/ServiceMessageProvider.tsx b/client/packages/service-message/provider/ServiceMessageProvider.tsx index c981b93c3..a6cc81b88 100644 --- a/client/packages/service-message/provider/ServiceMessageProvider.tsx +++ b/client/packages/service-message/provider/ServiceMessageProvider.tsx @@ -67,8 +67,7 @@ class ServiceMessages { ) ) ) - ) - .pipe(map((messages) => messages.filter((message) => true))); + ); this.appMessages$ = this.messages$.pipe(map((messages) => this.#appServiceMessageMapper(messages))); From 248fcfaa0606f546ff9f7c9df1a43ebb8469350b Mon Sep 17 00:00:00 2001 From: Christopher Berge Hove Date: Wed, 15 Nov 2023 08:51:25 +0100 Subject: [PATCH 6/7] chore: service message test and structure --- .../components/ServiceMessage.tsx | 3 +- .../provider/ServiceMessageProvider.tsx | 174 +------------- .../services/service-message.test.ts | 218 ++++++++++++++++++ .../services/service-message.ts | 162 +++++++++++++ .../packages/service-message/types/types.ts | 7 + 5 files changed, 392 insertions(+), 172 deletions(-) create mode 100644 client/packages/service-message/services/service-message.test.ts create mode 100644 client/packages/service-message/services/service-message.ts diff --git a/client/packages/service-message/components/ServiceMessage.tsx b/client/packages/service-message/components/ServiceMessage.tsx index ee5605afc..dc18b3603 100644 --- a/client/packages/service-message/components/ServiceMessage.tsx +++ b/client/packages/service-message/components/ServiceMessage.tsx @@ -5,10 +5,11 @@ import { useParams } from 'react-router-dom'; import styled from 'styled-components'; import { ServiceMessageList } from './ServiceMessageList'; -import { AppServiceMessage } from '../provider/ServiceMessageProvider'; + import { useServiceMessage } from '../query/use-service-message'; import { PortalActionProps } from '@equinor/portal-core'; import SideSheet from '@equinor/fusion-react-side-sheet'; +import { AppServiceMessage } from '../types/types'; export function ServiceMessages({ action, onClose, open }: PortalActionProps) { const { appKey } = useParams(); diff --git a/client/packages/service-message/provider/ServiceMessageProvider.tsx b/client/packages/service-message/provider/ServiceMessageProvider.tsx index a6cc81b88..c871eef61 100644 --- a/client/packages/service-message/provider/ServiceMessageProvider.tsx +++ b/client/packages/service-message/provider/ServiceMessageProvider.tsx @@ -1,10 +1,9 @@ import { useSignalR } from '@equinor/fusion-framework-react/signalr'; - import { createContext, FC, PropsWithChildren, useCallback, useEffect, useLayoutEffect } from 'react'; -import { BehaviorSubject, combineLatestWith, map, Observable } from 'rxjs'; - import { useServiceMessageQuery } from '../query/use-service-message-query'; -import { AppReference, PortalReference, ServiceMessage } from '../types/types'; +import { ServiceMessage } from '../types/types'; +import { ServiceMessages } from '../services/service-message'; +import { map } from 'rxjs'; interface IServiceMessageContext { serviceMessages: ServiceMessages; @@ -14,173 +13,6 @@ interface IServiceMessageContext { export const ServiceMessageContext = createContext(null); -export interface AppServiceMessage extends AppReference { - messages: ServiceMessage[]; -} -export interface PortalServiceMessage extends PortalReference { - messages: ServiceMessage[]; -} - -class ServiceMessages { - messages$: Observable; - - #messages$: BehaviorSubject; - - #portalsFilter$: BehaviorSubject; - - #appsFilter$: BehaviorSubject; - - appMessages$: Observable; - - currentPortalAndAppMessages$: Observable; - - portal$: Observable; - - currentAppKey$: BehaviorSubject; - - constructor(_initial: ServiceMessage[]) { - this.currentAppKey$ = new BehaviorSubject(''); - - this.#portalsFilter$ = new BehaviorSubject(undefined); - this.#appsFilter$ = new BehaviorSubject(undefined); - - this.#messages$ = new BehaviorSubject(_initial); - this.messages$ = this.#messages$ - .pipe( - combineLatestWith(this.#appsFilter$), - map(([messages, apps]) => - messages.filter( - (message) => - message.scope === 'Portal' || - message.relevantApps?.some((app) => (apps ? apps?.includes(app.key) : true)) - ) - ) - ) - .pipe( - combineLatestWith(this.#portalsFilter$), - map(([messages, portals]) => - messages.filter( - (message) => - message.scope === 'App' || - message.relevantPortals?.some((portal) => - portals ? portals?.includes(portal.identifier) : true - ) - ) - ) - ); - - this.appMessages$ = this.messages$.pipe(map((messages) => this.#appServiceMessageMapper(messages))); - - this.currentPortalAndAppMessages$ = this.messages$.pipe( - combineLatestWith(this.currentAppKey$), - map(([messages, appKey]) => - messages.filter( - (message) => message.scope === 'Portal' || message.relevantApps?.some((app) => app.key === appKey) - ) - ) - ); - this.portal$ = this.messages$.pipe(map((messages) => this.#portalServiceMessageMapper(messages))); - } - - #appServiceMessageMapper = (serviceMessages: ServiceMessage[]): AppServiceMessage[] => { - const currentAppMessageRecord = serviceMessages - .filter((message) => message.scope === 'App') - .reduce(this.#reduceAppServiceMessage, {}); - return Object.keys(currentAppMessageRecord).map((key) => currentAppMessageRecord[key]); - }; - - #portalServiceMessageMapper = (serviceMessages: ServiceMessage[]): PortalServiceMessage[] => { - return Object.values( - serviceMessages.filter((message) => message.scope === 'Portal').reduce(this.#reducePortalServiceMessage, {}) - ); - }; - - // eslint-disable-next-line class-methods-use-this - #sortMessages = (serviceMessages: ServiceMessage[]): ServiceMessage[] => { - return serviceMessages - .sort((a: ServiceMessage, b: ServiceMessage) => { - return new Date(b.timestamp).getUTCDate() - new Date(a.timestamp).getUTCDate(); - }) - .sort((a: ServiceMessage, b: ServiceMessage): number => { - const statusValues = { - Issue: 3, - Maintenance: 2, - Info: 1, - }; - - return statusValues[b.type] - statusValues[a.type]; - }); - }; - - #reduceAppServiceMessage = ( - acc: Record, - message: ServiceMessage - ): Record => { - if (!message.relevantApps) return acc; - message.relevantApps.forEach((app) => { - if (acc[app.key]) { - acc[app.key].messages.push(message); - acc[app.key].messages = this.#sortMessages(acc[app.key].messages); - } else { - acc[app.key] = { - ...app, - messages: [message], - }; - } - }); - return acc; - }; - - #reducePortalServiceMessage = ( - acc: Record, - message: ServiceMessage - ): Record => { - if (!message.relevantPortals) return acc; - message.relevantPortals.forEach((portal) => { - if (acc[portal.identifier]) { - acc[portal.identifier].messages.push(message); - acc[portal.identifier].messages = this.#sortMessages(acc[portal.identifier].messages); - } else { - acc[portal.identifier] = { - ...portal, - messages: [message], - }; - } - }); - return acc; - }; - - next(value: ServiceMessage[]) { - this.#messages$.next(value); - } - - registerAppsFilter(value?: string[]) { - this.#appsFilter$.next(value); - } - - registerPortalFilter(value?: string[]) { - this.#portalsFilter$.next(value); - } - - setCurrentApp(appKey: string) { - this.currentAppKey$.next(appKey); - } - - get appMessages() { - return this.#appServiceMessageMapper(this.#messages$.value); - } - - get currentAppMessages() { - return this.#messages$.value.filter((message) => - message.relevantApps?.some((app) => app.key === this.currentAppKey$.value) - ); - } - - get portalMessages() { - return this.#messages$.value.filter((message) => message.scope === 'Portal'); - } -} - const serviceMessages = new ServiceMessages([]); export const ServiceMessageProvider: FC = ({ children }) => { diff --git a/client/packages/service-message/services/service-message.test.ts b/client/packages/service-message/services/service-message.test.ts new file mode 100644 index 000000000..9ed0d33da --- /dev/null +++ b/client/packages/service-message/services/service-message.test.ts @@ -0,0 +1,218 @@ +import { describe, beforeEach, it, expect } from 'vitest'; +import { ServiceMessages } from './service-message'; +import { AppReference, ServiceMessage } from '../types/types'; + +describe('ServiceMessages', () => { + let serviceMessages: ServiceMessages; + let initialMessages: ServiceMessage[]; + + beforeEach(() => { + initialMessages = [ + { + id: '1', + type: 'Info', + title: 'Initial Message', + content: 'This is an initial message', + scope: 'App', + relevantApps: [{ key: 'appKey', name: 'AppName', shortName: 'AN' }], + timestamp: new Date('2023-01-01T12:00:00Z'), + notifyUser: true, + }, + { + id: '2', + type: 'Issue', + title: 'Another Message', + content: 'This is another message', + scope: 'Portal', + relevantPortals: [{ identifier: 'portal1' }], + timestamp: new Date('2023-01-02T12:00:00Z'), + notifyUser: false, + }, + ]; + + serviceMessages = new ServiceMessages(initialMessages); + }); + + it('should be created', () => { + expect(serviceMessages).toBeTruthy(); + }); + + it('should update messages when next is called', () => { + const newMessages: ServiceMessage[] = [ + { + id: '3', + type: 'Maintenance', + title: 'Updated Message', + content: 'This is an updated message', + scope: 'App', + relevantApps: [{ key: 'appKey', name: 'AppName', shortName: 'AN' }], + timestamp: new Date(), + notifyUser: true, + }, + ]; + + serviceMessages.next(newMessages); + + serviceMessages.messages$.subscribe((messages) => { + expect(messages).toEqual(newMessages); + }); + }); + + it('should filter appMessages based on appsFilter', () => { + const appsFilter: string[] = ['appKey']; + + serviceMessages.registerAppsFilter(appsFilter); + + serviceMessages.appMessages$.subscribe((appMessages) => { + expect(appMessages).toEqual([ + { + key: 'appKey', + name: 'AppName', + shortName: 'AN', + messages: [ + { + id: '1', + type: 'Info', + title: 'Initial Message', + content: 'This is an initial message', + scope: 'App', + relevantApps: [{ key: 'appKey', name: 'AppName', shortName: 'AN' }], + timestamp: new Date('2023-01-01T12:00:00Z'), + notifyUser: true, + }, + ], + }, + ]); + }); + }); + + it('should filter currentPortalAndAppMessages based on currentAppKey', () => { + const newAppKey = 'newAppKey'; + + serviceMessages.setCurrentApp(newAppKey); + + serviceMessages.currentPortalAndAppMessages$.subscribe((messages) => { + expect(messages).toEqual([ + { + id: '2', + type: 'Issue', + title: 'Another Message', + content: 'This is another message', + scope: 'Portal', + relevantPortals: [{ identifier: 'portal1' }], + timestamp: new Date('2023-01-02T12:00:00Z'), + notifyUser: false, + }, + ]); + }); + }); + + it('should filter portalMessages based on portalsFilter', () => { + const portalsFilter: string[] = ['portal1']; + + serviceMessages.registerPortalFilter(portalsFilter); + + serviceMessages.portal$.subscribe((portalMessages) => { + expect(portalMessages).toEqual([ + { + identifier: 'portal1', + messages: [ + { + id: '2', + type: 'Issue', + title: 'Another Message', + content: 'This is another message', + scope: 'Portal', + relevantPortals: [{ identifier: 'portal1' }], + timestamp: new Date('2023-01-02T12:00:00Z'), + notifyUser: false, + }, + ], + }, + ]); + }); + }); + + it('should correctly map app messages using the types', () => { + const appReference: AppReference = { + key: 'appKey', + name: 'AppName', + shortName: 'AN', + }; + + const appMessages: ServiceMessage[] = [ + { + id: '1', + type: 'Info', + title: 'Initial Message', + content: 'This is an initial message', + scope: 'App', + relevantApps: [appReference], + timestamp: new Date('2023-01-01T12:00:00Z'), + notifyUser: true, + }, + { + id: '2', + type: 'Issue', + title: 'Another Message', + content: 'This is another message', + scope: 'Portal', + relevantPortals: [{ identifier: 'portal1' }], + timestamp: new Date('2023-01-02T12:00:00Z'), + notifyUser: false, + }, + { + id: '3', + type: 'Maintenance', + title: 'Updated Message', + content: 'This is an updated message', + scope: 'Portal', + relevantPortals: [{ identifier: 'portal1' }], + timestamp: new Date('2023-01-02T12:00:00Z'), + notifyUser: true, + }, + { + id: '4', + type: 'Info', + title: 'Another App Message', + content: 'This is another app message', + scope: 'App', + relevantApps: [appReference], + timestamp: new Date('2023-01-01T12:00:00Z'), + notifyUser: true, + }, + ]; + + serviceMessages.next(appMessages); + + expect(serviceMessages.appMessages).toEqual([ + { + key: 'appKey', + name: 'AppName', + shortName: 'AN', + messages: [ + { + id: '1', + type: 'Info', + title: 'Initial Message', + content: 'This is an initial message', + scope: 'App', + relevantApps: [appReference], + timestamp: new Date('2023-01-01T12:00:00Z'), + notifyUser: true, + }, + { + id: '4', + type: 'Info', + title: 'Another App Message', + content: 'This is another app message', + scope: 'App', + relevantApps: [appReference], + timestamp: new Date('2023-01-01T12:00:00Z'), + notifyUser: true, + }, + ], + }, + ]); + }); +}); diff --git a/client/packages/service-message/services/service-message.ts b/client/packages/service-message/services/service-message.ts new file mode 100644 index 000000000..907d67dc3 --- /dev/null +++ b/client/packages/service-message/services/service-message.ts @@ -0,0 +1,162 @@ +import { Observable, BehaviorSubject, combineLatestWith, map } from 'rxjs'; +import { ServiceMessage, AppServiceMessage, PortalServiceMessage } from '../types/types'; + +export class ServiceMessages { + messages$: Observable; + + #messages$: BehaviorSubject; + + #portalsFilter$: BehaviorSubject; + + #appsFilter$: BehaviorSubject; + + appMessages$: Observable; + + currentPortalAndAppMessages$: Observable; + + portal$: Observable; + + currentAppKey$: BehaviorSubject; + + constructor(_initial: ServiceMessage[]) { + this.currentAppKey$ = new BehaviorSubject(''); + + this.#portalsFilter$ = new BehaviorSubject(undefined); + this.#appsFilter$ = new BehaviorSubject(undefined); + + this.#messages$ = new BehaviorSubject(_initial); + this.messages$ = this.#messages$ + .pipe( + combineLatestWith(this.#appsFilter$), + map(([messages, apps]) => + messages.filter( + (message) => + message.scope === 'Portal' || + message.relevantApps?.some((app) => (apps ? apps?.includes(app.key) : true)) + ) + ) + ) + .pipe( + combineLatestWith(this.#portalsFilter$), + map(([messages, portals]) => + messages.filter( + (message) => + message.scope === 'App' || + message.relevantPortals?.some((portal) => + portals ? portals?.includes(portal.identifier) : true + ) + ) + ) + ); + + this.appMessages$ = this.messages$.pipe(map((messages) => this.#appServiceMessageMapper(messages))); + + this.currentPortalAndAppMessages$ = this.messages$.pipe( + combineLatestWith(this.currentAppKey$), + map(([messages, appKey]) => + messages.filter( + (message) => message.scope === 'Portal' || message.relevantApps?.some((app) => app.key === appKey) + ) + ) + ); + this.portal$ = this.messages$.pipe(map((messages) => this.#portalServiceMessageMapper(messages))); + } + + #appServiceMessageMapper = (serviceMessages: ServiceMessage[]): AppServiceMessage[] => { + const currentAppMessageRecord = serviceMessages + .filter((message) => message.scope === 'App') + .reduce(this.#reduceAppServiceMessage, {}); + return Object.keys(currentAppMessageRecord).map((key) => currentAppMessageRecord[key]); + }; + + #portalServiceMessageMapper = (serviceMessages: ServiceMessage[]): PortalServiceMessage[] => { + return Object.values( + serviceMessages.filter((message) => message.scope === 'Portal').reduce(this.#reducePortalServiceMessage, {}) + ); + }; + + // eslint-disable-next-line class-methods-use-this + #sortMessages = (serviceMessages: ServiceMessage[]): ServiceMessage[] => { + return serviceMessages + .sort((a: ServiceMessage, b: ServiceMessage) => { + return new Date(b.timestamp).getUTCDate() - new Date(a.timestamp).getUTCDate(); + }) + .sort((a: ServiceMessage, b: ServiceMessage): number => { + const statusValues = { + Issue: 3, + Maintenance: 2, + Info: 1, + }; + + return statusValues[b.type] - statusValues[a.type]; + }); + }; + + #reduceAppServiceMessage = ( + acc: Record, + message: ServiceMessage + ): Record => { + if (!message.relevantApps) return acc; + message.relevantApps.forEach((app) => { + if (acc[app.key]) { + acc[app.key].messages.push(message); + acc[app.key].messages = this.#sortMessages(acc[app.key].messages); + } else { + acc[app.key] = { + ...app, + messages: [message], + }; + } + }); + return acc; + }; + + #reducePortalServiceMessage = ( + acc: Record, + message: ServiceMessage + ): Record => { + if (!message.relevantPortals) return acc; + message.relevantPortals.forEach((portal) => { + if (acc[portal.identifier]) { + acc[portal.identifier].messages.push(message); + acc[portal.identifier].messages = this.#sortMessages(acc[portal.identifier].messages); + } else { + acc[portal.identifier] = { + ...portal, + messages: [message], + }; + } + }); + return acc; + }; + + next(value: ServiceMessage[]) { + this.#messages$.next(value); + } + + registerAppsFilter(value?: string[]) { + this.#appsFilter$.next(value); + } + + registerPortalFilter(value?: string[]) { + this.#portalsFilter$.next(value); + } + + setCurrentApp(appKey: string) { + this.currentAppKey$.next(appKey); + } + + get appMessages() { + return this.#appServiceMessageMapper(this.#messages$.value); + } + + get currentAppMessages() { + return this.#messages$.value.filter((message) => + message.relevantApps?.some((app) => app.key === this.currentAppKey$.value) + ); + } + + get portalMessages() { + return this.#messages$.value.filter((message) => message.scope === 'Portal'); + } +} diff --git a/client/packages/service-message/types/types.ts b/client/packages/service-message/types/types.ts index 8a6a8a5f0..fe02a7cee 100644 --- a/client/packages/service-message/types/types.ts +++ b/client/packages/service-message/types/types.ts @@ -22,3 +22,10 @@ export type PortalReference = { }; export type ServiceMessages = Record; + +export interface AppServiceMessage extends AppReference { + messages: ServiceMessage[]; +} +export interface PortalServiceMessage extends PortalReference { + messages: ServiceMessage[]; +} From ca744ebe12f4cfa5051d8e6dc8925c8c5d3a7338 Mon Sep 17 00:00:00 2001 From: Christopher Berge Hove Date: Wed, 15 Nov 2023 08:56:23 +0100 Subject: [PATCH 7/7] chore: move files and fix imports --- .../components/NotificationService.tsx | 2 +- .../components/ServiceMessage.tsx | 2 +- .../components/ServiceMessageIcon.tsx | 2 +- .../{query => hooks}/use-service-message.ts | 4 ++-- client/packages/service-message/index.ts | 2 +- .../query/use-service-message-query.ts | 20 ++++++++----------- 6 files changed, 14 insertions(+), 18 deletions(-) rename client/packages/service-message/{query => hooks}/use-service-message.ts (93%) diff --git a/client/packages/service-message/components/NotificationService.tsx b/client/packages/service-message/components/NotificationService.tsx index e44d013b3..506bba87b 100644 --- a/client/packages/service-message/components/NotificationService.tsx +++ b/client/packages/service-message/components/NotificationService.tsx @@ -1,7 +1,7 @@ import { FC, PropsWithChildren } from 'react'; import { useParams } from 'react-router-dom'; -import { useServiceMessage } from '../query/use-service-message'; +import { useServiceMessage } from '../hooks/use-service-message'; import { MessageWrapper } from './MessageWrapper'; import { css } from '@emotion/css'; diff --git a/client/packages/service-message/components/ServiceMessage.tsx b/client/packages/service-message/components/ServiceMessage.tsx index dc18b3603..c88cad34c 100644 --- a/client/packages/service-message/components/ServiceMessage.tsx +++ b/client/packages/service-message/components/ServiceMessage.tsx @@ -6,7 +6,7 @@ import styled from 'styled-components'; import { ServiceMessageList } from './ServiceMessageList'; -import { useServiceMessage } from '../query/use-service-message'; +import { useServiceMessage } from '../hooks/use-service-message'; import { PortalActionProps } from '@equinor/portal-core'; import SideSheet from '@equinor/fusion-react-side-sheet'; import { AppServiceMessage } from '../types/types'; diff --git a/client/packages/service-message/components/ServiceMessageIcon.tsx b/client/packages/service-message/components/ServiceMessageIcon.tsx index 287ac8951..d19f4e11e 100644 --- a/client/packages/service-message/components/ServiceMessageIcon.tsx +++ b/client/packages/service-message/components/ServiceMessageIcon.tsx @@ -2,7 +2,7 @@ import { Icon } from '@equinor/eds-core-react'; import { tokens } from '@equinor/eds-tokens'; import { useMemo } from 'react'; import styled from 'styled-components'; -import { useServiceMessage } from '../query/use-service-message'; +import { useServiceMessage } from '../hooks/use-service-message'; import { ServiceMessage } from '../types/types'; const StyledMessageChip = styled.span<{ color: string }>` diff --git a/client/packages/service-message/query/use-service-message.ts b/client/packages/service-message/hooks/use-service-message.ts similarity index 93% rename from client/packages/service-message/query/use-service-message.ts rename to client/packages/service-message/hooks/use-service-message.ts index 086bd0a7d..24245aa16 100644 --- a/client/packages/service-message/query/use-service-message.ts +++ b/client/packages/service-message/hooks/use-service-message.ts @@ -1,7 +1,7 @@ import { useContext, useEffect, useState } from 'react'; -import { AppServiceMessage, PortalServiceMessage, ServiceMessageContext } from '../provider/ServiceMessageProvider'; +import { ServiceMessageContext } from '../provider/ServiceMessageProvider'; -import { ServiceMessage } from '../types/types'; +import { AppServiceMessage, PortalServiceMessage, ServiceMessage } from '../types/types'; export const useServiceMessage = (appKey?: string) => { const context = useContext(ServiceMessageContext); diff --git a/client/packages/service-message/index.ts b/client/packages/service-message/index.ts index 3788201f1..664262fee 100644 --- a/client/packages/service-message/index.ts +++ b/client/packages/service-message/index.ts @@ -1,4 +1,4 @@ export * from './components/ServiceMessage'; export * from './components'; export * from './provider/ServiceMessageProvider'; -export * from './query/use-service-message'; +export * from './hooks/use-service-message'; diff --git a/client/packages/service-message/query/use-service-message-query.ts b/client/packages/service-message/query/use-service-message-query.ts index 37e864760..40b654578 100644 --- a/client/packages/service-message/query/use-service-message-query.ts +++ b/client/packages/service-message/query/use-service-message-query.ts @@ -4,21 +4,17 @@ import { useQuery } from 'react-query'; import { ServiceMessage } from '../types/types'; - - export async function getActiveServiceMessages(client: IHttpClient): Promise { - const res = await client.fetch(`/api/service-messages/active`); - if (!res.ok) throw res; - return (await res.json()) as ServiceMessage[]; + const res = await client.fetch(`/api/service-messages/active`); + if (!res.ok) throw res; + return (await res.json()) as ServiceMessage[]; } - export const useServiceMessageQuery = () => { - const client = useFramework().modules.serviceDiscovery.createClient('portal'); + const client = useFramework().modules.serviceDiscovery.createClient('portal'); - return useQuery({ - queryKey: ['service-message'], - queryFn: async () => - getActiveServiceMessages(await client), - }); + return useQuery({ + queryKey: ['service-message'], + queryFn: async () => getActiveServiceMessages(await client), + }); };