mirror of
https://github.com/Kong/insomnia.git
synced 2026-04-20 14:17:29 -04:00
Modal prompt to select protofile (#2756)
This commit is contained in:
@@ -46,8 +46,8 @@ export function getById(_id: string): Promise<ProtoFile | null> {
|
||||
return db.getWhere(type, { _id });
|
||||
}
|
||||
|
||||
export function getByParentId(parentId: string): Promise<ProtoFile | null> {
|
||||
return db.getWhere(type, { parentId });
|
||||
export function findByParentId(parentId: string): Promise<Array<ProtoFile>> {
|
||||
return db.find(type, { parentId });
|
||||
}
|
||||
|
||||
export function all(): Promise<Array<ProtoFile>> {
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
// @flow
|
||||
import * as React from 'react';
|
||||
import * as models from '../../../models';
|
||||
import type { ProtoFile } from '../../../models/proto-file';
|
||||
import ModalHeader from '../base/modal-header';
|
||||
import ModalBody from '../base/modal-body';
|
||||
import ModalFooter from '../base/modal-footer';
|
||||
import autobind from 'autobind-decorator';
|
||||
import type { Workspace } from '../../../models/workspace';
|
||||
import Modal from '../base/modal';
|
||||
import ProtoFileList from '../proto-file/proto-file-list';
|
||||
|
||||
type Props = {|
|
||||
workspace: Workspace,
|
||||
|};
|
||||
|
||||
type State = {|
|
||||
protoFiles: Array<ProtoFile>,
|
||||
selectedProtoFileId: string,
|
||||
|};
|
||||
|
||||
type ProtoFilesModalOptions = {|
|
||||
preselectProtoFileId?: string,
|
||||
onSave: string => Promise<void>,
|
||||
|};
|
||||
|
||||
const INITIAL_STATE: State = {
|
||||
protoFiles: [],
|
||||
selectedProtoFileId: '',
|
||||
};
|
||||
|
||||
@autobind
|
||||
class ProtoFilesModal extends React.PureComponent<Props, State> {
|
||||
modal: Modal | null;
|
||||
onSave: (string => Promise<void>) | null;
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = INITIAL_STATE;
|
||||
this.onSave = null;
|
||||
}
|
||||
|
||||
_setModalRef(ref: ?Modal) {
|
||||
this.modal = ref;
|
||||
}
|
||||
|
||||
async show(options: ProtoFilesModalOptions) {
|
||||
this.onSave = options.onSave;
|
||||
this.setState({ ...INITIAL_STATE });
|
||||
|
||||
this.modal && this.modal.show();
|
||||
await this._refresh(options.preselectProtoFileId);
|
||||
}
|
||||
|
||||
async _refresh(preselectProtoFileId?: string) {
|
||||
const { workspace } = this.props;
|
||||
const protoFilesForWorkspace = await models.protoFile.findByParentId(workspace._id);
|
||||
|
||||
protoFilesForWorkspace.push(
|
||||
{ _id: 'pf_123', name: 'File 1' },
|
||||
{ _id: 'pf_456', name: 'File 2' },
|
||||
{ _id: 'pf_789', name: 'File 3' },
|
||||
);
|
||||
|
||||
this.setState({
|
||||
protoFiles: protoFilesForWorkspace,
|
||||
selectedProtoFileId: preselectProtoFileId,
|
||||
});
|
||||
}
|
||||
|
||||
async _handleSave(e: SyntheticEvent<HTMLButtonElement>) {
|
||||
e.preventDefault();
|
||||
this.hide();
|
||||
|
||||
if (typeof this.onSave === 'function') {
|
||||
await this.onSave(this.state.selectedProtoFileId);
|
||||
}
|
||||
}
|
||||
|
||||
hide() {
|
||||
this.modal && this.modal.hide();
|
||||
}
|
||||
|
||||
_handleSelect(id: string) {
|
||||
this.setState({ selectedProtoFileId: id });
|
||||
}
|
||||
|
||||
_handleDelete(protoFile: ProtoFile) {
|
||||
// TODO: to be built in INS-209
|
||||
console.log(`delete ${protoFile._id}`);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { protoFiles, selectedProtoFileId } = this.state;
|
||||
|
||||
return (
|
||||
<Modal ref={this._setModalRef}>
|
||||
<ModalHeader>Select Protofile</ModalHeader>
|
||||
<ModalBody className="wide pad">
|
||||
Files
|
||||
<ProtoFileList
|
||||
protoFiles={protoFiles}
|
||||
selectedId={selectedProtoFileId}
|
||||
handleSelect={this._handleSelect}
|
||||
handleDelete={this._handleDelete}
|
||||
/>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<div>
|
||||
<button className="btn" onClick={this._handleSave} disabled={!selectedProtoFileId}>
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
</ModalFooter>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ProtoFilesModal;
|
||||
@@ -17,7 +17,8 @@ import {
|
||||
} from '../../../common/constants';
|
||||
import * as models from '../../../models/index';
|
||||
import { trackEvent } from '../../../common/analytics';
|
||||
import { showAlert } from './index';
|
||||
import { showModal } from './index';
|
||||
import ProtoFilesModal from './proto-files-modal';
|
||||
|
||||
type RequestCreateModalOptions = {
|
||||
parentId: string,
|
||||
@@ -54,13 +55,15 @@ class RequestCreateModal extends PureComponent {
|
||||
const { parentId, selectedContentType, selectedMethod } = this.state;
|
||||
const requestName = this._input.value;
|
||||
if (selectedMethod === METHOD_GRPC) {
|
||||
// TODO: Create new grpc request with the name - INS-198
|
||||
showModal(ProtoFilesModal, {
|
||||
onSave: async protofileId => {
|
||||
// TODO: Create new grpc request with the name and selected proto file - INS-198
|
||||
console.log(`Create request name: [${requestName}], and protofileId: [${protofileId}]`);
|
||||
|
||||
const id = 'gr_123';
|
||||
this._onComplete(id);
|
||||
|
||||
// TODO: Show protofile selection modal - INS-188
|
||||
showAlert({ title: 'Select protofile', message: 'To be built', okLabel: 'ok' });
|
||||
const createdRequestId = 'gr_123';
|
||||
this._onComplete(createdRequestId);
|
||||
},
|
||||
});
|
||||
} else {
|
||||
const request = await models.initModel(models.request.type, {
|
||||
parentId,
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
// @flow
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import type { ProtoFile } from '../../../models/proto-file';
|
||||
import PromptButton from '../base/prompt-button';
|
||||
import type { DeleteProtoFileHandler, SelectProtoFileHandler } from './proto-file-list';
|
||||
import { ListGroupItem } from '../../../../../insomnia-components';
|
||||
|
||||
type Props = {
|
||||
protoFile: ProtoFile,
|
||||
isSelected?: boolean,
|
||||
handleSelect: SelectProtoFileHandler,
|
||||
handleDelete: DeleteProtoFileHandler,
|
||||
};
|
||||
|
||||
const SelectableListItem: React.PureComponent<{ isSelected?: boolean }> = styled(ListGroupItem)`
|
||||
&:hover {
|
||||
background-color: var(--hl-sm) !important;
|
||||
}
|
||||
|
||||
background-color: ${({ isSelected }) => isSelected && 'var(--hl-sm) !important'};
|
||||
`;
|
||||
|
||||
const ProtoFileListItem = ({ protoFile, isSelected, handleSelect, handleDelete }: Props) => {
|
||||
const { name, _id } = protoFile;
|
||||
|
||||
// Don't re-instantiate the callbacks if the dependencies have not changed
|
||||
const handleSelectCallback = React.useCallback(() => handleSelect(_id), [handleSelect, _id]);
|
||||
const handleDeleteCallback = React.useCallback(
|
||||
async (e: SyntheticEvent<HTMLButtonElement>) => {
|
||||
e.stopPropagation();
|
||||
await handleDelete(protoFile);
|
||||
},
|
||||
[handleDelete, protoFile],
|
||||
);
|
||||
|
||||
return (
|
||||
<SelectableListItem isSelected={isSelected} onClick={handleSelectCallback}>
|
||||
<div className="row-spaced">
|
||||
{name}
|
||||
<PromptButton
|
||||
className="btn btn--super-compact btn--outlined"
|
||||
addIcon
|
||||
confirmMessage=""
|
||||
onClick={handleDeleteCallback}
|
||||
title="Delete Proto File">
|
||||
<i className="fa fa-trash-o" />
|
||||
</PromptButton>
|
||||
</div>
|
||||
</SelectableListItem>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProtoFileListItem;
|
||||
@@ -0,0 +1,32 @@
|
||||
// @flow
|
||||
import React from 'react';
|
||||
import type { ProtoFile } from '../../../models/proto-file';
|
||||
import { ListGroup, ListGroupItem } from 'insomnia-components';
|
||||
import ProtoFileListItem from './proto-file-list-item';
|
||||
|
||||
export type SelectProtoFileHandler = (id: string) => void;
|
||||
export type DeleteProtoFileHandler = (protofile: ProtoFile) => Promise<void>;
|
||||
|
||||
type Props = {
|
||||
protoFiles: Array<ProtoFile>,
|
||||
selectedId?: string,
|
||||
handleSelect: SelectProtoFileHandler,
|
||||
handleDelete: DeleteProtoFileHandler,
|
||||
};
|
||||
|
||||
const ProtoFileList = ({ protoFiles, selectedId, handleSelect, handleDelete }: Props) => (
|
||||
<ListGroup>
|
||||
{!protoFiles.length && <ListGroupItem>No proto files exist for this workspace</ListGroupItem>}
|
||||
{protoFiles.map(p => (
|
||||
<ProtoFileListItem
|
||||
key={p.id}
|
||||
protoFile={p}
|
||||
isSelected={p._id === selectedId}
|
||||
handleSelect={handleSelect}
|
||||
handleDelete={handleDelete}
|
||||
/>
|
||||
))}
|
||||
</ListGroup>
|
||||
);
|
||||
|
||||
export default ProtoFileList;
|
||||
@@ -90,6 +90,7 @@ import {
|
||||
getAppName,
|
||||
} from '../../common/constants';
|
||||
import { Spectral } from '@stoplight/spectral';
|
||||
import ProtoFilesModal from './modals/proto-files-modal';
|
||||
|
||||
const spectral = new Spectral();
|
||||
|
||||
@@ -770,6 +771,8 @@ class Wrapper extends React.PureComponent<WrapperProps, State> {
|
||||
childObjects={sidebarChildren.all}
|
||||
handleExportRequestsToFile={handleExportRequestsToFile}
|
||||
/>
|
||||
|
||||
<ProtoFilesModal ref={registerModal} workspace={activeWorkspace} />
|
||||
</ErrorBoundary>
|
||||
</div>
|
||||
<React.Fragment key={`views::${this.state.activeGitBranch}`}>
|
||||
|
||||
Reference in New Issue
Block a user