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

Display WebSocket requests in the sidebar #5048

Merged
merged 1 commit into from
Aug 5, 2022
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
14 changes: 10 additions & 4 deletions packages/insomnia/src/models/helpers/request-operations.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
import { GrpcRequest, isGrpcRequest, isGrpcRequestId } from '../grpc-request';
import * as models from '../index';
import { Request } from '../request';
import { isWebSocketRequest, WebSocketRequest } from '../websocket-request';

export function getById(requestId: string): Promise<Request | GrpcRequest | null> {
return isGrpcRequestId(requestId)
? models.grpcRequest.getById(requestId)
: models.request.getById(requestId);
}

export function remove(request: Request | GrpcRequest) {
return isGrpcRequest(request)
? models.grpcRequest.remove(request)
: models.request.remove(request);
export function remove(request: Request | GrpcRequest | WebSocketRequest) {
if (isGrpcRequest(request)) {
return models.grpcRequest.remove(request);
}
if (isWebSocketRequest(request)) {
return models.websocketRequest.remove(request);
} else {
return models.request.remove(request);
}
}

export function update<T extends object>(request: T, patch: Partial<T> = {}): Promise<T> {
Expand Down
4 changes: 3 additions & 1 deletion packages/insomnia/src/models/websocket-request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ export const canSync = false;
export interface BaseWebSocketRequest {
name: string;
url: string;
metaSortKey: number;
}

export type WebSocketRequest = BaseWebSocketRequest & BaseModel;
export type WebSocketRequest = BaseModel & BaseWebSocketRequest & { type: typeof type };

export const isWebSocketRequest = (model: Pick<BaseModel, 'type'>): model is WebSocketRequest => (
model.type === type
Expand All @@ -25,6 +26,7 @@ export const isWebSocketRequest = (model: Pick<BaseModel, 'type'>): model is Web
export const init = (): BaseWebSocketRequest => ({
name: 'New WebSocket Request',
url: '',
metaSortKey: -1 * Date.now(),
});

export const migrate = (doc: WebSocketRequest) => doc;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
} from '../../../common/constants';
import * as models from '../../../models';
import { update } from '../../../models/helpers/request-operations';
import { isRequest } from '../../../models/request';
import { selectActiveRequest } from '../../redux/selectors';
import { Dropdown } from '../base/dropdown/dropdown';
import { DropdownButton } from '../base/dropdown/dropdown-button';
Expand Down Expand Up @@ -46,8 +47,7 @@ export const AuthDropdown: FC = () => {
return;
}

if (!('authentication' in activeRequest)) {
// gRPC Requests don't have `authentication`
if (!isRequest(activeRequest)) {
return;
}

Expand Down Expand Up @@ -86,7 +86,7 @@ export const AuthDropdown: FC = () => {
if (!activeRequest) {
return false;
}
if (!('authentication' in activeRequest)) {
if (!isRequest(activeRequest)) {
return false;
}
return type === (activeRequest.authentication.type || AUTH_NONE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
CONTENT_TYPE_YAML,
getContentTypeName,
} from '../../../common/constants';
import { isWebSocketRequest } from '../../../models/websocket-request';
import { selectActiveRequest } from '../../redux/selectors';
import { Dropdown } from '../base/dropdown/dropdown';
import { DropdownButton } from '../base/dropdown/dropdown-button';
Expand All @@ -38,7 +39,9 @@ const MimeTypeItem: FC<{
mimeType,
onChange,
}) => {
const activeRequest = useSelector(selectActiveRequest);
const request = useSelector(selectActiveRequest);
const activeRequest = request && !isWebSocketRequest(request) ? request : null;

const handleChangeMimeType = useCallback(async (mimeType: string | null) => {
if (!activeRequest) {
return;
Expand Down Expand Up @@ -91,7 +94,8 @@ const MimeTypeItem: FC<{
MimeTypeItem.displayName = DropdownItem.name;

export const ContentTypeDropdown: FC<Props> = ({ onChange }) => {
const activeRequest = useSelector(selectActiveRequest);
const request = useSelector(selectActiveRequest);
const activeRequest = request && !isWebSocketRequest(request) ? request : null;

if (!activeRequest) {
return null;
Expand Down
3 changes: 2 additions & 1 deletion packages/insomnia/src/ui/components/sidebar/dnd.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@ import * as models from '../../../models';
import { GrpcRequest } from '../../../models/grpc-request';
import { Request } from '../../../models/request';
import { RequestGroup } from '../../../models/request-group';
import { WebSocketRequest } from '../../../models/websocket-request';

export type DnDDragProps = ReturnType<typeof sourceCollect>;
export type DnDDropProps = ReturnType<typeof targetCollect>;
export type DnDProps = DnDDragProps & DnDDropProps;

export interface DragObject {
item?: GrpcRequest | Request | RequestGroup;
item?: GrpcRequest | Request | WebSocketRequest | RequestGroup;
}

export const sourceCollect = (connect: DragSourceConnector, monitor: DragSourceMonitor) => ({
Expand Down
57 changes: 36 additions & 21 deletions packages/insomnia/src/ui/components/sidebar/sidebar-children.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ import React, { FC, Fragment } from 'react';
import ReactDOM from 'react-dom';
import { useSelector } from 'react-redux';

import { GrpcRequest, isGrpcRequest } from '../../../models/grpc-request';
import { GrpcRequest } from '../../../models/grpc-request';
import * as models from '../../../models/index';
import { isRequest, Request } from '../../../models/request';
import type { RequestGroup } from '../../../models/request-group';
import { Request } from '../../../models/request';
import { isRequestGroup, RequestGroup } from '../../../models/request-group';
import { WebSocketRequest } from '../../../models/websocket-request';
import { updateRequestMetaByParentId } from '../../hooks/create-request';
import { selectActiveRequest, selectActiveWorkspaceMeta } from '../../redux/selectors';
import { selectSidebarChildren } from '../../redux/sidebar-selectors';
Expand All @@ -14,7 +15,7 @@ import { SidebarRequestGroupRow } from './sidebar-request-group-row';
import { SidebarRequestRow } from './sidebar-request-row';

export interface Child {
doc: Request | GrpcRequest | RequestGroup;
doc: Request | GrpcRequest | WebSocketRequest | RequestGroup;
children: Child[];
collapsed: boolean;
hidden: boolean;
Expand Down Expand Up @@ -50,16 +51,37 @@ export const SidebarChildren: FC<Props> = ({
updateRequestMetaByParentId(requestId, { lastActive: Date.now() });
};

const RecursiveSidebarRows: FC<RecursiveSidebarRowsProps> = ({ rows, isInPinnedList }) => {
const RecursiveSidebarRows: FC<RecursiveSidebarRowsProps> = ({
rows,
isInPinnedList,
}) => {
const activeRequest = useSelector(selectActiveRequest);
const activeRequestId = activeRequest ? activeRequest._id : 'n/a';

return (
<>
{rows.map(row => (!isInPinnedList && row.hidden)
? null
: (isRequest(row.doc) || isGrpcRequest(row.doc))
? (
{rows
.filter(row => !(!isInPinnedList && row.hidden))
.map(row => {
if (isRequestGroup(row.doc)) {
return (
<SidebarRequestGroupRow
key={row.doc._id}
filter={filter || ''}
isActive={hasActiveChild(row.children, activeRequestId)}
isCollapsed={row.collapsed}
requestGroup={row.doc}
>
{row.children.filter(Boolean).length > 0 ? (
<RecursiveSidebarRows
isInPinnedList={isInPinnedList}
rows={row.children}
/>
) : null}
</SidebarRequestGroupRow>
);
}
return (
<SidebarRequestRow
key={row.doc._id}
filter={isInPinnedList ? '' : filter || ''}
Expand All @@ -70,19 +92,12 @@ export const SidebarChildren: FC<Props> = ({
disableDragAndDrop={isInPinnedList}
request={row.doc}
/>
) : (
<SidebarRequestGroupRow
key={row.doc._id}
filter={filter || ''}
isActive={hasActiveChild(row.children, activeRequestId)}
isCollapsed={row.collapsed}
requestGroup={row.doc}
>
{row.children.filter(Boolean).length > 0 ? <RecursiveSidebarRows isInPinnedList={isInPinnedList} rows={row.children} /> : null}
</SidebarRequestGroupRow>
))}
</>);
);
})}
</>
);
};

const { all, pinned } = sidebarChildren;
const showSeparator = sidebarChildren.pinned.length > 0;
const contextMenuPortal = ReactDOM.createPortal(
Expand Down
49 changes: 29 additions & 20 deletions packages/insomnia/src/ui/components/sidebar/sidebar-request-row.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ import { CONTENT_TYPE_GRAPHQL } from '../../../common/constants';
import { getMethodOverrideHeader } from '../../../common/misc';
import { GrpcRequest, isGrpcRequest } from '../../../models/grpc-request';
import * as requestOperations from '../../../models/helpers/request-operations';
import { Request } from '../../../models/request';
import { isRequest, Request } from '../../../models/request';
import { RequestGroup } from '../../../models/request-group';
import { isWebSocketRequest, WebSocketRequest } from '../../../models/websocket-request';
import { useNunjucks } from '../../context/nunjucks/use-nunjucks';
import { createRequest } from '../../hooks/create-request';
import { selectActiveEnvironment, selectActiveProject, selectActiveWorkspace } from '../../redux/selectors';
Expand All @@ -21,6 +22,7 @@ import { showModal } from '../modals/index';
import { RequestSettingsModal } from '../modals/request-settings-modal';
import { GrpcTag } from '../tags/grpc-tag';
import { MethodTag } from '../tags/method-tag';
import { WebSocketTag } from '../tags/websocket-tag';
import { DnDProps, DragObject, dropHandleCreator, hoverHandleCreator, sourceCollect, targetCollect } from './dnd';

interface RawProps {
Expand All @@ -30,7 +32,7 @@ interface RawProps {
handleDuplicateRequest: Function;
isActive: boolean;
isPinned: boolean;
request?: Request | GrpcRequest;
request?: Request | GrpcRequest | WebSocketRequest;
requestGroup?: RequestGroup;
}

Expand Down Expand Up @@ -138,7 +140,7 @@ export const _SidebarRequestRow: FC<Props> = forwardRef(({
return;
}

if (isGrpcRequest(request)) {
if (!isRequest(request)) {
return;
}

Expand Down Expand Up @@ -203,12 +205,17 @@ export const _SidebarRequestRow: FC<Props> = forwardRef(({
</li>
);
} else {
const methodTag =
isGrpcRequest(request) ? (
<GrpcTag />
) : (
<MethodTag method={request.method} override={methodOverrideValue} />
);

let methodTag = null;

if (isGrpcRequest(request)) {
methodTag = <GrpcTag />;
} else if (isWebSocketRequest(request)) {
methodTag = <WebSocketTag />;
} else if (isRequest(request)) {
methodTag = <MethodTag method={request.method} override={methodOverrideValue} />;
}

node = (
<li ref={nodeRef} className={classes}>
<div
Expand Down Expand Up @@ -243,17 +250,19 @@ export const _SidebarRequestRow: FC<Props> = forwardRef(({
</div>
</button>
<div className="sidebar__actions">
<RequestActionsDropdown
right
ref={requestActionsDropdown}
handleDuplicateRequest={handleDuplicateRequest}
handleShowSettings={handleShowRequestSettings}
request={request}
isPinned={isPinned}
requestGroup={requestGroup}
activeEnvironment={activeEnvironment}
activeProject={activeProject}
/>
{!isWebSocketRequest(request) && (
<RequestActionsDropdown
right
ref={requestActionsDropdown}
handleDuplicateRequest={handleDuplicateRequest}
handleShowSettings={handleShowRequestSettings}
request={request}
isPinned={isPinned}
requestGroup={requestGroup}
activeEnvironment={activeEnvironment}
activeProject={activeProject}
/>
)}
</div>
{isPinned && (
<div className="sidebar__item__icon-pin">
Expand Down
7 changes: 7 additions & 0 deletions packages/insomnia/src/ui/components/tags/websocket-tag.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import React from 'react';

export const WebSocketTag = () => (
<div className="tag tag--no-bg tag--small">
<span className="tag__inner">WS</span>
</div>
);
8 changes: 7 additions & 1 deletion packages/insomnia/src/ui/containers/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { isNotDefaultProject } from '../../models/project';
import { Request, updateMimeType } from '../../models/request';
import { type RequestGroupMeta } from '../../models/request-group-meta';
import { getByParentId as getRequestMetaByParentId } from '../../models/request-meta';
import { isWebSocketRequest, WebSocketRequest } from '../../models/websocket-request';
import { isWorkspace } from '../../models/workspace';
import * as plugins from '../../plugins';
import * as themes from '../../plugins/misc';
Expand Down Expand Up @@ -266,7 +267,7 @@ class App extends PureComponent<AppProps, State> {
];
}

_requestDuplicate(request?: Request | GrpcRequest) {
_requestDuplicate(request?: Request | GrpcRequest | WebSocketRequest) {
if (!request) {
return;
}
Expand Down Expand Up @@ -353,6 +354,11 @@ class App extends PureComponent<AppProps, State> {
return null;
}

if (isWebSocketRequest(this.props.activeRequest)) {
console.warn('Tried to update request mime-type on WebSocket request');
return null;
}

const requestMeta = await models.requestMeta.getOrCreateByParentId(
this.props.activeRequest._id,
);
Expand Down
4 changes: 3 additions & 1 deletion packages/insomnia/src/ui/context/nunjucks/use-nunjucks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useCallback } from 'react';
import { useSelector } from 'react-redux';

import { getRenderContext, getRenderContextAncestors, HandleGetRenderContext, HandleRender, render } from '../../../common/render';
import { isWebSocketRequest } from '../../../models/websocket-request';
import { NUNJUCKS_TEMPLATE_GLOBAL_PROPERTY_NAME } from '../../../templating';
import { getKeys } from '../../../templating/utils';
import { selectActiveEnvironment, selectActiveRequest, selectActiveWorkspace } from '../../redux/selectors';
Expand All @@ -19,7 +20,8 @@ initializeNunjucksRenderPromiseCache();
*/
export const useNunjucks = () => {
const environmentId = useSelector(selectActiveEnvironment)?._id;
const request = useSelector(selectActiveRequest);
const activeRequest = useSelector(selectActiveRequest);
const request = activeRequest && isWebSocketRequest(activeRequest) ? null : activeRequest;
const workspace = useSelector(selectActiveWorkspace);

const fetchRenderContext = useCallback(async () => {
Expand Down
7 changes: 3 additions & 4 deletions packages/insomnia/src/ui/hooks/use-active-request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import { useCallback } from 'react';
import { useSelector } from 'react-redux';

import * as models from '../../models';
import { isGrpcRequest } from '../../models/grpc-request';
import { Request } from '../../models/request';
import { isRequest, Request } from '../../models/request';
import { selectActiveRequest } from '../redux/selectors';

export const useActiveRequest = () => {
Expand All @@ -13,8 +12,8 @@ export const useActiveRequest = () => {
throw new Error('Tried to load null request');
}

if (isGrpcRequest(activeRequest)) {
throw new Error('Loaded GrpcRequest, expected to load Request');
if (!isRequest(activeRequest)) {
throw new Error('Expected to load Request');
}

const patchRequest = useCallback(async (patch: Partial<Request>) => {
Expand Down
3 changes: 2 additions & 1 deletion packages/insomnia/src/ui/redux/sidebar-selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type { BaseModel } from '../../models';
import { GrpcRequest, isGrpcRequest } from '../../models/grpc-request';
import { isRequest, Request } from '../../models/request';
import { isRequestGroup, RequestGroup } from '../../models/request-group';
import { isWebSocketRequest } from '../../models/websocket-request';
import {
selectActiveWorkspace,
selectActiveWorkspaceMeta,
Expand All @@ -17,7 +18,7 @@ import {
type SidebarModel = Request | GrpcRequest | RequestGroup;

export const shouldShowInSidebar = (model: BaseModel): boolean =>
isRequest(model) || isGrpcRequest(model) || isRequestGroup(model);
isRequest(model) || isWebSocketRequest(model) || isGrpcRequest(model) || isRequestGroup(model);

export const shouldIgnoreChildrenOf = (model: SidebarModel): boolean =>
isRequest(model) || isGrpcRequest(model);
Expand Down