Skip to content

Commit 41d97f9

Browse files
committed
Add rule creation & HAR export to multiselect
1 parent f47b137 commit 41d97f9

2 files changed

Lines changed: 79 additions & 2 deletions

File tree

src/components/account/pro-placeholders.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,14 +115,15 @@ const OverlayGetProButton = styled(GetProButton)`
115115

116116
@observer
117117
export class GetProOverlay extends React.Component<{
118+
className?: string,
118119
getPro: (source: string) => void,
119120
source: string,
120121
children: React.ReactNode
121122
}> {
122123
private buttonRef = React.createRef<HTMLButtonElement>();
123124

124125
render() {
125-
return <OverlayContainer>
126+
return <OverlayContainer className={this.props.className}>
126127
<OverlayGetProButton
127128
ref={this.buttonRef}
128129
onClick={() => this.props.getPro(this.props.source)}

src/components/view/multi-selection-summary-pane.tsx

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
import * as React from 'react';
2+
import * as dateFns from 'date-fns';
23
import { inject, observer } from 'mobx-react';
34

45
import { css, styled } from '../../styles';
5-
import { Ctrl } from '../../util/ui';
6+
import { Ctrl, saveFile } from '../../util/ui';
67
import { CollectedEvent } from '../../types';
78
import { AccountStore } from '../../model/account/account-store';
9+
import { generateHar } from '../../model/http/har';
810

911
import { Icon } from '../../icons';
1012
import { Button } from '../common/inputs';
13+
import { GetProOverlay } from '../account/pro-placeholders';
1114

1215
import { getEventPreviewContent, getEventMarkerColor, isOpaqueConnection } from './event-rows/event-row';
1316

@@ -133,6 +136,29 @@ const PinIcon = styled(Icon).attrs({
133136
`}
134137
`;
135138

139+
const ProDivider = styled.hr`
140+
width: 100%;
141+
margin: 36px 0;
142+
border: none;
143+
border: solid 1px ${p => p.theme.mainColor};
144+
`;
145+
146+
const ProActionsContainer = styled.div`
147+
display: flex;
148+
flex-direction: column;
149+
align-items: stretch;
150+
gap: 10px;
151+
width: 100%;
152+
`;
153+
154+
const ProActionsOverlay = styled(GetProOverlay)`
155+
min-height: 0;
156+
157+
> button {
158+
top: 50%;
159+
}
160+
`;
161+
136162
const PREVIEW_COUNT = 10;
137163

138164
export const MultiSelectionSummaryPane = inject('accountStore')(observer((props: {
@@ -144,6 +170,11 @@ export const MultiSelectionSummaryPane = inject('accountStore')(observer((props:
144170
}) => {
145171
const { selectedEvents } = props;
146172
const count = selectedEvents.length;
173+
const isPaidUser = props.accountStore!.user.isPaidUser();
174+
175+
const httpCount = selectedEvents.filter(e =>
176+
e.isHttp() && !e.isWebSocket()
177+
).length;
147178

148179
const allHttp = count > 0 && selectedEvents.every(e => e.isHttp());
149180
const allPinned = selectedEvents.every(e => e.pinned);
@@ -153,6 +184,36 @@ export const MultiSelectionSummaryPane = inject('accountStore')(observer((props:
153184
// Reverse so the most recent is the front card (index 0).
154185
const previewEvents = selectedEvents.slice(-PREVIEW_COUNT).reverse();
155186

187+
const proButtons = <>
188+
<ActionButton
189+
title={isPaidUser ? `(${Ctrl}+M)` : 'Requires HTTP Toolkit Pro'}
190+
disabled={!isPaidUser || httpCount === 0}
191+
onClick={props.onBuildRule}
192+
>
193+
<Icon icon='Pencil' fixedWidth />
194+
Create {httpCount} Matching Rule{httpCount !== 1 ? 's' : ''}
195+
</ActionButton>
196+
<ActionButton
197+
title={isPaidUser
198+
? 'Export selected exchanges as a HAR file'
199+
: 'With Pro: export as HAR'
200+
}
201+
disabled={!isPaidUser || count === 0}
202+
onClick={async () => {
203+
const harContent = JSON.stringify(
204+
await generateHar(selectedEvents)
205+
);
206+
const filename = `HTTPToolkit_${
207+
dateFns.format(Date.now(), 'YYYY-MM-DD_HH-mm')
208+
}.har`;
209+
saveFile(filename, 'application/har+json;charset=utf-8', harContent);
210+
}}
211+
>
212+
<Icon icon={['fas', 'save']} fixedWidth />
213+
Export as HAR
214+
</ActionButton>
215+
</>;
216+
156217
return <SummaryContainer>
157218
<PreviewStack>
158219
{previewEvents.map((event, index) => {
@@ -185,6 +246,21 @@ export const MultiSelectionSummaryPane = inject('accountStore')(observer((props:
185246
<Icon icon={['far', 'trash-alt']} fixedWidth />
186247
Delete {count} {label}{count !== 1 ? 's' : ''}
187248
</ActionButton>
249+
250+
{ isPaidUser
251+
? proButtons
252+
: <>
253+
<ProDivider />
254+
<ProActionsOverlay
255+
getPro={props.accountStore!.getPro}
256+
source='multi-selection-pane'
257+
>
258+
<ProActionsContainer>
259+
{proButtons}
260+
</ProActionsContainer>
261+
</ProActionsOverlay>
262+
</>
263+
}
188264
</ActionsContainer>
189265
</SummaryContainer>;
190266
}));

0 commit comments

Comments
 (0)