mirror of
https://github.com/Kong/insomnia
synced 2024-11-08 23:00:30 +00:00
245 lines
6.2 KiB
TypeScript
245 lines
6.2 KiB
TypeScript
import React, { PureComponent } from 'react';
|
|
import { autoBindMethodsForReact } from 'class-autobind-decorator';
|
|
import { AUTOBIND_CFG } from '../../../common/constants';
|
|
import Modal, { ModalProps } from '../base/modal';
|
|
import ModalBody from '../base/modal-body';
|
|
import ModalHeader from '../base/modal-header';
|
|
import ModalFooter from '../base/modal-footer';
|
|
import Tree from '../export-requests/tree';
|
|
import { isRequest, Request } from '../../../models/request';
|
|
import { isRequestGroup, RequestGroup } from '../../../models/request-group';
|
|
import * as models from '../../../models';
|
|
import { GrpcRequest, isGrpcRequest } from '../../../models/grpc-request';
|
|
import { Child } from '../sidebar/sidebar-children';
|
|
|
|
export interface Node {
|
|
doc: Request | GrpcRequest | RequestGroup;
|
|
children: Node[];
|
|
collapsed: boolean;
|
|
totalRequests: number;
|
|
selectedRequests: number;
|
|
}
|
|
|
|
interface Props extends ModalProps {
|
|
childObjects: Child[];
|
|
handleExportRequestsToFile: Function;
|
|
}
|
|
|
|
interface State {
|
|
treeRoot: Node | null;
|
|
}
|
|
|
|
@autoBindMethodsForReact(AUTOBIND_CFG)
|
|
class ExportRequestsModal extends PureComponent<Props, State> {
|
|
modal: Modal | null = null;
|
|
|
|
state: State = {
|
|
treeRoot: null,
|
|
}
|
|
|
|
setModalRef(modal: Modal) {
|
|
if (modal != null) {
|
|
this.modal = modal;
|
|
}
|
|
}
|
|
|
|
show() {
|
|
this.modal?.show();
|
|
this.createTree();
|
|
}
|
|
|
|
hide() {
|
|
this.modal?.hide();
|
|
}
|
|
|
|
handleExport() {
|
|
const { treeRoot } = this.state;
|
|
|
|
if (treeRoot == null || treeRoot.selectedRequests === 0) {
|
|
return;
|
|
}
|
|
|
|
const exportedRequestIds = this.getSelectedRequestIds(treeRoot);
|
|
this.props.handleExportRequestsToFile(exportedRequestIds);
|
|
this.hide();
|
|
}
|
|
|
|
getSelectedRequestIds(node: Node): string[] {
|
|
const docIsRequest = isRequest(node.doc) || isGrpcRequest(node.doc);
|
|
|
|
if (docIsRequest && node.selectedRequests === node.totalRequests) {
|
|
return [node.doc._id];
|
|
}
|
|
|
|
const requestIds: string[] = [];
|
|
|
|
for (const child of node.children) {
|
|
const reqIds = this.getSelectedRequestIds(child);
|
|
requestIds.push(...reqIds);
|
|
}
|
|
|
|
return requestIds;
|
|
}
|
|
|
|
createTree() {
|
|
const { childObjects } = this.props;
|
|
const children: Node[] = childObjects.map(child => this.createNode(child));
|
|
const totalRequests = children
|
|
.map(child => child.totalRequests)
|
|
.reduce((acc, totalRequests) => acc + totalRequests, 0);
|
|
|
|
// @ts-expect-error -- TSCONVERSION missing property
|
|
const rootFolder: RequestGroup = {
|
|
...models.requestGroup.init(),
|
|
_id: 'all',
|
|
type: models.requestGroup.type,
|
|
name: 'All requests',
|
|
parentId: '',
|
|
modified: 0,
|
|
created: 0,
|
|
};
|
|
this.setState({
|
|
treeRoot: {
|
|
doc: rootFolder,
|
|
collapsed: false,
|
|
children: children,
|
|
totalRequests: totalRequests,
|
|
selectedRequests: totalRequests, // Default select all
|
|
},
|
|
});
|
|
}
|
|
|
|
createNode(item: Record<string, any>): Node {
|
|
const children: Node[] = item.children.map(child => this.createNode(child));
|
|
let totalRequests = children
|
|
.map(child => child.totalRequests)
|
|
.reduce((acc, totalRequests) => acc + totalRequests, 0);
|
|
const docIsRequest = isRequest(item.doc) || isGrpcRequest(item.doc);
|
|
|
|
if (docIsRequest) {
|
|
totalRequests++;
|
|
}
|
|
|
|
return {
|
|
doc: item.doc,
|
|
collapsed: false,
|
|
children: children,
|
|
totalRequests: totalRequests,
|
|
selectedRequests: totalRequests, // Default select all
|
|
};
|
|
}
|
|
|
|
handleSetRequestGroupCollapsed(requestGroupId: string, isCollapsed: boolean) {
|
|
const { treeRoot } = this.state;
|
|
|
|
if (treeRoot == null) {
|
|
return;
|
|
}
|
|
|
|
const found = this.setRequestGroupCollapsed(treeRoot, isCollapsed, requestGroupId);
|
|
|
|
if (!found) {
|
|
return;
|
|
}
|
|
|
|
this.setState({
|
|
treeRoot: { ...treeRoot },
|
|
});
|
|
}
|
|
|
|
handleSetItemSelected(itemId: string, isSelected: boolean) {
|
|
const { treeRoot } = this.state;
|
|
|
|
if (treeRoot == null) {
|
|
return;
|
|
}
|
|
|
|
const found = this.setItemSelected(treeRoot, isSelected, itemId);
|
|
|
|
if (!found) {
|
|
return;
|
|
}
|
|
|
|
this.setState({
|
|
treeRoot: { ...treeRoot },
|
|
});
|
|
}
|
|
|
|
setRequestGroupCollapsed(node: Node, isCollapsed: boolean, requestGroupId: string) {
|
|
if (!isRequestGroup(node.doc)) {
|
|
return false;
|
|
}
|
|
|
|
if (node.doc._id === requestGroupId) {
|
|
node.collapsed = isCollapsed;
|
|
return true;
|
|
}
|
|
|
|
for (const child of node.children) {
|
|
const found = this.setRequestGroupCollapsed(child, isCollapsed, requestGroupId);
|
|
|
|
if (found) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
setItemSelected(node: Node, isSelected: boolean, id?: string) {
|
|
if (id == null || node.doc._id === id) {
|
|
// Switch the flags of all children in this subtree.
|
|
for (const child of node.children) {
|
|
this.setItemSelected(child, isSelected);
|
|
}
|
|
|
|
node.selectedRequests = isSelected ? node.totalRequests : 0;
|
|
return true;
|
|
}
|
|
|
|
for (const child of node.children) {
|
|
const found = this.setItemSelected(child, isSelected, id);
|
|
|
|
if (found) {
|
|
node.selectedRequests = node.children
|
|
.map(ch => ch.selectedRequests)
|
|
.reduce((acc, selected) => acc + selected, 0);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
render() {
|
|
const { treeRoot } = this.state;
|
|
const isExportDisabled = treeRoot != null ? treeRoot.selectedRequests === 0 : false;
|
|
return (
|
|
<Modal ref={this.setModalRef} tall freshState {...this.props}>
|
|
<ModalHeader>Select Requests to Export</ModalHeader>
|
|
<ModalBody>
|
|
<div className="requests-tree">
|
|
<Tree
|
|
root={treeRoot}
|
|
handleSetRequestGroupCollapsed={this.handleSetRequestGroupCollapsed}
|
|
handleSetItemSelected={this.handleSetItemSelected}
|
|
/>
|
|
</div>
|
|
</ModalBody>
|
|
<ModalFooter>
|
|
<div>
|
|
<button className="btn" onClick={this.hide}>
|
|
Cancel
|
|
</button>
|
|
<button className="btn" onClick={this.handleExport} disabled={isExportDisabled}>
|
|
Export
|
|
</button>
|
|
</div>
|
|
</ModalFooter>
|
|
</Modal>
|
|
);
|
|
}
|
|
}
|
|
|
|
export default ExportRequestsModal;
|