mirror of
https://github.com/Kong/insomnia.git
synced 2026-04-22 07:08:16 -04:00
[INS-1979] Add disconnect dropdown (#5236)
* add disconnect dropdown * remove console * add style fix for ux * add e2e tests * rename * Simplify the smoke websocket smoke tests Co-authored-by: Filipe Freire <livrofubia@gmail.com>
This commit is contained in:
@@ -49,4 +49,13 @@ test('can make websocket connection', async ({ app, page }) => {
|
||||
await page.click('[data-testid="response-pane"] >> [role="tab"]:has-text("Timeline")');
|
||||
await expect(responseBody).toContainText('WebSocket connection established');
|
||||
|
||||
const webSocketActiveConnections = page.locator('[data-testid="WebSocketSpinner__Connected"]');
|
||||
|
||||
// Basic auth, Bearer auth, and Redirect connections are displayed as open
|
||||
await expect(webSocketActiveConnections).toHaveCount(3);
|
||||
|
||||
// Can disconnect from all connections
|
||||
await page.locator('button[name="DisconnectDropdown__DropdownButton"]').click();
|
||||
await page.locator('text=Disconnect all requests').click();
|
||||
await expect(webSocketActiveConnections).toHaveCount(0);
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { autoBindMethodsForReact } from 'class-autobind-decorator';
|
||||
import classnames from 'classnames';
|
||||
import React, { createElement, PureComponent, ReactNode } from 'react';
|
||||
import React, { ButtonHTMLAttributes, createElement, PureComponent, ReactNode } from 'react';
|
||||
|
||||
import { AUTOBIND_CFG } from '../../../../common/constants';
|
||||
|
||||
@@ -15,6 +15,7 @@ interface Props {
|
||||
children: ReactNode;
|
||||
className?: string;
|
||||
color?: string;
|
||||
unsetStyles?: boolean;
|
||||
}
|
||||
|
||||
@autoBindMethodsForReact(AUTOBIND_CFG)
|
||||
@@ -44,6 +45,7 @@ export class DropdownItem extends PureComponent<Props> {
|
||||
className,
|
||||
color,
|
||||
onClick,
|
||||
unsetStyles,
|
||||
// eslint-disable-line @typescript-eslint/no-unused-vars
|
||||
stayOpenAfterClick,
|
||||
// eslint-disable-line @typescript-eslint/no-unused-vars
|
||||
@@ -61,11 +63,16 @@ export class DropdownItem extends PureComponent<Props> {
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
const buttonProps = {
|
||||
const buttonProps: ButtonHTMLAttributes<HTMLButtonElement> = {
|
||||
type: 'button',
|
||||
onClick: this._handleClick,
|
||||
...props,
|
||||
};
|
||||
|
||||
if (unsetStyles) {
|
||||
buttonProps.className = 'dropdown__item-button-unset';
|
||||
}
|
||||
|
||||
return createElement(buttonClass || 'button', buttonProps, inner);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -337,5 +337,5 @@ export const SidebarRequestRow = DropTarget('SIDEBAR_REQUEST_ROW', dragTarget, t
|
||||
|
||||
const WebSocketSpinner = ({ requestId }: { requestId: string }) => {
|
||||
const readyState = useWSReadyState(requestId);
|
||||
return readyState === ReadyState.OPEN ? <ConnectionCircle /> : null;
|
||||
return readyState === ReadyState.OPEN ? <ConnectionCircle data-testid="WebSocketSpinner__Connected" /> : null;
|
||||
};
|
||||
|
||||
@@ -10,6 +10,7 @@ import { OneLineEditor } from '../codemirror/one-line-editor';
|
||||
import { useDocBodyKeyboardShortcuts } from '../keydown-binder';
|
||||
import { showAlert, showModal } from '../modals';
|
||||
import { RequestRenderErrorModal } from '../modals/request-render-error-modal';
|
||||
import { DisconnectButton } from './disconnect-button';
|
||||
|
||||
const Button = styled.button<{ warning?: boolean }>(({ warning }) => ({
|
||||
paddingRight: 'var(--padding-md)',
|
||||
@@ -161,7 +162,7 @@ export const WebSocketActionBar: FC<ActionBarProps> = ({ request, workspaceId, e
|
||||
</StyledUrlBar>
|
||||
{isConnectingOrClosed
|
||||
? <Button type="submit">Connect</Button>
|
||||
: <Button type="submit" warning>Disconnect</Button>}
|
||||
: <DisconnectButton requestId={request._id} />}
|
||||
</Form>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
import React, { FC, useRef } from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { Dropdown as OriginalDropdown, DropdownHandle } from '../base/dropdown/dropdown';
|
||||
import { DROPDOWN_BUTTON_DISPLAY_NAME, DropdownButton as OriginalDropdownButton } from '../base/dropdown/dropdown-button';
|
||||
import { DropdownItem } from '../base/dropdown/dropdown-item';
|
||||
|
||||
const SplitButton = styled.div({
|
||||
display: 'flex',
|
||||
color: 'var(--color-font-surprise)',
|
||||
});
|
||||
const Dropdown = styled(OriginalDropdown)({
|
||||
display: 'flex',
|
||||
textAlign: 'center',
|
||||
borderLeft: '1px solid var(--hl-md)',
|
||||
background: 'var(--color-danger)',
|
||||
':hover': {
|
||||
opacity: 0.9,
|
||||
},
|
||||
});
|
||||
const DropdownButton = styled(OriginalDropdownButton)({
|
||||
paddingRight: 'var(--padding-xs)',
|
||||
paddingLeft: 'var(--padding-xs)',
|
||||
});
|
||||
DropdownButton.displayName = DROPDOWN_BUTTON_DISPLAY_NAME;
|
||||
const ActionButton = styled.button({
|
||||
paddingRight: 'var(--padding-md)',
|
||||
paddingLeft: 'var(--padding-md)',
|
||||
background: 'var(--color-danger)',
|
||||
':hover': {
|
||||
opacity: 0.9,
|
||||
},
|
||||
});
|
||||
const Connections = styled.div({
|
||||
display: 'flex',
|
||||
justifyContent: 'space-evenly',
|
||||
width: 25,
|
||||
});
|
||||
const Connection = styled.div<{ size?: number }>(({ size = 10 }) => ({
|
||||
borderRadius: '50%',
|
||||
width: size,
|
||||
height: size,
|
||||
background: 'var(--color-success)',
|
||||
}));
|
||||
const TextWrapper = styled.div({
|
||||
textAlign: 'left',
|
||||
width: '100%',
|
||||
paddingLeft: 'var(--padding-xs)',
|
||||
});
|
||||
|
||||
export const DisconnectButton: FC<{ requestId: string }> = ({ requestId }) => {
|
||||
const dropdownRef = useRef<DropdownHandle>();
|
||||
const handleCloseThisRequest = () => {
|
||||
window.main.webSocket.close({ requestId });
|
||||
};
|
||||
const handleCloseAllRequests = () => {
|
||||
window.main.webSocket.closeAll();
|
||||
};
|
||||
return (
|
||||
<SplitButton>
|
||||
<ActionButton
|
||||
type="button"
|
||||
onClick={handleCloseThisRequest}
|
||||
>
|
||||
Disconnect
|
||||
</ActionButton>
|
||||
<Dropdown
|
||||
key="dropdown"
|
||||
className="tall"
|
||||
right
|
||||
data-testid="DisconnectDropdown__Dropdown"
|
||||
>
|
||||
<DropdownButton
|
||||
name="DisconnectDropdown__DropdownButton"
|
||||
onClick={() => dropdownRef.current?.show()}
|
||||
>
|
||||
<i className="fa fa-caret-down" />
|
||||
</DropdownButton>
|
||||
<DropdownItem unsetStyles onClick={handleCloseThisRequest}>
|
||||
<Connections>
|
||||
<Connection />
|
||||
</Connections>
|
||||
<TextWrapper>
|
||||
Disconnect this request
|
||||
</TextWrapper>
|
||||
</DropdownItem>
|
||||
<DropdownItem unsetStyles onClick={handleCloseAllRequests}>
|
||||
<Connections>
|
||||
<Connection size={5} />
|
||||
<Connection size={5} />
|
||||
<Connection size={5} />
|
||||
</Connections>
|
||||
<TextWrapper>
|
||||
Disconnect all requests
|
||||
</TextWrapper>
|
||||
</DropdownItem>
|
||||
</Dropdown>
|
||||
</SplitButton>
|
||||
);
|
||||
};
|
||||
@@ -126,7 +126,12 @@
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
li > .dropdown__item-button-unset {
|
||||
min-width: unset;
|
||||
.dropdown__text > * {
|
||||
margin-left: unset;
|
||||
}
|
||||
}
|
||||
li > button:hover:not(:disabled),
|
||||
li.active > button:not(:disabled) {
|
||||
background: var(--hl-sm);
|
||||
|
||||
Reference in New Issue
Block a user