Skip to content

Commit c732fa7

Browse files
authored
feat: implement info panel (#622)
* feat: implement info panel
1 parent 4a341c3 commit c732fa7

File tree

23 files changed

+402
-70
lines changed

23 files changed

+402
-70
lines changed

lib/gui/constants/client-events.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ export const ClientEvents = {
99
RETRY: 'retry',
1010
ERROR: 'err',
1111

12-
END: 'end'
12+
END: 'end',
13+
14+
CONNECTED: 'connected'
1315
} as const;
1416

1517
export type ClientEvents = typeof ClientEvents;

lib/gui/event-source.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,28 @@
11
import {Response} from 'express';
22
import stringify from 'json-stringify-safe';
3+
import {ClientEvents} from './constants';
34

45
export class EventSource {
56
private _connections: Response[];
67
constructor() {
78
this._connections = [];
89
}
910

11+
private _write(connection: Response, event: string, data?: unknown): void {
12+
connection.write('event: ' + event + '\n');
13+
connection.write('data: ' + stringify(data) + '\n');
14+
connection.write('\n\n');
15+
}
16+
1017
addConnection(connection: Response): void {
1118
this._connections.push(connection);
19+
20+
this._write(connection, ClientEvents.CONNECTED, 1);
1221
}
1322

1423
emit(event: string, data?: unknown): void {
15-
this._connections.forEach(function(connection) {
16-
connection.write('event: ' + event + '\n');
17-
connection.write('data: ' + stringify(data) + '\n');
18-
connection.write('\n\n');
24+
this._connections.forEach((connection) => {
25+
this._write(connection, event, data);
1926
});
2027
}
2128
}

lib/static/modules/action-names.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,5 +78,6 @@ export default {
7878
SELECT_ALL: 'SELECT_ALL',
7979
DESELECT_ALL: 'DESELECT_ALL',
8080
SORT_TESTS_SET_CURRENT_EXPRESSION: 'SORT_TESTS_SET_CURRENT_EXPRESSION',
81-
SORT_TESTS_SET_DIRECTION: 'SORT_TESTS_SET_DIRECTION'
81+
SORT_TESTS_SET_DIRECTION: 'SORT_TESTS_SET_DIRECTION',
82+
SET_GUI_SERVER_CONNECTION_STATUS: 'SET_GUI_SERVER_CONNECTION_STATUS'
8283
} as const;
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import {Action} from '@/static/modules/actions/types';
2+
import actionNames from '@/static/modules/action-names';
3+
4+
type SetGuiServerConnectionStatusAction = Action<typeof actionNames.SET_GUI_SERVER_CONNECTION_STATUS, {
5+
isConnected: boolean;
6+
}>;
7+
export const setGuiServerConnectionStatus = (payload: SetGuiServerConnectionStatusAction['payload']): SetGuiServerConnectionStatusAction =>
8+
({type: actionNames.SET_GUI_SERVER_CONNECTION_STATUS, payload});
9+
10+
export type GuiServerConnectionAction = SetGuiServerConnectionStatusAction;

lib/static/modules/actions/types.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {State} from '@/static/new-ui/types/store';
88
import {LifecycleAction} from '@/static/modules/actions/lifecycle';
99
import {SuitesPageAction} from '@/static/modules/actions/suites-page';
1010
import {SortTestsAction} from '@/static/modules/actions/sort-tests';
11+
import {GuiServerConnectionAction} from '@/static/modules/actions/gui-server-connection';
1112

1213
export type {Dispatch} from 'redux';
1314

@@ -23,5 +24,6 @@ export type AppThunk<ReturnType = Promise<void>> = ThunkAction<ReturnType, State
2324
export type SomeAction =
2425
| GroupTestsAction
2526
| LifecycleAction
27+
| SortTestsAction
2628
| SuitesPageAction
27-
| SortTestsAction;
29+
| GuiServerConnectionAction;

lib/static/modules/default-state.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,9 @@ export default Object.assign({config: configDefaults}, {
126126
availableExpressions: [],
127127
currentExpressionIds: [],
128128
currentDirection: SortDirection.Asc
129+
},
130+
guiServerConnection: {
131+
isConnected: false
129132
}
130133
},
131134
ui: {
@@ -139,5 +142,6 @@ export default Object.assign({config: configDefaults}, {
139142
staticImageAccepterToolbar: {
140143
offset: {x: 0, y: 0}
141144
}
142-
}
145+
},
146+
timestamp: 0
143147
}) satisfies State;
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import {State} from '@/static/new-ui/types/store';
2+
import {SomeAction} from '@/static/modules/actions/types';
3+
import actionNames from '@/static/modules/action-names';
4+
import {applyStateUpdate} from '@/static/modules/utils';
5+
6+
export default (state: State, action: SomeAction): State => {
7+
switch (action.type) {
8+
case actionNames.SET_GUI_SERVER_CONNECTION_STATUS: {
9+
return applyStateUpdate(state, {
10+
app: {
11+
guiServerConnection: {
12+
isConnected: action.payload.isConnected
13+
}
14+
}
15+
});
16+
}
17+
default:
18+
return state;
19+
}
20+
};

lib/static/modules/reducers/index.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import visualChecksPage from './visual-checks-page';
3131
import isInitialized from './is-initialized';
3232
import newUiGroupedTests from './new-ui-grouped-tests';
3333
import sortTests from './sort-tests';
34+
import guiServerConnection from './gui-server-connection';
3435

3536
// The order of specifying reducers is important.
3637
// At the top specify reducers that does not depend on other state fields.
@@ -66,5 +67,6 @@ export default reduceReducers(
6667
progressBar,
6768
suitesPage,
6869
visualChecksPage,
69-
isInitialized
70+
isInitialized,
71+
guiServerConnection
7072
);

lib/static/new-ui/app/gui.tsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import {ClientEvents} from '@/gui/constants';
55
import {App} from './App';
66
import store from '../../modules/store';
77
import {finGuiReport, thunkInitGuiReport, suiteBegin, testBegin, testResult, testsEnd} from '../../modules/actions';
8+
import {setGuiServerConnectionStatus} from '@/static/modules/actions/gui-server-connection';
9+
import actionNames from '@/static/modules/action-names';
810

911
const rootEl = document.getElementById('app') as HTMLDivElement;
1012
const root = createRoot(rootEl);
@@ -13,6 +15,20 @@ function Gui(): ReactNode {
1315
const subscribeToEvents = (): void => {
1416
const eventSource = new EventSource('/events');
1517

18+
eventSource.addEventListener(ClientEvents.CONNECTED, (): void => {
19+
store.dispatch({type: actionNames.UPDATE_LOADING_VISIBILITY, payload: false});
20+
21+
store.dispatch(setGuiServerConnectionStatus({isConnected: true}));
22+
});
23+
24+
eventSource.onerror = (): void => {
25+
store.dispatch({type: actionNames.UPDATE_LOADING_IS_IN_PROGRESS, payload: true});
26+
store.dispatch({type: actionNames.UPDATE_LOADING_TITLE, payload: 'Lost connection to Testplane UI server. Trying to reconnect'});
27+
store.dispatch({type: actionNames.UPDATE_LOADING_VISIBILITY, payload: true});
28+
29+
store.dispatch(setGuiServerConnectionStatus({isConnected: false}));
30+
};
31+
1632
eventSource.addEventListener(ClientEvents.BEGIN_SUITE, (e) => {
1733
const data = JSON.parse(e.data);
1834
store.dispatch(suiteBegin(data));
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
.container {
2+
background-color: #fff;
3+
padding: 20px;
4+
width: 440px;
5+
height: 100%;
6+
overflow-x: scroll;
7+
8+
--g-text-body-font-weight: 450;
9+
--g-text-body-short-font-size: 15px;
10+
}
11+
12+
.divider {
13+
margin: 12px 0 20px 0;
14+
}

0 commit comments

Comments
 (0)