mirror of
https://dev.azure.com/tstanciu94/ReverseProxy/_git/ReverseProxy_Frontend
synced 2025-10-03 16:49:04 +03:00
- feat: Add session management components and improve system overview - feat: Update dependencies and replace react-flags with react-country-flag - Update dependencies in package.json: reintroduce react-dom and upgrade redux to version 5.0.1 - refactor: update chatbot implementation and dependencies - refactor: migrate to Redux Toolkit and update dependencies - feat: enhance ReactCountryFlag component with SVG support - refactor: remove Bootstrap dependency and update Node engine requirement; add LabelValue component for better UI consistency - refactor: enhance LabelValue component usage in ServerSummary for improved readability and tooltip support - refactor: replace inline text with LabelValue component in ActiveSessionSummary and SessionSummary for improved consistency and readability - refactor: update components to use LabelValue for improved consistency and readability - refactor: optimize LabelValue component for improved readability and structure - refactor: improve code readability in SessionForwardsComponent by standardizing arrow function syntax and adjusting styling properties
323 lines
8.6 KiB
Markdown
323 lines
8.6 KiB
Markdown
# Redux to RTK Upgrade Plan
|
|
|
|
## Current State Analysis
|
|
|
|
### ✅ What's Working Well
|
|
|
|
1. **Modular Organization**: Reducers organized by features (server, sessions, chatbot, etc.)
|
|
2. **Redux Toolkit Integration**: Using `@reduxjs/toolkit` and `configureStore`
|
|
3. **Consistent Loading States**: Pattern for `loading/loaded` on each entity
|
|
4. **TypeScript Integration**: Well-defined types for actions and state
|
|
|
|
### Current Architecture Pattern
|
|
|
|
```
|
|
features/
|
|
├── server/
|
|
│ ├── actionTypes.ts - Action type constants
|
|
│ ├── actionCreators.ts - Async action creators with thunks
|
|
│ ├── reducer.ts - State management logic
|
|
│ └── api.ts - API calls
|
|
└── [other features...]
|
|
```
|
|
|
|
## Upgrade Opportunities
|
|
|
|
### 1. Redux Toolkit Slices (Major Improvement)
|
|
|
|
**Current approach** uses classic Redux pattern with separate files:
|
|
```typescript
|
|
// actionTypes.ts
|
|
export const LOAD_SERVER_DATA_SUCCESS = "LOAD_SERVER_DATA_SUCCESS" as const;
|
|
|
|
// actionCreators.ts
|
|
export function loadServerData() {
|
|
return async function(dispatch: Dispatch): Promise<void> {
|
|
try {
|
|
const data = await dispatch(sendHttpRequest(api.getServerData()) as any);
|
|
dispatch({ type: types.LOAD_SERVER_DATA_SUCCESS, payload: data });
|
|
} catch (error) {
|
|
throw error;
|
|
}
|
|
};
|
|
}
|
|
|
|
// reducer.ts
|
|
export default function serverReducer(state: ServerState = initialState.server, action: ServerAction): ServerState {
|
|
switch (action.type) {
|
|
case types.LOAD_SERVER_DATA_SUCCESS:
|
|
return { ...state, data: { ...action.payload, loading: false, loaded: true } };
|
|
default:
|
|
return state;
|
|
}
|
|
}
|
|
```
|
|
|
|
**Recommended RTK Slice approach**:
|
|
```typescript
|
|
// serverSlice.ts
|
|
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
|
|
|
|
export const loadServerData = createAsyncThunk(
|
|
'server/loadData',
|
|
async () => {
|
|
return await api.getServerData();
|
|
}
|
|
);
|
|
|
|
const serverSlice = createSlice({
|
|
name: 'server',
|
|
initialState: {
|
|
data: { loading: false, loaded: false },
|
|
activeSession: { loading: false, loaded: false }
|
|
},
|
|
reducers: {
|
|
// Synchronous actions
|
|
clearServerData: (state) => {
|
|
state.data = { loading: false, loaded: false };
|
|
}
|
|
},
|
|
extraReducers: (builder) => {
|
|
builder
|
|
.addCase(loadServerData.pending, (state) => {
|
|
state.data.loading = true;
|
|
})
|
|
.addCase(loadServerData.fulfilled, (state, action) => {
|
|
state.data = { ...action.payload, loading: false, loaded: true };
|
|
})
|
|
.addCase(loadServerData.rejected, (state) => {
|
|
state.data.loading = false;
|
|
});
|
|
}
|
|
});
|
|
|
|
export const { clearServerData } = serverSlice.actions;
|
|
export default serverSlice.reducer;
|
|
```
|
|
|
|
**Benefits**:
|
|
- 70% less boilerplate code
|
|
- Automatic action creators
|
|
- Built-in loading/error handling
|
|
- Immer integration (direct state mutations)
|
|
- Better TypeScript inference
|
|
|
|
### 2. RTK Query for API Management
|
|
|
|
**Current API pattern**:
|
|
```typescript
|
|
// Separate API calls, manual caching, manual loading states
|
|
export function loadServerData() {
|
|
return async function(dispatch: Dispatch): Promise<void> {
|
|
try {
|
|
const data = await dispatch(sendHttpRequest(api.getServerData()) as any);
|
|
dispatch({ type: types.LOAD_SERVER_DATA_SUCCESS, payload: data });
|
|
} catch (error) {
|
|
throw error;
|
|
}
|
|
};
|
|
}
|
|
```
|
|
|
|
**RTK Query approach**:
|
|
```typescript
|
|
// api/serverApi.ts
|
|
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
|
|
|
|
export const serverApi = createApi({
|
|
reducerPath: 'serverApi',
|
|
baseQuery: fetchBaseQuery({
|
|
baseUrl: '/api/',
|
|
prepareHeaders: (headers) => {
|
|
// Add auth headers, content-type, etc.
|
|
return headers;
|
|
},
|
|
}),
|
|
tagTypes: ['ServerData'],
|
|
endpoints: (builder) => ({
|
|
getServerData: builder.query<ServerData, void>({
|
|
query: () => 'server',
|
|
providesTags: ['ServerData'],
|
|
}),
|
|
getActiveSession: builder.query<ActiveSession, string>({
|
|
query: (sessionId) => `sessions/${sessionId}`,
|
|
providesTags: ['ServerData'],
|
|
}),
|
|
}),
|
|
});
|
|
|
|
export const { useGetServerDataQuery, useGetActiveSessionQuery } = serverApi;
|
|
```
|
|
|
|
**Usage in components**:
|
|
```typescript
|
|
function ServerComponent() {
|
|
const { data: serverData, isLoading, error } = useGetServerDataQuery();
|
|
|
|
if (isLoading) return <Spinner />;
|
|
if (error) return <ErrorMessage />;
|
|
|
|
return <ServerDisplay data={serverData} />;
|
|
}
|
|
```
|
|
|
|
**Benefits**:
|
|
- Automatic caching and cache invalidation
|
|
- Built-in loading/error states
|
|
- Automatic re-fetching
|
|
- Optimistic updates
|
|
- Request deduplication
|
|
- Background sync
|
|
|
|
### 3. Enhanced Type Safety
|
|
|
|
**Current types**:
|
|
```typescript
|
|
interface LoadServerDataSuccessAction {
|
|
type: typeof types.LOAD_SERVER_DATA_SUCCESS;
|
|
payload: any; // ❌ Too generic
|
|
}
|
|
```
|
|
|
|
**Improved types**:
|
|
```typescript
|
|
interface ServerData {
|
|
hostname: string;
|
|
sessionsCount: number;
|
|
isChainMember: boolean;
|
|
domain: {
|
|
name: string;
|
|
};
|
|
// ... specific fields instead of 'any'
|
|
}
|
|
|
|
interface ActiveSession {
|
|
sessionId: string;
|
|
isActive: boolean;
|
|
forwards: Forward[];
|
|
// ... specific structure
|
|
}
|
|
```
|
|
|
|
### 4. Selectors with Reselect
|
|
|
|
**Current approach**:
|
|
```typescript
|
|
// Direct state access in components
|
|
const serverData = useSelector(state => state.server.data);
|
|
```
|
|
|
|
**Memoized selectors**:
|
|
```typescript
|
|
import { createSelector } from '@reduxjs/toolkit';
|
|
|
|
// Base selectors
|
|
export const selectServerState = (state: RootState) => state.server;
|
|
export const selectServerData = (state: RootState) => state.server.data;
|
|
|
|
// Memoized computed selectors
|
|
export const selectIsServerLoading = createSelector(
|
|
selectServerData,
|
|
(serverData) => serverData.loading
|
|
);
|
|
|
|
export const selectServerSummary = createSelector(
|
|
selectServerData,
|
|
(serverData) => ({
|
|
hostname: serverData.hostname,
|
|
status: serverData.isChainMember ? 'Active' : 'Inactive',
|
|
sessions: serverData.sessionsCount
|
|
})
|
|
);
|
|
```
|
|
|
|
## Migration Strategy
|
|
|
|
### Phase 1: Setup RTK Query Infrastructure
|
|
1. Install RTK Query dependencies
|
|
2. Configure store with RTK Query middleware
|
|
3. Create base API slice
|
|
|
|
### Phase 2: Migrate One Feature (Server Module)
|
|
1. Convert server module to RTK Query
|
|
2. Update components to use RTK Query hooks
|
|
3. Remove old Redux actions/reducers
|
|
4. Test thoroughly
|
|
|
|
### Phase 3: Gradual Migration
|
|
1. Migrate one feature at a time
|
|
2. Sessions → Forwards → System → Charts
|
|
3. Keep both patterns during transition
|
|
|
|
### Phase 4: Cleanup
|
|
1. Remove old HTTP action utilities
|
|
2. Consolidate remaining slices
|
|
3. Update all TypeScript types
|
|
|
|
## Benefits of Upgrade
|
|
|
|
### Developer Experience
|
|
- **90% less boilerplate** for API calls
|
|
- **Automatic TypeScript inference**
|
|
- **Better debugging tools**
|
|
- **Standardized patterns**
|
|
|
|
### Performance
|
|
- **Automatic request deduplication**
|
|
- **Smart caching strategies**
|
|
- **Background updates**
|
|
- **Optimistic updates**
|
|
|
|
### Maintenance
|
|
- **Single source of truth for API logic**
|
|
- **Automatic error handling**
|
|
- **Built-in retry logic**
|
|
- **Cache invalidation strategies**
|
|
|
|
## Implementation Priority
|
|
|
|
1. **High Impact, Low Risk**: RTK Query for new API endpoints
|
|
2. **Medium Impact**: Convert existing simple GET endpoints
|
|
3. **High Impact, Higher Risk**: Complex state management with mutations
|
|
4. **Polish**: Enhanced selectors and type safety
|
|
|
|
## Timeline Estimate
|
|
|
|
- **Phase 1** (Setup): 1-2 days
|
|
- **Phase 2** (First module): 2-3 days
|
|
- **Phase 3** (Gradual migration): 1-2 weeks
|
|
- **Phase 4** (Cleanup): 2-3 days
|
|
|
|
**Total**: 3-4 weeks for complete migration
|
|
|
|
## Files to Reference
|
|
|
|
Current key files in the Redux architecture:
|
|
- `src/redux/configureStore.ts` - Store configuration
|
|
- `src/redux/reducers/index.ts` - Root reducer
|
|
- `src/features/*/actionTypes.ts` - Action constants
|
|
- `src/features/*/actionCreators.ts` - Thunk actions
|
|
- `src/features/*/reducer.ts` - State management
|
|
- `src/features/*/api.ts` - API calls
|
|
|
|
These will be consolidated into:
|
|
- `src/store/store.ts` - RTK configured store
|
|
- `src/api/` - RTK Query API slices
|
|
- `src/features/*/slice.ts` - RTK slices for local state
|
|
|
|
## Notes for Future Implementation
|
|
|
|
- Start with the server module as it has the simplest data flow
|
|
- Keep backward compatibility during transition
|
|
- Use TypeScript strict mode to catch type issues early
|
|
- Consider using RTK Query code generation for OpenAPI specs if available
|
|
- Plan for cache persistence if needed for offline functionality
|
|
|
|
## Decision Points
|
|
|
|
- **Do we need offline support?** → Affects caching strategy
|
|
- **Are there real-time updates needed?** → Consider WebSocket integration
|
|
- **How complex are the mutations?** → Affects optimistic update strategy
|
|
- **Do we need request cancellation?** → RTK Query provides this automatically
|
|
|
|
This upgrade will significantly modernize the Redux architecture while maintaining all current functionality. |