Allow sidebar to show grpc requests (#2786)

This commit is contained in:
Opender Singh authored and GitHub committed 2020-10-29 11:44:37 +13:00
1 parent d1e1da53e5
commit 5f1c1bb747
8 files changed
+185 -92

No files matched your search

@@ -14,7 +14,7 @@ import { Dropdown } from '../base/dropdown';
import SidebarCreateDropdown from './sidebar-create-dropdown';
type Child = {
doc: Request | RequestGroup,
doc: Request | GrpcRequest | RequestGroup,
children: Array<Child>,
collapsed: boolean,
hidden: boolean,
@@ -103,7 +103,7 @@ class SidebarChildren extends React.PureComponent<Props> {
return null;
}
if (child.doc.type === models.request.type) {
if (child.doc.type === models.request.type || child.doc.type === models.grpcRequest.type) {
return (
<SidebarRequestRow
key={child.doc._id}
@@ -13,6 +13,7 @@ import { showModal } from '../modals/index';
import RequestSettingsModal from '../modals/request-settings-modal';
import { CONTENT_TYPE_GRAPHQL } from '../../../common/constants';
import { getMethodOverrideHeader } from '../../../common/misc';
import GrpcTag from '../tags/grpc-tag';
@autobind
class SidebarRequestRow extends PureComponent {
@@ -174,6 +175,13 @@ class SidebarRequestRow extends PureComponent {
</li>
);
} else {
const methodTag =
request.type === models.grpcRequest.type ? (
<GrpcTag />
) : (
<MethodTag method={request.method} override={this._getMethodOverrideHeaderValue()} />
);
node = (
<li className={classes}>
<div
@@ -185,10 +193,7 @@ class SidebarRequestRow extends PureComponent {
onClick={this._handleRequestActivate}
onContextMenu={this._handleShowRequestActions}>
<div className="sidebar__clickable">
<MethodTag
method={request.method}
override={this._getMethodOverrideHeaderValue()}
/>
{methodTag}
<Editable
value={request.name}
fallbackValue={this.state.renderedUrl}
@@ -267,7 +272,7 @@ SidebarRequestRow.propTypes = {
// Optional
requestGroup: PropTypes.object,
request: PropTypes.object,
request: PropTypes.object, // can be Request or GrpcRequest
disableDragAndDrop: PropTypes.bool,
};
@@ -0,0 +1,11 @@
import React from 'react';
const GrpcTag = () => (
<div style={{ position: 'relative' }}>
<div className="tag tag--no-bg tag--small method-grpc">
<span className="tag__inner">gRPC</span>
</div>
</div>
);
export default GrpcTag;
@@ -52,11 +52,11 @@ import {
selectActiveWorkspaceClientCertificates,
selectActiveWorkspaceMeta,
selectEntitiesLists,
selectSidebarChildren,
selectSyncItems,
selectUnseenWorkspaces,
selectWorkspaceRequestsAndRequestGroups,
} from '../redux/selectors';
import { selectSidebarChildren } from '../redux/sidebar-selectors';
import RequestCreateModal from '../components/modals/request-create-modal';
import GenerateCodeModal from '../components/modals/generate-code-modal';
import WorkspaceSettingsModal from '../components/modals/workspace-settings-modal';
@@ -27,11 +27,14 @@
}
.notice,
.http-method-PATCH,
.method-grpc {
.http-method-PATCH {
color: var(--color-notice) !important;
}
.method-grpc {
color: #ffbf2f !important;
}
.warning,
.http-method-PUT {
color: var(--color-warning) !important;
@@ -0,0 +1,47 @@
import * as models from '../../../models';
import {
shouldIgnoreChildrenOf,
shouldShowInSidebar,
sortByMetaKeyOrId,
} from '../sidebar-selectors';
import { difference } from 'lodash';
describe('shouldShowInSidebar', () => {
const allTypes = models.types();
const supported = [models.request.type, models.requestGroup.type, models.grpcRequest.type];
const unsupported = difference(allTypes, supported);
it.each(supported)('should show %s in sidebar', type => {
expect(shouldShowInSidebar({ type })).toBe(true);
});
it.each(unsupported)('should not show %s in sidebar', type => {
expect(shouldShowInSidebar({ type })).toBe(false);
});
});
describe('shouldIgnoreChildrenOf', () => {
it.each([models.request.type, models.grpcRequest.type])('should ignore children of %s', type => {
expect(shouldIgnoreChildrenOf({ type })).toBe(true);
});
it.each([models.requestGroup.type])('should not ignore children of', type => {
expect(shouldIgnoreChildrenOf({ type })).toBe(false);
});
});
describe('sortByMetaKeyOrId', () => {
it('sort by _id if meta keys are identical', () => {
const a = { _id: 'a', metaSortKey: '1' };
const b = { _id: 'b', metaSortKey: '1' };
expect(sortByMetaKeyOrId(a, b)).toBe(1);
expect(sortByMetaKeyOrId(b, a)).toBe(-1);
});
it('sort by meta keys', () => {
const a = { metaSortKey: '1' };
const b = { metaSortKey: '2' };
expect(sortByMetaKeyOrId(a, b)).toBe(-1);
expect(sortByMetaKeyOrId(b, a)).toBe(1);
});
});
@@ -1,5 +1,4 @@
import { createSelector } from 'reselect';
import { fuzzyMatchAll } from '../../common/misc';
import * as models from '../../models';
// ~~~~~~~~~ //
@@ -139,98 +138,22 @@ export const selectActiveWorkspaceEntities = createSelector(
export const selectPinnedRequests = createSelector(selectEntitiesLists, entities => {
const pinned = {};
const requests = [...entities.requests, ...entities.grpcRequests];
const requestMetas = [...entities.requestMetas, ...entities.grpcRequestMetas];
// Default all to unpinned
for (const request of entities.requests) {
for (const request of requests) {
pinned[request._id] = false;
}
// Update those that have metadata (not all do)
for (const meta of entities.requestMetas) {
for (const meta of requestMetas) {
pinned[meta.parentId] = meta.pinned;
}
return pinned;
});
export const selectSidebarChildren = createSelector(
selectCollapsedRequestGroups,
selectPinnedRequests,
selectActiveWorkspace,
selectActiveWorkspaceMeta,
selectEntitiesChildrenMap,
(collapsed, pinned, activeWorkspace, activeWorkspaceMeta, childrenMap) => {
const sidebarFilter = activeWorkspaceMeta ? activeWorkspaceMeta.sidebarFilter : '';
function next(parentId, pinnedChildren) {
const children = (childrenMap[parentId] || [])
.filter(doc => {
return doc.type === models.request.type || doc.type === models.requestGroup.type;
})
.sort((a, b) => {
if (a.metaSortKey === b.metaSortKey) {
return a._id > b._id ? -1 : 1;
} else {
return a.metaSortKey < b.metaSortKey ? -1 : 1;
}
});
if (children.length > 0) {
return children.map(c => {
const child = {
doc: c,
hidden: false,
collapsed: !!collapsed[c._id],
pinned: !!pinned[c._id],
};
if (child.pinned) {
pinnedChildren.push(child);
}
// Don't add children of requests
child.children = c.type === models.request.type ? [] : next(c._id, pinnedChildren);
return child;
});
} else {
return children;
}
}
function matchChildren(children, parentNames = []) {
// Bail early if no filter defined
if (!sidebarFilter) {
return children;
}
for (const child of children) {
// Gather all parents so we can match them too
matchChildren(child.children, [...parentNames, child.doc.name]);
const hasMatchedChildren = child.children.find(c => c.hidden === false);
// Try to match request attributes
const { name, method } = child.doc;
const match = fuzzyMatchAll(sidebarFilter, [name, method, ...parentNames], {
splitSpace: true,
});
// Update hidden state depending on whether it matched
const matched = hasMatchedChildren || match;
child.hidden = !matched;
}
return children;
}
const pinnedChildren = [];
const childrenTree = next(activeWorkspace._id, pinnedChildren);
const matchedChildren = matchChildren(childrenTree);
return { pinned: pinnedChildren, all: matchedChildren };
},
);
export const selectWorkspaceRequestsAndRequestGroups = createSelector(
selectActiveWorkspaceEntities,
entities => {
@@ -0,0 +1,104 @@
// @flow
import * as models from '../../models';
import type { BaseModel } from '../../models';
import type { Request } from '../../models/request';
import type { GrpcRequest } from '../../models/grpc-request';
import type { RequestGroup } from '../../models/request-group';
import { createSelector } from 'reselect';
import { fuzzyMatchAll } from '../../common/misc';
import {
selectActiveWorkspace,
selectActiveWorkspaceMeta,
selectCollapsedRequestGroups,
selectEntitiesChildrenMap,
selectPinnedRequests,
} from './selectors';
type SidebarModels = Request | GrpcRequest | RequestGroup;
export const shouldShowInSidebar = ({ type }: BaseModel): boolean =>
type === models.request.type ||
type === models.grpcRequest.type ||
type === models.requestGroup.type;
export const shouldIgnoreChildrenOf = ({ type }: SidebarModels): boolean =>
type === models.request.type || type === models.grpcRequest.type;
export const sortByMetaKeyOrId = (a: SidebarModels, b: SidebarModels): number => {
if (a.metaSortKey === b.metaSortKey) {
return a._id > b._id ? -1 : 1; // ascending
} else {
return a.metaSortKey < b.metaSortKey ? -1 : 1; // descending
}
};
export const selectSidebarChildren = createSelector(
selectCollapsedRequestGroups,
selectPinnedRequests,
selectActiveWorkspace,
selectActiveWorkspaceMeta,
selectEntitiesChildrenMap,
(collapsed, pinned, activeWorkspace, activeWorkspaceMeta, childrenMap) => {
const sidebarFilter = activeWorkspaceMeta ? activeWorkspaceMeta.sidebarFilter : '';
function next(parentId, pinnedChildren) {
const children: Array<SidebarModels> = (childrenMap[parentId] || [])
.filter(shouldShowInSidebar)
.sort(sortByMetaKeyOrId);
if (children.length > 0) {
return children.map(c => {
const child = {
doc: c,
hidden: false,
collapsed: !!collapsed[c._id],
pinned: !!pinned[c._id],
};
if (child.pinned) {
pinnedChildren.push(child);
}
// Don't add children of requests
child.children = shouldIgnoreChildrenOf(c) ? [] : next(c._id, pinnedChildren);
return child;
});
} else {
return children;
}
}
function matchChildren(children, parentNames = []) {
// Bail early if no filter defined
if (!sidebarFilter) {
return children;
}
for (const child of children) {
// Gather all parents so we can match them too
matchChildren(child.children, [...parentNames, child.doc.name]);
const hasMatchedChildren = child.children.find(c => c.hidden === false);
// Try to match request attributes
const { name, method } = child.doc;
const match = fuzzyMatchAll(sidebarFilter, [name, method, ...parentNames], {
splitSpace: true,
});
// Update hidden state depending on whether it matched
const matched = hasMatchedChildren || match;
child.hidden = !matched;
}
return children;
}
const pinnedChildren = [];
const childrenTree = next(activeWorkspace._id, pinnedChildren);
const matchedChildren = matchChildren(childrenTree);
return { pinned: pinnedChildren, all: matchedChildren };
},
);