Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Copy All Button for Response #145

Merged
merged 5 commits into from
Aug 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions config/rollup/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export const postcssPlugin = (options = {}) => (
autoModules: false,
modules: {
generateScopedName: '[name]__[local]___[hash:base64:5]',
hashPrefix: 'prefix',
},
...options,
})
Expand Down
7 changes: 3 additions & 4 deletions src/Components/NetworkTable/NetworkTable.styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
border-top: $border;
}


.network-table-header {
display: flex;
width: 100%;
Expand All @@ -27,13 +26,14 @@
width: 12%;
align-self: center;
padding-right: $size-xs-s;
min-width: $table-column-min-width;

&:last-child {
padding-right: 0;
}

&.show-waterfall {
width: 9%;
width: 10%;
}

&.file {
Expand All @@ -44,8 +44,7 @@
}
}

&.domain,
&.waterfall{
&.domain {
width: 15%;
}
}
Expand Down
16 changes: 12 additions & 4 deletions src/Components/NetworkTable/NetworkTableBody.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import NetworkTableRow from './NetworkTableRow';
import { TABLE_ENTRY_HEIGHT } from '../../constants';
import { useResizeObserver } from '../../hooks/useResizeObserver';
import Styles from './NetworkTable.styles.scss';
import { useTheme } from '../../state/theme/Context';

/* eslint no-underscore-dangle: 0 */

Expand Down Expand Up @@ -41,19 +42,26 @@ const NetworkTableBody = ({ height }) => {
actions,
callbacks,
} = useNetwork();
const { enableAutoScroll } = useTheme();
const numberOfNewEntries = state.get('numberOfNewEntries');
const data = state.get('data');
const totalNetworkTime = state.get('totalNetworkTime');
const selectedReqIndex = state.get('selectedReqIndex');

const ref = useRef(null);
const { elementDims } = useResizeObserver(ref);
const { elementDims } = useResizeObserver(ref?.current?._outerRef || ref?.current);

useEffect(() => actions.setTableHeaderWidth(elementDims.width), [elementDims]);

