Skip to content

Commit 20d53a7

Browse files
authored
Merge pull request #335 from HDI-Project/expInfoDrop
Added experiment info dropdown in the header
2 parents db5982f + a3b6296 commit 20d53a7

File tree

7 files changed

+171
-6
lines changed

7 files changed

+171
-6
lines changed

client/src/components/Header/Header.tsx

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import React from 'react';
1+
import React, { useState } from 'react';
22
import './header.scss';
33
import { connect } from 'react-redux';
4-
import { Link, useHistory } from 'react-router-dom';
4+
import { Link, useLocation } from 'react-router-dom';
55
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
6-
import { faChevronRight, faChevronLeft } from '@fortawesome/free-solid-svg-icons';
6+
import { faChevronRight, faChevronLeft, faCaretDown } from '@fortawesome/free-solid-svg-icons';
7+
import { getCurrentExperimentDetails } from 'src/model/selectors/experiment';
78
import { getSelectedExperiment } from '../../model/selectors/projects';
89
import { onUserLogoutAction } from '../../model/actions/users';
910
import { RootState } from '../../model/types';
@@ -14,13 +15,28 @@ type Props = StateProps & DispatchProps;
1415

1516
export const Header: React.FC<Props> = (props) => {
1617
const isSwitchVisible = props.selectedExperimentID ? 'active' : '';
17-
let history = useHistory();
18-
const currentView = history.location.pathname;
18+
const { experimentDetails } = props;
19+
let location = useLocation();
20+
21+
const currentView = location.pathname;
1922
const linkTo = currentView === '/' ? `/experiment/${props.selectedExperimentID}` : '/';
23+
2024
const logoutUser = () => {
2125
props.userLogout();
2226
window.location.href = '/';
2327
};
28+
29+
const [isInfoOpen, toggleInfo] = useState(false);
30+
const activeClass = isInfoOpen ? 'active' : '';
31+
32+
window.addEventListener('click', (evt: any) => {
33+
if (currentView === '/') {
34+
return null;
35+
}
36+
const dropdown = document.querySelector('.exp-info');
37+
dropdown && !dropdown.contains(evt.target) && toggleInfo(false);
38+
});
39+
2440
return (
2541
<header id="header" className="main-header">
2642
<div className="header-container">
@@ -30,6 +46,37 @@ export const Header: React.FC<Props> = (props) => {
3046
<Link to={linkTo} className={`page-switch-btn ${isSwitchVisible}`}>
3147
<FontAwesomeIcon icon={currentView === '/' ? faChevronRight : faChevronLeft} />
3248
</Link>
49+
{currentView !== '/' && (
50+
<div className="exp-info" onClick={() => toggleInfo(!isInfoOpen)}>
51+
<ul>
52+
<li className={activeClass}>
53+
Details
54+
<span>
55+
<FontAwesomeIcon icon={faCaretDown} />
56+
</span>
57+
<ul>
58+
<li>
59+
<span>Pipeline:</span>
60+
<span>{experimentDetails.pipeline}</span>
61+
</li>
62+
<li>
63+
<span>Dataset:</span>
64+
<span>{experimentDetails.dataset}</span>
65+
</li>
66+
<li>
67+
<span>By:</span>
68+
<span>{experimentDetails.created_by || 'Unknown'}</span>
69+
</li>
70+
<li>
71+
<span>Project:</span>
72+
<span>{experimentDetails.project}</span>
73+
</li>
74+
</ul>
75+
</li>
76+
</ul>
77+
</div>
78+
)}
79+
3380
<ul className="user-opts">
3481
<li>
3582
<button type="button" onClick={logoutUser} className="logout-button">
@@ -44,6 +91,7 @@ export const Header: React.FC<Props> = (props) => {
4491

4592
const mapState = (state: RootState) => ({
4693
selectedExperimentID: getSelectedExperiment(state),
94+
experimentDetails: getCurrentExperimentDetails(state),
4795
});
4896

4997
const mapDispatch = (dispatch: Function) => ({

client/src/components/Header/header.scss

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,4 +70,91 @@
7070
cursor: pointer;
7171
outline: none;
7272
}
73+
74+
.exp-info{
75+
float: left;
76+
font-family: 'Roboto';
77+
78+
ul{
79+
width: 200px;
80+
display: inline-block;
81+
font-size: 16px;
82+
border: 1px solid rgba(151,151,151,0.5);
83+
border-radius: 4px;
84+
box-shadow: 0 2px 4px -1px rgba(0,0,0,0.2), 0 4px 5px 0 rgba(0,0,0,0.14), 0 1px 10px 0 rgba(0,0,0,0.12);
85+
padding: 5px 15px;
86+
margin: 8px 0 0 50px;
87+
cursor: pointer;
88+
font-weight: bold;
89+
background: #282A30;
90+
91+
&:hover{
92+
span{
93+
path{
94+
fill: #fff;
95+
}
96+
}
97+
}
98+
99+
li{
100+
position: relative;
101+
102+
span{
103+
float: right;
104+
105+
path{
106+
fill: #979797;
107+
transition: all .2s ease-in-out;
108+
}
109+
110+
&:last-child{
111+
font-weight: normal;
112+
}
113+
}
114+
115+
ul{
116+
border-top-left-radius: 0;
117+
border-top-right-radius: 0;
118+
border-top: none;
119+
position: absolute;
120+
left: -16px;
121+
margin: 4px 0 0 0;
122+
z-index: -100;
123+
padding: 10px 15px;
124+
transition: all .2s ease-in-out;
125+
opacity: 0;
126+
top: 21px;
127+
}
128+
129+
&.active{
130+
border-bottom: none;
131+
box-shadow: none;
132+
133+
ul{
134+
z-index: 1;
135+
opacity: 1;
136+
}
137+
138+
span{
139+
path{
140+
fill: #fff;
141+
}
142+
}
143+
}
144+
145+
li{
146+
display: flex;
147+
cursor: initial;
148+
font-size: 14px;
149+
text-transform: none;
150+
margin-bottom: 8px;
151+
152+
span{
153+
flex: 1;
154+
}
155+
}
156+
}
157+
}
158+
159+
}
73160
}

client/src/model/actions/datarun.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ export function saveEventDetailsAction() {
183183
eventUpdateStatus: 'success',
184184
});
185185

186+
// @TODO - make a sinle API call with find instead of all
186187
await API.events.all('events').then((response) => {
187188
const { events } = response;
188189
const datarun = getDatarunDetails(getState());

client/src/model/actions/landing.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
FETCH_DATARUNS_BY_EXPERIMENT_ID,
1919
FecthDatarunsByExperimentIDAction,
2020
SELECT_DATARUN,
21+
FETCH_EXPERIMENT_DATA,
2122
} from '../types';
2223

2324
export function fetchExperiments() {
@@ -99,13 +100,22 @@ export function selectPipeline(selectedPipelineName: string) {
99100
}
100101

101102
export function selectExperiment(history: any, experimentID: string) {
102-
return function (dispatch) {
103+
return async function (dispatch) {
104+
// @TODO - combine this action with fetchExpAction
103105
const action: SelectExperimentAction = {
104106
type: SELECT_EXPERIMENT,
105107
selectedExperimentID: experimentID,
106108
};
107109

108110
dispatch(action);
111+
112+
const fetchExpAction = {
113+
type: FETCH_EXPERIMENT_DATA,
114+
promise: API.experiments.find(`${experimentID}/`),
115+
};
116+
117+
dispatch(fetchExpAction);
118+
109119
dispatch({
110120
type: SELECT_DATARUN,
111121
datarunID: '',

client/src/model/reducers/experiments.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ const initialState: ExperimentState = {
55
isExperimentsLoading: true,
66
experimentsList: [],
77
selectedExperimentID: null,
8+
isExperimentDataLoading: true,
9+
experimentDetails: [],
810
};
911

1012
function FETCH_EXPERIMENTS_REQUEST(nextState: ExperimentState) {
@@ -22,6 +24,16 @@ function FETCH_EXPERIMENTS_FAILURE(nextState: ExperimentState) {
2224
nextState.experimentsList = [];
2325
}
2426

27+
function FETCH_EXPERIMENT_DATA_SUCCESS(nextState, action) {
28+
nextState.isExperimentDataLoading = false;
29+
nextState.experimentDetails = action.result;
30+
}
31+
32+
function FETCH_EXPERIMENT_DATA_FAILURE(nextState) {
33+
nextState.isExperimentDataLoading = false;
34+
nextState.experimentDetails = [];
35+
}
36+
2537
function SELECT_EXPERIMENT(nextState: ExperimentState, action: SelectExperimentAction) {
2638
nextState.selectedExperimentID = action.selectedExperimentID;
2739
}
@@ -31,4 +43,6 @@ export default createReducer<ExperimentState>(initialState, {
3143
FETCH_EXPERIMENTS_SUCCESS,
3244
FETCH_EXPERIMENTS_FAILURE,
3345
SELECT_EXPERIMENT,
46+
FETCH_EXPERIMENT_DATA_SUCCESS,
47+
FETCH_EXPERIMENT_DATA_FAILURE,
3448
});

client/src/model/selectors/experiment.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,3 +245,5 @@ export const getProcessedMatrixData = createSelector([getFilteredExperiments], (
245245

246246
return { scale, tagStats: tagStatsList[0] };
247247
});
248+
249+
export const getCurrentExperimentDetails = (state) => state.experiments.experimentDetails;

client/src/model/types/experiment.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { DatarunDataType } from './datarun';
22

33
export const FETCH_EXPERIMENTS = 'FETCH_EXPERIMENTS';
44
export const SELECT_EXPERIMENT = 'SELECT_EXPERIMENT';
5+
export const FETCH_EXPERIMENT_DATA = 'FETCH_EXPERIMENT_DATA';
56

67
export type FetchExperimentsAction = {
78
type: typeof FETCH_EXPERIMENTS;
@@ -22,6 +23,8 @@ export type ExperimentState = {
2223
isExperimentsLoading: boolean;
2324
experimentsList: ExperimentDataType[];
2425
selectedExperimentID: string;
26+
isExperimentDataLoading: boolean;
27+
experimentDetails: ExperimentDataType[];
2528
};
2629

2730
/**

0 commit comments

Comments
 (0)