Skip to content

Commit e73668b

Browse files
authored
Add status filter and buttons to pause and export (#134)
* add status filter dropdown and action buttons to pause and export * update test snapshots * use entry.connection as index
1 parent d8de327 commit e73668b

36 files changed

+2683
-1154
lines changed
+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import React from 'react';
2+
import FileSaver from 'file-saver';
3+
import PropTypes from 'prop-types';
4+
5+
import Button from '../Common/Button';
6+
import Styles from './IconButton.styles.scss';
7+
import IconDownload from '../../icons/IconDownload';
8+
9+
const ExportHarButton = ({ rawData }) => {
10+
const downloadHar = () => {
11+
const formattedHar = JSON.stringify(rawData, null, 4);
12+
13+
FileSaver.saveAs(new Blob([formattedHar]), 'network.har');
14+
};
15+
16+
return (
17+
<Button
18+
className={Styles['icon-button']}
19+
onClick={downloadHar}
20+
>
21+
<IconDownload className={Styles['action-icon']} />
22+
</Button>
23+
);
24+
};
25+
26+
ExportHarButton.propTypes = {
27+
rawData: PropTypes.string,
28+
};
29+
30+
ExportHarButton.defaultProps = {
31+
rawData: '',
32+
};
33+
34+
export default ExportHarButton;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
@import "./../../styles/variables";
2+
3+
.icon-button {
4+
padding: $size-xs $size-xs-s;
5+
height: $filter-button-height;
6+
7+
.action-icon {
8+
fill: $brand-primary-dark-gray;
9+
height: $size-s;
10+
width: $size-s;
11+
}
12+
}
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import React from 'react';
2+
3+
import Button from '../Common/Button';
4+
import Styles from './IconButton.styles.scss';
5+
import IconUpload from '../../icons/IconImport';
6+
7+
const ImportHarButton = () => (
8+
<Button className={Styles['icon-button']}>
9+
<IconUpload className={Styles['action-icon']} />
10+
</Button>
11+
);
12+
13+
export default ImportHarButton;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import React, { useState } from 'react';
2+
3+
import Button from '../Common/Button';
4+
import Styles from './IconButton.styles.scss';
5+
import IconPause from '../../icons/IconPause';
6+
import { useNetwork } from '../../state/network/Context';
7+
import IconResume from '../../icons/IconResume';
8+
9+
const PauseResumeButton = () => {
10+
const { callbacks } = useNetwork();
11+
const [isPaused, setIsPaused] = useState(false);
12+
13+
const pause = () => {
14+
setIsPaused(true);
15+
callbacks.onPause();
16+
};
17+
18+
const resume = () => {
19+
setIsPaused(false);
20+
callbacks.onResume();
21+
};
22+
23+
return (
24+
<Button
25+
className={Styles['icon-button']}
26+
onClick={isPaused ? resume : pause}
27+
>
28+
{isPaused ?
29+
<IconResume className={Styles['action-icon']} /> :
30+
<IconPause className={Styles['action-icon']} />}
31+
</Button>
32+
);
33+
};
34+
35+
export default PauseResumeButton;
+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import React from 'react';
2+
3+
import Button from '../Common/Button';
4+
import IconReset from '../../icons/IconReset';
5+
import Styles from './IconButton.styles.scss';
6+
import { useNetwork } from '../../state/network/Context';
7+
8+
const ResetButton = () => {
9+
const { actions, callbacks } = useNetwork();
10+
11+
const handleReset = () => {
12+
window.history.pushState({}, document.title, '/');
13+
actions.resetState();
14+
callbacks.onReset();
15+
};
16+
17+
return (
18+
<Button
19+
className={Styles['icon-button']}
20+
onClick={handleReset}
21+
>
22+
<IconReset className={Styles['action-icon']} />
23+
</Button>
24+
);
25+
};
26+
27+
export default ResetButton;

src/Components/Filters/ErrorFilter.jsx

-27
This file was deleted.
+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import React from 'react';
2+
3+
import Dropdown from '../Common/Dropdown';
4+
import { useNetwork } from '../../state/network/Context';
5+
import { STATUS_FILTERS } from '../../constants';
6+
7+
const StatusFilter = () => {
8+
const { state, actions } = useNetwork();
9+
const filter = state.get('statusFilter');
10+
11+
return (
12+
<Dropdown
13+
items={STATUS_FILTERS}
14+
onChange={actions.updateStatusFilter}
15+
selected={filter}
16+
/>
17+
);
18+
};
19+
20+
export default StatusFilter;

src/Components/Filters/TypeFilter.jsx

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import React from 'react';
2+
import classNames from 'classnames/bind';
3+
4+
import { useNetwork } from '../../state/network/Context';
5+
import Button from '../Common/Button';
6+
import { TYPE_FILTERS } from '../../constants';
7+
import Styles from '../../Containers/FilterContainer.styles.scss';
8+
9+
const context = classNames.bind(Styles);
10+
11+
const TypeFilter = () => {
12+
const { state, actions } = useNetwork();
13+
const filter = state.get('typeFilter');
14+
15+
return TYPE_FILTERS.map(({ name, filterBy }) => {
16+
const selectedFilter = filterBy.value === filter.value;
17+
18+
return (
19+
<Button
20+
key={name}
21+
className={context({ active: selectedFilter })}
22+
onClick={() => actions.updateTypeFilter(filterBy)}
23+
variant="text"
24+
>
25+
{name}
26+
</Button>
27+
);
28+
});
29+
};
30+
31+
export default TypeFilter;

src/Components/Import/ImportHAR.jsx

+5-7
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import { useDropzone } from 'react-dropzone';
55
import { useNetwork } from './../../state/network/Context';
66
import Styles from './ImportHAR.styles.scss';
77
import Button from './../Common/Button';
8+
import IconUpload from '../../icons/IconImport';
9+
import ImportHarButton from '../Actions/ImportHarButton';
810

911
const DROP_FILE_CONFIG = {
1012
accept: '.har',
@@ -45,13 +47,9 @@ const ImportHar = ({ showButton, className }) => {
4547
return (
4648
<div {...getRootProps()}>
4749
<input {...getInputProps()} />
48-
{showButton ? (
49-
<Button className={className}>
50-
Import HAR
51-
</Button>
52-
) : (
53-
<p className={Styles['drag-drop']}>Drag and drop HAR file here, or click to select file</p>
54-
)}
50+
{showButton ?
51+
(<ImportHarButton />) :
52+
(<p className={Styles['drag-drop']}>Drag and drop HAR file here, or click to select file</p>)}
5553
</div>
5654
);
5755
};

src/Components/Import/Reset.jsx

-35
This file was deleted.

src/Components/NetworkTable/NetworkTableFooter.styles.scss

+4-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
position: absolute;
66
bottom: 0;
77
width: 100%;
8-
background: $white-97;
9-
padding: $size-xs * 2;
8+
background: $bg-gray-90;
9+
padding: $size-xs-s $size-s;
1010
display: inline-flex;
1111
vertical-align: middle;
1212

@@ -16,6 +16,8 @@
1616
display: inline-flex;
1717
align-items: center;
1818
border-right: 1px solid $white-80;
19+
padding: 0 $size-xs;
20+
overflow: hidden;
1921

2022
&:last-child {
2123
border-right: none;

src/Containers/FilterContainer.jsx

+15-45
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,35 @@
11
import React from 'react';
2-
import classNames from 'classnames/bind';
32

4-
import ImportHar from './../Components/Import/ImportHAR';
53
import Search from './../Components/Filters/Search';
6-
import { useNetwork } from './../state/network/Context';
7-
import { FILTERS } from './../constants';
84
import Styles from './FilterContainer.styles.scss';
9-
import Button from './../Components/Common/Button';
5+
import ResetButton from '../Components/Actions/ResetButton';
6+
import StatusFilter from '../Components/Filters/StatusFilter';
7+
import ExportHarButton from '../Components/Actions/ExportHarButton';
8+
import PauseResumeButton from '../Components/Actions/PauseResumeButton';
9+
import TypeFilter from '../Components/Filters/TypeFilter';
10+
import ImportHAR from '../Components/Import/ImportHAR';
1011
import { useTheme } from '../state/theme/Context';
11-
import ErrorFilter from '../Components/Filters/ErrorFilter';
12-
import Reset from '../Components/Import/Reset';
13-
14-
const context = classNames.bind(Styles);
12+
import { useNetwork } from '../state/network/Context';
1513

1614
const FilterContainer = () => {
17-
const { state, actions } = useNetwork();
18-
const { showImportHAR } = useTheme();
19-
const filter = state.get('filter');
20-
const filterByError = state.get('errorFilter');
15+
const { state } = useNetwork();
16+
const { showImportHar, showExportHar, showPauseResume } = useTheme();
2117

2218
return (
2319
<section className={Styles['filters-container']}>
2420
<div className={Styles['filter-row']}>
21+
<StatusFilter />
2522
<Search {...state.get('search')} />
23+
{showPauseResume && <PauseResumeButton {...state.get('rawData')} />}
24+
<ResetButton />
25+
{showExportHar && <ExportHarButton />}
26+
{showImportHar && <ImportHAR />}
2627
</div>
2728

2829
<div className={Styles['type-filter-row']}>
29-
<>
30-
{FILTERS.map(({ name, filterBy }) => {
31-
const selectedFilter = filterBy.value === filter.value;
32-
const buttonStyle = context('filter-button', {
33-
'selected-filter': selectedFilter,
34-
});
35-
return (
36-
<Button
37-
key={name}
38-
className={buttonStyle}
39-
onClick={() => actions.updateFilter(filterBy)}
40-
size="sm"
41-
>
42-
{name}
43-
</Button>
44-
);
45-
})}
46-
<ErrorFilter
47-
isError={filterByError}
48-
onChange={actions.updateErrorFilter}
49-
/>
50-
{showImportHAR && (
51-
<>
52-
<ImportHar className={Styles['addon-action-button']} />
53-
<Reset
54-
className={Styles['addon-action-button']}
55-
onReset={actions.resetState}
56-
/>
57-
</>
58-
)}
59-
</>
30+
<TypeFilter />
6031
</div>
6132
</section>
62-
6333
);
6434
};
6535

src/Containers/NetworkTableContainer.jsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import PropTypes from 'prop-types';
55
import NetworkTableHeader from './../Components/NetworkTable/NetworkTableHeader';
66
import NetworkTableRow from './../Components/NetworkTable/NetworkTableRow';
77
import { useNetwork } from './../state/network/Context';
8-
import ImportHar from './../Components/Import/ImportHAR';
8+
import ImportHar from '../Components/Import/ImportHAR';
99
import Styles from './NetworkTableContainer.styles.scss';
1010
import ErrorMessage from './../Components/ErrorMessage';
1111
import { useTheme } from '../state/theme/Context';
@@ -15,7 +15,7 @@ const context = classNames.bind(Styles);
1515

1616
const NetworkTableContainer = ({ onRequestSelect }) => {
1717
const { state, actions } = useNetwork();
18-
const { showImportHAR } = useTheme();
18+
const { showImportHar } = useTheme();
1919
const actualData = state.get('actualData');
2020
const data = state.get('data');
2121
const totalNetworkTime = state.get('totalNetworkTime');
@@ -40,7 +40,7 @@ const NetworkTableContainer = ({ onRequestSelect }) => {
4040
if (!actualData.size) {
4141
return (
4242
<section className={Styles['table-container']}>
43-
{showImportHAR && (
43+
{showImportHar && (
4444
<>
4545
<ImportHar showButton={false} />
4646
<InputHAR />

0 commit comments

Comments
 (0)