Skip to content

Commit

Permalink
Do not .gitignore the Logs folder
Browse files Browse the repository at this point in the history
  • Loading branch information
carlreid committed Feb 12, 2025
1 parent c2dc366 commit 4222594
Show file tree
Hide file tree
Showing 8 changed files with 488 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ bld/
[Oo]bj/
[Ll]og/
[Ll]ogs/
!StreamMaster.WebUI/lib/smAPI/Logs/

# Visual Studio 2015/2017 cache/options directory
.vs/
Expand Down
31 changes: 31 additions & 0 deletions StreamMaster.WebUI/lib/smAPI/Logs/GetLogContentsFetch.ts
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 StreamMaster.WebUI/lib/smAPI/Logs/GetLogContentsSlice.ts
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;
24 changes: 24 additions & 0 deletions StreamMaster.WebUI/lib/smAPI/Logs/GetLogNamesFetch.ts
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 });
}
});


85 changes: 85 additions & 0 deletions StreamMaster.WebUI/lib/smAPI/Logs/GetLogNamesSlice.ts
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;
17 changes: 17 additions & 0 deletions StreamMaster.WebUI/lib/smAPI/Logs/LogsCommands.ts
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 StreamMaster.WebUI/lib/smAPI/Logs/useGetLogContents.tsx
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;
Loading

0 comments on commit 4222594

Please sign in to comment.