useEffect(() => {
const outerRef = ref?.current?._outerRef;
if (outerRef.scrollTop + outerRef.offsetHeight + TABLE_ENTRY_HEIGHT >= outerRef.scrollHeight) {
ref.current._outerRef.scrollTop = outerRef.scrollHeight;
if (enableAutoScroll && ref?.current?._outerRef) {
const outerRef = ref?.current?._outerRef;
const needToScroll = outerRef.scrollTop +
outerRef.offsetHeight +
(numberOfNewEntries * TABLE_ENTRY_HEIGHT) >= outerRef.scrollHeight;
if (needToScroll) {
ref.current._outerRef.scrollTop = outerRef.scrollHeight;
}
}
}, [data, ref]);

Expand Down
5 changes: 1 addition & 4 deletions src/Components/NetworkTable/TimeChart.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,7 @@ const TimeChart = ({
placement="left"
title={<TimeChartTooltip data={timings} />}
>
<svg
{...TIME_CHART_SVG_PROPS}
className={Styles['time-chart']}
>
<svg {...TIME_CHART_SVG_PROPS}>
<g>
{chartAttributes.map((chartProps) => (
<rect
Expand Down
4 changes: 0 additions & 4 deletions src/Components/NetworkTable/TimeChart.styles.scss
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
@import "./../../styles/variables.scss";

.time-chart {
height: 15px;
}

.time-chart-tooltip {
background-color: $white-100 !important;
overflow: hidden !important;
Expand Down
48 changes: 48 additions & 0 deletions src/Components/ReqDetail/CopyAllButton.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import React, { useRef, useState } from 'react';
import PropTypes from 'prop-types';

import Button from '../Common/Button';
import Styles from './CopyAllButton.styles.scss';
import IconCopy from '../../icons/IconCopy';
import IconCheckMark from '../../icons/IconCheckMark';

const CopyAllButton = ({ text }) => {
const [isCopied, setIsCopied] = useState(false);
const timeoutRef = useRef(null);

const copy = () => {
navigator.clipboard.writeText(text);
setIsCopied(true);

if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}

timeoutRef.current = setTimeout(() => {
setIsCopied(false);
}, 5000);
};

return (
<Button
className={Styles['copy-button']}
onClick={copy}
variant="text"
>
{isCopied ?
<IconCheckMark className={Styles['copy-icon']} /> :
<IconCopy className={Styles['copy-icon']} />}
<span className={Styles['copy-text']}>{isCopied ? 'Copied!' : 'Copy All'}</span>
</Button>
);
};

CopyAllButton.propTypes = {
text: PropTypes.object,
};

CopyAllButton.defaultProps = {
text: 'testi testi',
};

export default CopyAllButton;
17 changes: 17 additions & 0 deletions src/Components/ReqDetail/CopyAllButton.styles.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
@import "./../../styles/variables";

.copy-button {
height: $filter-button-height;
color: $brand-blue;
font-size: $font-size-h6;

.copy-text {
padding-left: $size-xs;
}

.copy-icon {
fill: $brand-blue;
height: $size-s;
width: $size-s;
}
}
8 changes: 6 additions & 2 deletions src/Components/ReqDetail/Response.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';

import Styles from './Response.styles.scss';
import CopyAllButton from './CopyAllButton';

const NoResponseText = () => (
<h4 className={Styles['no-response']}>This request has no response data available.</h4>
Expand All @@ -16,9 +17,12 @@ const Response = ({ data }) => {

return (
<div className={Styles['response-content']}>
<pre className={Styles['log-body-colorless']}>
<div className={Styles['copy-button']}>
<CopyAllButton text={content} />
</div>
<span className={Styles['response-body']}>
{content}
</pre>
</span>
</div>
);
};
Expand Down
12 changes: 12 additions & 0 deletions src/Components/ReqDetail/Response.styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,16 @@
.response-content {
font-size: $font-size-small;
width: 100%;
display: flex;
flex-direction: column;

.copy-button {
align-self: end;
}

.response-body {
font-family: monospace;
white-space: pre-wrap;
word-break: break-all;
}
}
4 changes: 2 additions & 2 deletions src/Components/ReqDetail/headers/General.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { GENERAL_HEADERS } from '../../../constants';
const General = ({ data }) => (
<div className={Styles['header-detail']}>
{Object.entries(GENERAL_HEADERS).map(([dataKey, { key, name }]) => (
<p
<div
key={dataKey}
className={Styles['info-row']}
>
Expand All @@ -17,7 +17,7 @@ const General = ({ data }) => (
<span className={Styles['info-value']}>
{key === 'status' && data.error ? data.error : data[key]}
</span>
</p>
</div>
))}
</div>
);
Expand Down
1 change: 1 addition & 0 deletions src/Containers/MainContainer.styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@
height: 100%;
width: 100%;
overflow: auto;
overflow-x: hidden;
outline: none;
}
2 changes: 1 addition & 1 deletion src/Containers/NetworkTableContainer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const NetworkTableContainer = () => {
if (ref?.current) {
setTableBodyHeight(ref.current.clientHeight - TABLE_HEADER_HEIGHT);
}
}, [ref]);
}, [ref, actualData]);

if (error) {
return (
Expand Down
1 change: 1 addition & 0 deletions src/Containers/ReqDetailContainer.styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -66,5 +66,6 @@ $tab-height: 35px;
padding: $size-s $size-m;
height: calc(100% - #{$tab-height});
overflow: auto;
outline: none;
}
}
8 changes: 5 additions & 3 deletions src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -227,14 +227,15 @@ export const TIMINGS = {
};

export const TIME_CHART_SVG_PROPS = {
viewBox: '0 0 250 20',
height: '15',
viewBox: '0 0 200 20',
version: '1.1',
preserveAspectRatio: 'xMinYMin meet',
};

export const TIME_CHART_DEFAULT_PROPS = {
height: 16,
y: 3.5,
height: 30,
y: 0,
};

export const ROW_ID_PREFIX = 'network-viewer-table-row-';
Expand Down Expand Up @@ -293,6 +294,7 @@ export const NETWORK_VIEWER_DEFAULT_OPTIONS = {
showPauseResume: false,
showTimeline: false,
showWaterfall: true,
enableAutoScroll: false,
};

export const PAYLOAD_CAPTIONS = Object.freeze({
Expand Down
16 changes: 7 additions & 9 deletions src/hooks/useResizeObserver.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,23 @@ export const useResizeObserver = (elementRef) => {
height: 0,
});
useEffect(() => {
const element = elementRef.current;

const onResize = () => {
if (element._outerRef) {
if (elementRef) {
setElementDims({
width: element._outerRef.clientWidth,
height: element._outerRef.clientHeight,
width: elementRef.clientWidth,
height: elementRef.clientHeight,
});
}
};
const resizeObserver = new ResizeObserver(onResize);

if (element._outerRef) {
resizeObserver.observe(element._outerRef);
if (elementRef) {
resizeObserver.observe(elementRef);
}

return () => {
if (element._outerRef) {
resizeObserver.unobserve(element._outerRef);
if (elementRef) {
resizeObserver.unobserve(elementRef);
}
};
}, [elementRef]);
Expand Down
28 changes: 28 additions & 0 deletions src/icons/IconCheckMark.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React from 'react';
import PropTypes from 'prop-types';

const IconCheckMark = ({ className }) => (
<svg
className={className}
height="24"
viewBox="0 0 24 24"
width="24"
xmlns="http://www.w3.org/2000/svg"
>
<path
clipRule="evenodd"
d="M23.5789 2.30868C24.0956 2.75821 24.1435 3.53404 23.6857 4.04153L7.48717 22L0.313554 14.0321C-0.143724 13.5242 -0.0951526 12.7485 0.42204 12.2994C0.939233 11.8503 1.7292 11.898 2.18648 12.4059L7.48892 18.2954L21.8143 2.41361C22.2721 1.90612 23.0621 1.85914 23.5789 2.30868Z"
fillRule="evenodd"
/>
</svg>
);

IconCheckMark.propTypes = {
className: PropTypes.string,
};

IconCheckMark.defaultProps = {
className: '',
};

export default IconCheckMark;
28 changes: 28 additions & 0 deletions src/icons/IconCopy.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React from 'react';
import PropTypes from 'prop-types';

const IconCopy = ({ className }) => (
<svg
className={className}
height="24"
viewBox="0 0 24 24"
width="24"
xmlns="http://www.w3.org/2000/svg"
>
<path
clipRule="evenodd"
d="M14.5 0C15.3284 0 16 0.671573 16 1.5V4H22C23.1046 4 24 4.89543 24 6V22C24 23.1046 23.1046 24 22 24H10C8.89543 24 8 23.1046 8 22V20H1.5C0.671572 20 0 19.3284 0 18.5V5.34711C0 4.93755 0.167468 4.5458 0.463528 4.2628L4.4882 0.415691C4.76731 0.148892 5.13856 0 5.52467 0H14.5ZM22 6V22H10V11.2H14.9999C15.2652 11.2 15.5195 11.0946 15.707 10.9071C15.8946 10.7195 15.9999 10.4652 15.9999 10.2V6H22ZM13.9999 6H13.7252L10.3775 9.19997H13.9999V6Z"
fillRule="evenodd"
/>
</svg>
);

IconCopy.propTypes = {
className: PropTypes.string,
};

IconCopy.defaultProps = {
className: '',
};

export default IconCopy;
5 changes: 5 additions & 0 deletions src/state/network/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const initialState = new Map({
showReqDetail: false,
reqDetail: null,
tableHeaderWidth: '100%',
numberOfNewEntries: 0,
});

const reducer = (state = initialState, {
Expand Down Expand Up @@ -58,11 +59,15 @@ const reducer = (state = initialState, {
search: state.get('search'),
});

const prevData = state.get('data');
const numberOfNewEntries = filteredData.size - prevData.size;

newState
.set('error', null)
.set('rawData', payload)
.set('data', filteredData)
.set('actualData', sortedData)
.set('numberOfNewEntries', numberOfNewEntries)
.set('totalNetworkTime', totalNetworkTime)
.set('dataSummary', new Map({
totalRequests,
Expand Down
Loading