diff --git a/apps/web/src/app/App.tsx b/apps/web/src/app/App.tsx index 7138326df541ac0f2bfb62826d25b62bf1551c07..929f0f35b270e085905acca260a593b582597a05 100644 --- a/apps/web/src/app/App.tsx +++ b/apps/web/src/app/App.tsx @@ -38,13 +38,13 @@ export function App(props: App) { const dispatch = useAppDispatch(); const [monitoringOpen, setMonitoringOpen] = useState<boolean>(false); - const runQuery = () => { + const rerunQuery = () => { if (session?.currentSaveState && query) { if (query.nodes.length === 0) { dispatch(resetGraphQueryResults()); } else { dispatch(queryingBackend()); - wsQueryRequest(ml); + wsQueryRequest(session.currentSaveState, ml); } } }; @@ -66,7 +66,7 @@ export function App(props: App) { return ( <div className="h-screen w-screen overflow-clip"> <EventBus - onRunQuery={runQuery} + onRunQuery={rerunQuery} onAuthorized={() => { setAuthCheck(true); }} @@ -129,7 +129,7 @@ export function App(props: App) { fallback={<div>Something went wrong</div>} onError={() => dispatch(addError('Something went wrong while trying to load the query builder'))} > - <QueryBuilder onRunQuery={runQuery} /> + <QueryBuilder onRunQuery={rerunQuery} /> </ErrorBoundary> </Resizable> </Resizable> diff --git a/apps/web/src/components/navbar/navbar.tsx b/apps/web/src/components/navbar/navbar.tsx index aead53e59131a5888c441b24ea76f9065d5fe50e..0e3340946cc13a4b9564d74b14a59ade37557951 100644 --- a/apps/web/src/components/navbar/navbar.tsx +++ b/apps/web/src/components/navbar/navbar.tsx @@ -74,7 +74,7 @@ export const Navbar = () => { <PopoverContent className="w-56 z-30 bg-light rounded-sm border-[1px] outline-none"> <div className="p-2 text-sm border-b"> <h2 className="font-bold">user: {authCache.authentication?.username}</h2> - <h3 className="text-xs break-words">session: {authCache.authentication?.sessionID}</h3> + <h3 className="text-xs break-words">session: {authCache?.sessionID}</h3> <h3 className="text-xs break-words">license: Creator</h3> </div> {authCache.authentication?.authenticated ? ( diff --git a/libs/shared/lib/data-access/api/eventBus.tsx b/libs/shared/lib/data-access/api/eventBus.tsx index d58c915cfdb5070ac12e9ed8c75b865e0d5173df..4bbc062ba1b8b2b16936892ca011524bf9ac1f8e 100644 --- a/libs/shared/lib/data-access/api/eventBus.tsx +++ b/libs/shared/lib/data-access/api/eventBus.tsx @@ -25,12 +25,10 @@ import { wsGetState, wsGetStates, wsUpdateState, - wsSelectState, nilUUID, wsGetStatesSubscription, wsDeleteStateSubscription, wsGetStateSubscription, - wsSelectStateSubscription, wsTestSaveStateConnectionSubscription, wsStateGetPolicy, } from '../broker/wsState'; @@ -50,8 +48,9 @@ import { setSchemaAttributeDimensions, setSchemaAttributeInformation, setSchemaL import { addError } from '@graphpolaris/shared/lib/data-access/store/configSlice'; import { unSelect } from '../store/interactionSlice'; import { SchemaGraphStats } from '../../schema'; -import { wsUserGetPolicy } from '../broker/wsUser'; -import { authorized } from '../store/authSlice'; +import { wsReconnectSubscription, wsUserGetPolicy } from '../broker/wsUser'; +import { authorized, setSessionID } from '../store/authSlice'; +import { queryingBackend } from '../store/graphQueryResultSlice'; export const EventBus = (props: { onRunQuery: Function; onAuthorized: Function }) => { const { login } = useAuthentication(); @@ -115,6 +114,12 @@ export const EventBus = (props: { onRunQuery: Function; onAuthorized: Function } }), ); + unsubs.push( + wsReconnectSubscription((data) => { + if (data) dispatch(setSessionID(data)); + }), + ); + Broker.instance().subscribe((data: SchemaGraphStats) => { dispatch(setSchemaAttributeInformation(data)); dispatch(addInfo('Received attribute information')); @@ -170,7 +175,6 @@ export const EventBus = (props: { onRunQuery: Function; onAuthorized: Function } ); unsubs.push(wsDeleteStateSubscription((data) => {})); - unsubs.push(wsSelectStateSubscription((data) => {})); // Broker.instance().subscribe((response: TestDatabaseConnectionResponse) => { // if (response && response.status === 'success') dispatch(testedSaveState(response.saveStateID)); @@ -210,6 +214,7 @@ export const EventBus = (props: { onRunQuery: Function; onAuthorized: Function } if (!isEqual(state.queries?.[0], queryBuilder)) { console.debug('Updating queryBuilder state', state.queries, queryBuilder); state.queries = [{ ...queryBuilder }]; + dispatch(queryingBackend()); dispatch(updateSelectedSaveState(state)); wsUpdateState(state); } @@ -234,7 +239,6 @@ export const EventBus = (props: { onRunQuery: Function; onAuthorized: Function } dispatch(setSchemaLoading(true)); wsSchemaRequest(session.currentSaveState); wsSchemaStatsRequest(session.currentSaveState); - wsSelectState(session.currentSaveState); loadSaveState(session.currentSaveState, session.saveStates); } }, [session.currentSaveState]); @@ -278,16 +282,5 @@ export const EventBus = (props: { onRunQuery: Function; onAuthorized: Function } } }, [auth.authentication]); - useEffect(() => { - if (!queryBuilder.ignoreReactivity) { - props.onRunQuery(); - // Broker.instance().sendMessage({ //TODO!! - // sessionID: auth?.sessionID || '', - // key: 'broadcastState', - // body: { type: 'query_builder_state', status: '', value: queryBuilder }, - // }); - } - }, [queryHash, mlHash, queryBuilderSettings, queryBuilderSettings.unionTypes]); - return <div className="hide"></div>; }; diff --git a/libs/shared/lib/data-access/broker/broker.tsx b/libs/shared/lib/data-access/broker/broker.tsx index 41cfe6f8e7892d116f3f3335568613a782a72b1c..a5ec8c9d47882a077de90b12e98707356bbfe5bf 100644 --- a/libs/shared/lib/data-access/broker/broker.tsx +++ b/libs/shared/lib/data-access/broker/broker.tsx @@ -139,7 +139,6 @@ export class Broker { if (this.authHeader?.roomID) params.set('roomID', this.authHeader?.roomID ?? ''); if (this.saveStateID) params.set('saveStateID', this.saveStateID ?? ''); - if (this.authHeader?.sessionID) params.set('sessionID', this.authHeader?.sessionID ?? ''); // if (this.authHeader?.jwt) params.set('jwt', this.authHeader?.jwt ?? ''); this.webSocket = new WebSocket(this.url + '?' + params.toString()); this.webSocket.onopen = () => { @@ -199,9 +198,8 @@ export class Broker { this.callbackListeners[uuid] = callback; } - fullMessage.sessionID = this.authHeader?.sessionID ?? ''; - if (message.body && typeof message.body !== 'string') { - fullMessage.body = JSON.stringify(message.body); + if (message.body) { + fullMessage.body = message.body; } if (this.webSocket && this.connected && this.webSocket.readyState === 1) this.webSocket.send(JSON.stringify(fullMessage)); diff --git a/libs/shared/lib/data-access/broker/wsInsightSharing.ts b/libs/shared/lib/data-access/broker/wsInsightSharing.ts index 04c366a3ebbb44dcbe5e407c05029adfd8b2f0f6..8159d847236ecf69267fde4afc8c410738da86a7 100644 --- a/libs/shared/lib/data-access/broker/wsInsightSharing.ts +++ b/libs/shared/lib/data-access/broker/wsInsightSharing.ts @@ -11,7 +11,7 @@ export function wsGetInsights(saveStateId: string, callback?: GetInsightsRespons { key: 'insight', subKey: 'getAll', - body: JSON.stringify({ saveStateId: saveStateId }) + body: { saveStateId: saveStateId } }, internalCallback ); @@ -22,7 +22,7 @@ export function wsCreateInsight(insight: InsightRequest, callback?: Function) { { key: 'insight', subKey: 'create', - body: JSON.stringify(insight), + body: insight, }, (data: any, status: string) => { if (status === 'Bad Request') { @@ -32,7 +32,7 @@ export function wsCreateInsight(insight: InsightRequest, callback?: Function) { } if (!data || typeof data !== 'object') { - console.error('Invalid repsonse data', data) + console.error('Invalid response data', data) if (callback) callback(null, 'error'); return; } @@ -57,7 +57,7 @@ export function wsUpdateInsight( { key: 'insight', subKey: 'update', - body: JSON.stringify({ id: id, insight: insight }), + body: { id: id, insight: insight }, }, (data: any, status: string) => { if (status === 'Bad Request') { @@ -74,7 +74,7 @@ export function wsDeleteInsight(id: string, callback?: Function) { { key: 'insight', subKey: 'delete', - body: JSON.stringify({ id }), + body: { id }, }, (data: any, status: string) => { if (status === 'Bad Request') { diff --git a/libs/shared/lib/data-access/broker/wsQuery.ts b/libs/shared/lib/data-access/broker/wsQuery.ts index c5e6ba7e35d0bf15c6ac2ff8c7d0e08eacc92b13..9a3caff0e5e5e5287ba3aa83e16caa2f0d445537 100644 --- a/libs/shared/lib/data-access/broker/wsQuery.ts +++ b/libs/shared/lib/data-access/broker/wsQuery.ts @@ -1,15 +1,14 @@ // All database related API calls -import { BackendQueryFormat } from '../../querybuilder'; import { Broker } from './broker'; import { QueryBuilderText } from '../store/querybuilderSlice'; import { GraphQueryResultFromBackendPayload } from '../store/graphQueryResultSlice'; import { ML, MLTypes } from '../store/mlSlice'; -export function wsQueryRequest(ml: ML) { +export function wsQueryRequest(saveStateID: string, ml: ML) { const mlEnabled = Object.entries(ml) - .filter(([_,value]) => value.enabled) - .map(([key,_]) => { + .filter(([_, value]) => value.enabled) + .map(([key, _]) => { return { type: key as MLTypes, //parameters: [] @@ -18,11 +17,12 @@ export function wsQueryRequest(ml: ML) { Broker.instance().sendMessage({ key: 'query', subKey: 'get', - body: { + body: { + saveStateID: saveStateID, queryID: "0", // TODO: not used yet, but used when multiple queries per save state are supported ml: mlEnabled, cached: false - }, + }, }); } diff --git a/libs/shared/lib/data-access/broker/wsState.tsx b/libs/shared/lib/data-access/broker/wsState.tsx index 9dd85998ddfd3bd5405524251bdeef89c8687751..7c2e21fedc8e9cdbb27ab102e18f545f33a82782 100644 --- a/libs/shared/lib/data-access/broker/wsState.tsx +++ b/libs/shared/lib/data-access/broker/wsState.tsx @@ -54,12 +54,12 @@ export type SaveStateI = { }; type GetStateResponse = (data: SaveStateI, status: string) => void; -export function wsGetState(saveStateId: string, callback?: GetStateResponse) { +export function wsGetState(saveStateID: string, callback?: GetStateResponse) { Broker.instance().sendMessage( { key: 'state', subKey: 'get', - body: { saveStateId: saveStateId }, //messageTypeGetSaveState + body: { saveStateID: saveStateID }, //messageTypeGetSaveState }, callback, ); @@ -92,28 +92,6 @@ export function wsGetStatesSubscription(callback: GetStatesResponse) { }; } -type SelectStateResponse = (data: { saveStateID: string; success: boolean }) => void; -export function wsSelectState(saveStateId: string | undefined, callback?: SelectStateResponse) { - if (saveStateId === undefined) saveStateId = ''; - Broker.instance().sendMessage( - { - key: 'state', - subKey: 'select', - body: { saveStateId: saveStateId }, //messageTypeGetSaveState - }, - callback, - ); - - Broker.instance().useSaveStateID(saveStateId); - setParam(URLParams.saveState, saveStateId); -} -export function wsSelectStateSubscription(callback: SelectStateResponse) { - const id = Broker.instance().subscribe(callback, 'save_state_selected'); - return () => { - Broker.instance().unSubscribe('save_state_selected', id); - }; -} - export function wsCreateState(request: SaveStateI, callback?: GetStateResponse) { Broker.instance().sendMessage( { @@ -132,7 +110,7 @@ export function wsDeleteState(id: string, callback?: Function) { { key: 'state', subKey: 'delete', - body: { saveStateId: id }, //messageTypeGetSaveState + body: { saveStateID: id }, //messageTypeGetSaveState }, callback, ); @@ -144,13 +122,13 @@ export function wsDeleteStateSubscription(callback: DeleteStateResponse) { }; } -type TestSaveStateConnectionResponse = (data: { status: 'success' | 'fail'; saveStateID: string }) => void; +type TestSaveStateConnectionResponse = (data: { status: 'success' | 'fail'; saveStateID?: string }) => void; export function wsTestSaveStateConnection(id: string, callback?: Function) { Broker.instance().sendMessage( { key: 'state', subKey: 'testConnection', - body: { saveStateId: id }, //messageTypeGetSaveState + body: { saveStateID: id }, //messageTypeGetSaveState }, callback, ); @@ -196,7 +174,7 @@ export function wsStateGetPolicy(saveStateID: string, callback?: StateGetPolicyR { key: 'state', subKey: 'getPolicy', - body: { SaveStateID: saveStateID }, + body: { saveStateID: saveStateID }, }, callback, ); diff --git a/libs/shared/lib/data-access/broker/wsUser.tsx b/libs/shared/lib/data-access/broker/wsUser.tsx index 9b6e50a6a91cc5a1e82133a992ee48001c8de9eb..e1ad44e6c516cc54b0d4934dca736b012f54cbda 100644 --- a/libs/shared/lib/data-access/broker/wsUser.tsx +++ b/libs/shared/lib/data-access/broker/wsUser.tsx @@ -1,4 +1,4 @@ -import { UserAuthorizationHeaders } from '../store/authSlice'; +import { ReconnectPayload, UserAuthorizationHeaders } from '../store/authSlice'; import { Broker } from './broker'; type UserPolicyCheckResponse = (data: boolean) => void; @@ -24,3 +24,14 @@ export function wsUserGetPolicy(callback?: UserGetPolicyResponse) { callback, ); } + +export function wsReconnectSubscription(callback: (data: ReconnectPayload) => void) { + const id = Broker.instance().subscribe((data: any) => { + if (data) { + callback(data); + } + }, 'reconnect'); + return () => { + Broker.instance().unSubscribe('reconnect', id); + }; +} diff --git a/libs/shared/lib/data-access/security/useAuthentication.tsx b/libs/shared/lib/data-access/security/useAuthentication.tsx index 33893871afe2d739da9980f30e1453e5ba366a61..eef1af9e64826b888807c568745e1f0a8edc0567 100644 --- a/libs/shared/lib/data-access/security/useAuthentication.tsx +++ b/libs/shared/lib/data-access/security/useAuthentication.tsx @@ -1,6 +1,6 @@ import { getEnvVariable } from 'config'; -import { useAppDispatch, useAuthCache, useSessionCache } from '../store'; -import { authenticated, UserAuthenticationHeader } from '../store/authSlice'; +import { useAppDispatch, useSessionCache } from '../store'; +import { authenticated, setSessionID, UserAuthenticationHeader } from '../store/authSlice'; import { addInfo, addError } from '../store/configSlice'; import { wsShareSaveState } from '../api'; import { getParam, URLParams } from '../api/url'; @@ -34,7 +34,6 @@ export const useAuthentication = () => { authenticated({ username: res.username, userID: res.userID, - sessionID: res.sessionID, jwt: res.jwt, authenticated: true, roomID: res.roomID, diff --git a/libs/shared/lib/data-access/store/authSlice.ts b/libs/shared/lib/data-access/store/authSlice.ts index 12c3b14fd7c17ed0765b08f55e43ed2faa0104c9..b9f5a6dd554108459f106e63686f13f3920fbdfd 100644 --- a/libs/shared/lib/data-access/store/authSlice.ts +++ b/libs/shared/lib/data-access/store/authSlice.ts @@ -28,7 +28,6 @@ export const UserAuthorizationHeadersDefaults: UserAuthorizationHeaders = { export type UserAuthenticationHeader = { username: string; userID: string; - sessionID: string; roomID: string; jwt: string; }; @@ -40,7 +39,6 @@ export type UseIsAuthorizedState = SingleIsAuthorizedState & { export type SingleIsAuthorizedState = { authenticated: boolean; jwt: string; - sessionID: string; userID: string; username: string; roomID: string | undefined; @@ -48,12 +46,16 @@ export type SingleIsAuthorizedState = { export type AuthSliceState = { authentication: SingleIsAuthorizedState | undefined; + sessionID?: string; authorization: UserAuthorizationHeaders; }; +export type ReconnectPayload = { sessionID: string }; + export const initialState: AuthSliceState = { authentication: undefined, authorization: cloneDeep(UserAuthorizationHeadersDefaults), + sessionID: undefined, }; export const authSlice = createSlice({ @@ -94,6 +96,10 @@ export const authSlice = createSlice({ query.delete('roomID'); history.pushState(null, '', '?' + query.toString()); }, + setSessionID(state, action: PayloadAction<ReconnectPayload>) { + console.info('Reconnecting with', action.payload); + state.sessionID = action.payload.sessionID; + }, // unauthorized(state) { // console.warn('Unauthorized'); // state.authentication.authenticated = false; @@ -104,7 +110,7 @@ export const authSlice = createSlice({ }, }); -export const { authorized, authenticated, logout, changeRoom } = authSlice.actions; +export const { authorized, authenticated, logout, changeRoom, setSessionID } = authSlice.actions; // Other code such as selectors can use the imported `RootState` type export const authState = (state: RootState) => state.auth; diff --git a/libs/shared/lib/data-access/store/insightSharingSlice.ts b/libs/shared/lib/data-access/store/insightSharingSlice.ts index ed0bd66ec472814639309ae0ba34fa230a205fa3..4dd06e4483f80b7047f4873cd7d3ad6a56d15aac 100644 --- a/libs/shared/lib/data-access/store/insightSharingSlice.ts +++ b/libs/shared/lib/data-access/store/insightSharingSlice.ts @@ -67,8 +67,8 @@ const insightSharingSlice = createSlice({ export const { setInsights, addInsight, updateInsight, deleteInsight } = insightSharingSlice.actions; -export const selectReports = (state: RootState): InsightResponse[] => state.insightSharing?.insights?.filter((i) => i.type === 'report') ?? []; -export const selectAlerts = (state: RootState): InsightResponse[] => state.insightSharing?.insights?.filter((i) => i.type === 'alert') ?? []; -export const selectInsights = (state: RootState): InsightResponse[] => state.insightSharing?.insights ?? []; +export const selectReports = (state: RootState): InsightResponse[] => state.insightSharing.insights?.filter((i) => i.type === 'report') ?? []; +export const selectAlerts = (state: RootState): InsightResponse[] => state.insightSharing.insights?.filter((i) => i.type === 'alert') ?? []; +export const selectInsights = (state: RootState): InsightResponse[] => state.insightSharing.insights ?? []; export default insightSharingSlice.reducer; diff --git a/libs/shared/lib/data-access/store/querybuilderSlice.ts b/libs/shared/lib/data-access/store/querybuilderSlice.ts index 79dba632784780e64ae643b5cb0de19025bb161c..24aefae6761ec1fab567c5d94dbeb7fae2e9908d 100644 --- a/libs/shared/lib/data-access/store/querybuilderSlice.ts +++ b/libs/shared/lib/data-access/store/querybuilderSlice.ts @@ -29,6 +29,7 @@ export enum QueryUnionType { export type QueryBuilderAttributeBeingShown = {}; export type QueryBuilderState = { + id?: number; graph: QueryMultiGraph; ignoreReactivity: boolean; settings: QueryBuilderSettings; @@ -37,6 +38,7 @@ export type QueryBuilderState = { }; export type SchemaState = { + id?: number; settings: Record<string, any>; } diff --git a/libs/shared/lib/data-access/store/sessionSlice.ts b/libs/shared/lib/data-access/store/sessionSlice.ts index 08d5dc8abaf7cf03a51996ad3a64406fce1a5f6d..19c89237481173c6f70400dfb3f0c2caa3898130 100644 --- a/libs/shared/lib/data-access/store/sessionSlice.ts +++ b/libs/shared/lib/data-access/store/sessionSlice.ts @@ -1,8 +1,7 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit'; import type { RootState } from './store'; -import { DatabaseStatus, SaveStateAuthorizationHeaders, SaveStateAuthorizationObjectsArray, SaveStateI } from '../broker/wsState'; +import { DatabaseStatus, SaveStateAuthorizationHeaders, SaveStateI } from '../broker/wsState'; import { getParam, URLParams } from '../api/url'; -import { AuthorizationOperations } from './authSlice'; import { cloneDeep } from 'lodash-es'; /** Message format of the error message from the backend */ diff --git a/libs/shared/lib/data-access/store/visualizationSlice.ts b/libs/shared/lib/data-access/store/visualizationSlice.ts index 97cb40bdd89fe0c4cf63ef99b84d29390d79124c..961874b9c03b3b66c83be4ae1dbd5bc34dd16239 100644 --- a/libs/shared/lib/data-access/store/visualizationSlice.ts +++ b/libs/shared/lib/data-access/store/visualizationSlice.ts @@ -5,6 +5,7 @@ import { isEqual } from 'lodash-es'; export type VisStateSettings = VisualizationSettingsType[]; export type VisState = { + id?: number; activeVisualizationIndex: number; openVisualizationArray: VisStateSettings; }; @@ -20,10 +21,10 @@ export const visualizationSlice = createSlice({ reducers: { removeVisualization: (state, action: PayloadAction<number | undefined>) => { const index = action.payload ?? state.activeVisualizationIndex; - + if (index >= 0 && index < state.openVisualizationArray.length) { state.openVisualizationArray.splice(index, 1); - + if (state.openVisualizationArray.length === 0) { state.activeVisualizationIndex = -1; } else if (state.activeVisualizationIndex >= state.openVisualizationArray.length) { @@ -81,9 +82,9 @@ export const visualizationSlice = createSlice({ ) => { const { id, newPosition } = action.payload; if ( - id >= 0 && - id < state.openVisualizationArray.length && - newPosition >= 0 && + id >= 0 && + id < state.openVisualizationArray.length && + newPosition >= 0 && newPosition < state.openVisualizationArray.length ) { const settingsCopy = [...state.openVisualizationArray]; @@ -94,12 +95,12 @@ export const visualizationSlice = createSlice({ if (state.activeVisualizationIndex === id) { state.activeVisualizationIndex = newPosition; } else if ( - state.activeVisualizationIndex > id && + state.activeVisualizationIndex > id && state.activeVisualizationIndex <= newPosition ) { state.activeVisualizationIndex--; } else if ( - state.activeVisualizationIndex < id && + state.activeVisualizationIndex < id && state.activeVisualizationIndex >= newPosition ) { state.activeVisualizationIndex++; diff --git a/libs/shared/lib/insight-sharing/FormAlert.tsx b/libs/shared/lib/insight-sharing/FormAlert.tsx index 4f4d2c6af236227bcb4864117b27da519025f2af..1909f4e3145d5bf3adb8ef83810f34633cc91ca6 100644 --- a/libs/shared/lib/insight-sharing/FormAlert.tsx +++ b/libs/shared/lib/insight-sharing/FormAlert.tsx @@ -63,12 +63,17 @@ export function FormAlert(props: Props) { return; } + if (!session.currentSaveState) { + dispatch(addError('No save state selected')); + return; + } + const alertData: InsightRequest = { name, description, recipients, template: JSON.stringify(element), - saveStateId: session.currentSaveState || '', + saveStateId: session.currentSaveState, type: 'alert' as const, frequency: '', }; @@ -162,14 +167,16 @@ export function FormAlert(props: Props) { <span className="font-semibold">Alerting text</span> </AccordionHead> <AccordionBody> - <TextEditor - key={`editor-${props.insight.id}`} - editorState={editorState} - setEditorState={setEditorState} - showToolbar={true} - placeholder="Start typing your alert template..." - handleSave={handleSave} - ><Button label="Delete" variantType="secondary" variant="outline" onClick={handleDelete} /></TextEditor> + <TextEditor + key={`editor-${props.insight.id}`} + editorState={editorState} + setEditorState={setEditorState} + showToolbar={true} + placeholder="Start typing your alert template..." + handleSave={handleSave} + > + <Button label="Delete" variantType="secondary" variant="outline" onClick={handleDelete} /> + </TextEditor> </AccordionBody> </AccordionItem> </Accordion> diff --git a/libs/shared/lib/insight-sharing/FormReport.tsx b/libs/shared/lib/insight-sharing/FormReport.tsx index 69e7a95bdbea93a5523189df5acc74372a87ca85..f721eda4487f155a7f33cc5480dade7976b19a3e 100644 --- a/libs/shared/lib/insight-sharing/FormReport.tsx +++ b/libs/shared/lib/insight-sharing/FormReport.tsx @@ -28,11 +28,11 @@ export function FormReport(props: Props) { const [recipients, setRecipients] = useState(props.insight.recipients || []); const [recipientInput, setRecipientInput] = useState<string>(''); const [frequency, setFrequency] = useState(props.insight.frequency || 'Daily'); - const [editorState, setEditorState] = useState<SerializedEditorState| null>(null); + const [editorState, setEditorState] = useState<SerializedEditorState | null>(null); useEffect(() => { let isMounted = true; - + if (isMounted) { setName(props.insight.name); setDescription(props.insight.description); @@ -50,7 +50,7 @@ export function FormReport(props: Props) { setEditorState(null); } } - + return () => { isMounted = false; setEditorState(null); @@ -75,13 +75,18 @@ export function FormReport(props: Props) { return; } + if (!session.currentSaveState) { + dispatch(addError('No save state ID found.')); + return; + } + const reportData: InsightRequest = { name, description, recipients, frequency, template: JSON.stringify(elements), - saveStateId: session.currentSaveState || '', + saveStateId: session.currentSaveState, type: 'report' as const, }; @@ -100,7 +105,6 @@ export function FormReport(props: Props) { }); } else { wsCreateInsight(reportData, (data: any, status: string) => { - debugger; setLoading(false); if (status === 'success') { dispatch(updateInsight(data)); @@ -187,14 +191,16 @@ export function FormReport(props: Props) { <span className="font-semibold">Email Template</span> </AccordionHead> <AccordionBody> - <TextEditor - key={`editor-${props.insight.id}`} - editorState={editorState} - setEditorState={setEditorState} - showToolbar={true} - placeholder="Start typing your report template..." - handleSave={handleSave} - ><Button label="Delete" variantType="secondary" variant="outline" onClick={handleDelete} /></TextEditor> + <TextEditor + key={`editor-${props.insight.id}`} + editorState={editorState} + setEditorState={setEditorState} + showToolbar={true} + placeholder="Start typing your report template..." + handleSave={handleSave} + > + <Button label="Delete" variantType="secondary" variant="outline" onClick={handleDelete} /> + </TextEditor> </AccordionBody> </AccordionItem> </Accordion> diff --git a/libs/shared/lib/insight-sharing/components/AddItem.tsx b/libs/shared/lib/insight-sharing/components/AddItem.tsx index b207b9ec6c890ed167495615fac412fc2ebfe35c..75b2e07f085e1d24b4e66312bc98a7825b8aec56 100644 --- a/libs/shared/lib/insight-sharing/components/AddItem.tsx +++ b/libs/shared/lib/insight-sharing/components/AddItem.tsx @@ -2,9 +2,9 @@ import React, { useState } from 'react'; import { Input, Button } from '../../components'; import { MonitorType as InsightType, MonitorType } from './Sidebar'; import { useAppDispatch, useSessionCache } from '../../data-access'; -import { addInsight } from '../../data-access/store/insightSharingSlice'; +import { addInsight, InsightRequest } from '../../data-access/store/insightSharingSlice'; import { wsCreateInsight } from '../../data-access/broker/wsInsightSharing'; -import { addError, addSuccess, } from '@graphpolaris/shared/lib/data-access/store/configSlice'; +import { addError, addSuccess } from '@graphpolaris/shared/lib/data-access/store/configSlice'; type Props = { setAdding: (val: false | MonitorType) => void; @@ -24,13 +24,18 @@ export function AddItem(props: Props) { return; } - const newInsight = { + if (!session.currentSaveState) { + dispatch(addError('No save state selected')); + return; + } + + const newInsight: InsightRequest = { name, description, recipients: [], template: '', frequency: props.type === 'report' ? 'Daily' : '', - saveStateId: session.currentSaveState || '', + saveStateId: session.currentSaveState, type: props.type, }; @@ -42,7 +47,7 @@ export function AddItem(props: Props) { dispatch(addSuccess('Succesfully created ' + props.type)); } else { console.error('Failed to create insight:', data); - dispatch(addError('Failed to create new ' + props.type)) + dispatch(addError('Failed to create new ' + props.type)); } }); }; diff --git a/libs/shared/lib/management/database/useHandleDatabase.ts b/libs/shared/lib/management/database/useHandleDatabase.ts index 8ee9639a5baf304fe6d35ac25339c5f940719146..450571fb61f419db77d71fed17d52235b40434c5 100644 --- a/libs/shared/lib/management/database/useHandleDatabase.ts +++ b/libs/shared/lib/management/database/useHandleDatabase.ts @@ -68,7 +68,9 @@ export const useHandleDatabase = () => { concludedCallback(); }); } else { - dispatch(testedSaveState(data.saveStateID)); + if (data.saveStateID) { + dispatch(testedSaveState(data.saveStateID)); + } wsUpdateState(saveStateData, (updatedSaveState) => { dispatch(addSaveState(updatedSaveState)); setConnectionStatus({