-
Notifications
You must be signed in to change notification settings - Fork 51
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
488 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import { GetLogContents } from '@lib/smAPI/Logs/LogsCommands'; | ||
import { GetLogContentsRequest } from '../smapiTypes'; | ||
import { isSkipToken } from '@lib/common/isSkipToken'; | ||
import { Logger } from '@lib/common/logger'; | ||
import { createAsyncThunk } from '@reduxjs/toolkit'; | ||
|
||
|
||
export const fetchGetLogContents = createAsyncThunk('cache/getGetLogContents', async (param: GetLogContentsRequest, thunkAPI) => { | ||
try { | ||
if (isSkipToken(param)) | ||
{ | ||
Logger.error('Skipping GetEPGFilePreviewById'); | ||
return undefined; | ||
} | ||
Logger.debug('Fetching GetLogContents'); | ||
const fetchDebug = localStorage.getItem('fetchDebug'); | ||
const start = performance.now(); | ||
const response = await GetLogContents(param); | ||
if (fetchDebug) { | ||
const duration = performance.now() - start; | ||
Logger.debug(`Fetch GetLogContents completed in ${duration.toFixed(2)}ms`); | ||
} | ||
|
||
return {param: param, value: response }; | ||
} catch (error) { | ||
console.error('Failed to fetch', error); | ||
return thunkAPI.rejectWithValue({ error: error || 'Unknown error', value: undefined }); | ||
} | ||
}); | ||
|
||
|
112 changes: 112 additions & 0 deletions
112
StreamMaster.WebUI/lib/smAPI/Logs/GetLogContentsSlice.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
import { PayloadAction, createSlice } from '@reduxjs/toolkit'; | ||
import { Logger } from '@lib/common/logger'; | ||
import {FieldData, } from '@lib/smAPI/smapiTypes'; | ||
import { fetchGetLogContents } from '@lib/smAPI/Logs/GetLogContentsFetch'; | ||
|
||
|
||
interface QueryState { | ||
data: Record<string, string | undefined>; | ||
error: Record<string, string | undefined>; | ||
isError: Record<string, boolean>; | ||
isForced: boolean; | ||
isLoading: Record<string, boolean>; | ||
} | ||
|
||
const initialState: QueryState = { | ||
data: {}, | ||
error: {}, | ||
isError: {}, | ||
isForced: false, | ||
isLoading: {} | ||
}; | ||
|
||
const getLogContentsSlice = createSlice({ | ||
initialState, | ||
name: 'GetLogContents', | ||
reducers: { | ||
clear: (state) => { | ||
state = initialState; | ||
Logger.debug('GetLogContents clear'); | ||
}, | ||
|
||
clearByTag: (state, action: PayloadAction<{ tag: string }>) => { | ||
const tag = action.payload.tag; | ||
for (const key in state.data) { | ||
if (key.includes(tag)) { | ||
state.data[key] = undefined; | ||
} | ||
} | ||
Logger.debug('GetLogContents clearByTag'); | ||
}, | ||
|
||
setField: (state, action: PayloadAction<{ fieldData: FieldData }>) => { | ||
const { fieldData } = action.payload; | ||
|
||
if (fieldData.Entity !== undefined && state.data[fieldData.Id]) { | ||
state.data[fieldData.Id] = fieldData.Value; | ||
return; | ||
} | ||
Logger.debug('GetLogContents setField'); | ||
}, | ||
setIsForced: (state, action: PayloadAction<{ force: boolean }>) => { | ||
const { force } = action.payload; | ||
state.isForced = force; | ||
|
||
const updatedData = { ...state.data }; | ||
for (const key in updatedData) { | ||
if (updatedData[key]) { | ||
updatedData[key] = undefined; | ||
} | ||
} | ||
state.data = updatedData; | ||
Logger.debug('GetLogContents setIsForced ', force); | ||
}, | ||
setIsLoading: (state, action: PayloadAction<{ param: string; isLoading: boolean }>) => { | ||
const { param, isLoading } = action.payload; | ||
if (param !== undefined) { | ||
const paramString = JSON.stringify(param); | ||
state.isLoading[paramString] = isLoading; | ||
} else { | ||
for (const key in state.data) { | ||
state.isLoading[key] = action.payload.isLoading; | ||
} | ||
} | ||
Logger.debug('GetLogContents setIsLoading ', action.payload.isLoading); | ||
} | ||
}, | ||
|
||
extraReducers: (builder) => { | ||
builder | ||
.addCase(fetchGetLogContents.pending, (state, action) => { | ||
const paramString = JSON.stringify(action.meta.arg); | ||
state.isLoading[paramString] = true; | ||
state.isError[paramString] = false; | ||
state.isForced = false; | ||
state.error[paramString] = undefined; | ||
}) | ||
.addCase(fetchGetLogContents.fulfilled, (state, action) => { | ||
if (action.payload) { | ||
const { param, value } = action.payload; | ||
const paramString = JSON.stringify(param); | ||
state.data[paramString] = value; | ||
setIsLoading({ isLoading: false, param: paramString }); | ||
state.isLoading[paramString] = false; | ||
state.isError[paramString] = false; | ||
state.error[paramString] = undefined; | ||
state.isForced = false; | ||
} | ||
}) | ||
.addCase(fetchGetLogContents.rejected, (state, action) => { | ||
const paramString = JSON.stringify(action.meta.arg); | ||
state.error[paramString] = action.error.message || 'Failed to fetch'; | ||
state.isError[paramString] = true; | ||
setIsLoading({ isLoading: false, param: paramString }); | ||
state.isLoading[paramString] = false; | ||
state.isForced = false; | ||
}); | ||
|
||
} | ||
}); | ||
|
||
export const { clear, clearByTag, setIsLoading, setIsForced, setField } = getLogContentsSlice.actions; | ||
export default getLogContentsSlice.reducer; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { GetLogNames } from '@lib/smAPI/Logs/LogsCommands'; | ||
import { Logger } from '@lib/common/logger'; | ||
import { createAsyncThunk } from '@reduxjs/toolkit'; | ||
|
||
|
||
export const fetchGetLogNames = createAsyncThunk('cache/getGetLogNames', async (_: void, thunkAPI) => { | ||
try { | ||
Logger.debug('Fetching GetLogNames'); | ||
const fetchDebug = localStorage.getItem('fetchDebug'); | ||
const start = performance.now(); | ||
const response = await GetLogNames(); | ||
if (fetchDebug) { | ||
const duration = performance.now() - start; | ||
Logger.debug(`Fetch GetLogNames completed in ${duration.toFixed(2)}ms`); | ||
} | ||
|
||
return {param: _, value: response }; | ||
} catch (error) { | ||
console.error('Failed to fetch', error); | ||
return thunkAPI.rejectWithValue({ error: error || 'Unknown error', value: undefined }); | ||
} | ||
}); | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import { PayloadAction, createSlice } from '@reduxjs/toolkit'; | ||
import { Logger } from '@lib/common/logger'; | ||
import {FieldData, } from '@lib/smAPI/smapiTypes'; | ||
import { fetchGetLogNames } from '@lib/smAPI/Logs/GetLogNamesFetch'; | ||
import { updateFieldInData } from '@lib/redux/updateFieldInData'; | ||
|
||
|
||
interface QueryState { | ||
data: string[] | undefined; | ||
error: string | undefined; | ||
isError: boolean; | ||
isForced: boolean; | ||
isLoading: boolean; | ||
} | ||
|
||
const initialState: QueryState = { | ||
data: undefined, | ||
error: undefined, | ||
isError: false, | ||
isForced: false, | ||
isLoading: false | ||
}; | ||
|
||
const getLogNamesSlice = createSlice({ | ||
initialState, | ||
name: 'GetLogNames', | ||
reducers: { | ||
clear: (state) => { | ||
state = initialState; | ||
Logger.debug('GetLogNames clear'); | ||
}, | ||
|
||
clearByTag: (state, action: PayloadAction<{ tag: string }>) => { | ||
state.data = undefined; | ||
Logger.debug('GetLogNames clearByTag'); | ||
}, | ||
|
||
setField: (state, action: PayloadAction<{ fieldData: FieldData }>) => { | ||
const { fieldData } = action.payload; | ||
state.data = updateFieldInData(state.data, fieldData); | ||
Logger.debug('GetLogNames setField'); | ||
}, | ||
setIsForced: (state, action: PayloadAction<{ force: boolean }>) => { | ||
const { force } = action.payload; | ||
state.isForced = force; | ||
Logger.debug('GetLogNames setIsForced ', force); | ||
}, | ||
setIsLoading: (state, action: PayloadAction<{isLoading: boolean }>) => { | ||
state.isLoading = action.payload.isLoading; | ||
Logger.debug('GetLogNames setIsLoading ', action.payload.isLoading); | ||
} | ||
}, | ||
|
||
extraReducers: (builder) => { | ||
builder | ||
.addCase(fetchGetLogNames.pending, (state, action) => { | ||
state.isLoading = true; | ||
state.isError = false; | ||
state.error = undefined; | ||
state.isForced = false; | ||
}) | ||
.addCase(fetchGetLogNames.fulfilled, (state, action) => { | ||
if (action.payload) { | ||
const { value } = action.payload; | ||
state.data = value ?? undefined; | ||
setIsLoading({ isLoading: false }); | ||
state.isLoading = false; | ||
state.isError = false; | ||
state.error = undefined; | ||
state.isForced = false; | ||
} | ||
}) | ||
.addCase(fetchGetLogNames.rejected, (state, action) => { | ||
state.error = action.error.message || 'Failed to fetch'; | ||
state.isError = true; | ||
setIsLoading({ isLoading: false }); | ||
state.isLoading = false; | ||
state.isForced = false; | ||
}); | ||
|
||
} | ||
}); | ||
|
||
export const { clear, clearByTag, setIsLoading, setIsForced, setField } = getLogNamesSlice.actions; | ||
export default getLogNamesSlice.reducer; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { isSkipToken } from '@lib/common/isSkipToken'; | ||
import SignalRService from '@lib/signalr/SignalRService'; | ||
import { GetLogContentsRequest } from '@lib/smAPI/smapiTypes'; | ||
|
||
export const GetLogContents = async (request: GetLogContentsRequest): Promise<string | undefined> => { | ||
if ( request === undefined ) { | ||
return undefined; | ||
} | ||
const signalRService = SignalRService.getInstance(); | ||
return await signalRService.invokeHubCommand<string>('GetLogContents', request); | ||
}; | ||
|
||
export const GetLogNames = async (): Promise<string[] | undefined> => { | ||
const signalRService = SignalRService.getInstance(); | ||
return await signalRService.invokeHubCommand<string[]>('GetLogNames'); | ||
}; | ||
|
115 changes: 115 additions & 0 deletions
115
StreamMaster.WebUI/lib/smAPI/Logs/useGetLogContents.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
import { QueryHookResult } from '@lib/apiDefs'; | ||
import store, { RootState } from '@lib/redux/store'; | ||
import { useAppDispatch, useAppSelector } from '@lib/redux/hooks'; | ||
import { clear, clearByTag, setField, setIsForced, setIsLoading } from './GetLogContentsSlice'; | ||
import { useCallback,useEffect } from 'react'; | ||
import { useSMContext } from '@lib/context/SMProvider'; | ||
import { SkipToken } from '@reduxjs/toolkit/query'; | ||
import { getParameters } from '@lib/common/getParameters'; | ||
import { fetchGetLogContents } from './GetLogContentsFetch'; | ||
import {FieldData, GetLogContentsRequest } from '@lib/smAPI/smapiTypes'; | ||
|
||
interface ExtendedQueryHookResult extends QueryHookResult<string | undefined> {} | ||
interface Result extends ExtendedQueryHookResult { | ||
Clear: () => void; | ||
ClearByTag: (tag: string) => void; | ||
SetField: (fieldData: FieldData) => void; | ||
SetIsForced: (force: boolean) => void; | ||
SetIsLoading: (isLoading: boolean, query: string) => void; | ||
} | ||
const useGetLogContents = (params?: GetLogContentsRequest | undefined | SkipToken): Result => { | ||
const { isSystemReady } = useSMContext(); | ||
const dispatch = useAppDispatch(); | ||
const param = getParameters(params); | ||
const isForced = useAppSelector((state) => state.GetLogContents.isForced ?? false); | ||
|
||
const SetIsForced = useCallback( | ||
(forceRefresh: boolean): void => { | ||
dispatch(setIsForced({ force: forceRefresh })); | ||
}, | ||
[dispatch] | ||
); | ||
const ClearByTag = useCallback( | ||
(tag: string): void => { | ||
dispatch(clearByTag({tag: tag })); | ||
}, | ||
[dispatch] | ||
); | ||
|
||
|
||
|
||
const SetIsLoading = useCallback( | ||
(isLoading: boolean, param: string): void => { | ||
if (param === undefined) return; | ||
dispatch(setIsLoading({ isLoading: isLoading, param: param })); | ||
}, | ||
[dispatch] | ||
); | ||
|
||
const selectData = (state: RootState) => { | ||
if (param === undefined) return undefined; | ||
return state.GetLogContents.data[param] || undefined; | ||
}; | ||
const data = useAppSelector(selectData); | ||
|
||
const selectError = (state: RootState) => { | ||
if (param === undefined) return undefined; | ||
return state.GetLogContents.error[param] || undefined; | ||
}; | ||
const error = useAppSelector(selectError); | ||
|
||
const selectIsError = (state: RootState) => { | ||
if (param === undefined) return false; | ||
return state.GetLogContents.isError[param] || false; | ||
}; | ||
const isError = useAppSelector(selectIsError); | ||
|
||
const selectIsLoading = (state: RootState) => { | ||
if (param === undefined) return false; | ||
return state.GetLogContents.isLoading[param] || false; | ||
}; | ||
const isLoading = useAppSelector(selectIsLoading); | ||
|
||
|
||
useEffect(() => { | ||
if (param === undefined) return; | ||
const state = store.getState().GetLogContents; | ||
if (data === undefined && state.isLoading[param] !== true && state.isForced !== true) { | ||
SetIsForced(true); | ||
} | ||
}, [data, param, SetIsForced]); | ||
|
||
useEffect(() => { | ||
if (!isSystemReady) return; | ||
if (param === undefined) return; | ||
const state = store.getState().GetLogContents; | ||
if (params === undefined || param === undefined || param === '{}' ) return; | ||
if (state.isLoading[param]) return; | ||
if (data !== undefined && !isForced) return; | ||
|
||
SetIsLoading(true, param); | ||
dispatch(fetchGetLogContents(params as GetLogContentsRequest)); | ||
}, [SetIsLoading, data, dispatch, isForced, isSystemReady, param, params]); | ||
|
||
const SetField = (fieldData: FieldData): void => { | ||
dispatch(setField({ fieldData: fieldData })); | ||
}; | ||
|
||
const Clear = (): void => { | ||
dispatch(clear()); | ||
}; | ||
|
||
return { | ||
Clear, | ||
ClearByTag, | ||
data, | ||
error, | ||
isError, | ||
isLoading, | ||
SetField, | ||
SetIsForced, | ||
SetIsLoading | ||
}; | ||
}; | ||
|
||
export default useGetLogContents; |
Oops, something went wrong.