mirror of
https://github.com/Kong/insomnia
synced 2024-11-07 22:30:15 +00:00
Prompt for import as collection or document (#3130)
* feat: add prompt and update import logic * feat: update usages and plugin api * chore: WIP * chore: convert to options * chore: don't create workspace model until needed * chore: add OR condition * chore: add workspace name and don't change scope * feat: prompt with appropriate name * chore: rename * chore: rename type * chore: update signature * chore: properly type the import functions * feat: don't activate the workspace after importing * chore: show loading on homepage * fix: typo * chore: fix tests and rename * Update packages/insomnia-app/app/common/__tests__/import.test.js Co-authored-by: David Marby <david@dmarby.se> Co-authored-by: David Marby <david@dmarby.se>
This commit is contained in:
parent
4b993a7762
commit
049964bb9b
@ -376,14 +376,26 @@ describe('export', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('isApiSpec()', () => {
|
||||
describe('isApiSpecImport()', () => {
|
||||
it.each(['swagger2', 'openapi3'])('should return true if spec id is %o', (id: string) => {
|
||||
expect(importUtil.isApiSpec(id)).toBe(true);
|
||||
expect(importUtil.isApiSpecImport({ id })).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false if spec id is not valid', () => {
|
||||
const id = 'invalid-id';
|
||||
|
||||
expect(importUtil.isApiSpec(id)).toBe(false);
|
||||
expect(importUtil.isApiSpecImport({ id })).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isInsomniaV4Import()', () => {
|
||||
it.each(['insomnia-4'])('should return true if spec id is %o', (id: string) => {
|
||||
expect(importUtil.isInsomniaV4Import({ id })).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false if spec id is not valid', () => {
|
||||
const id = 'invalid-id';
|
||||
|
||||
expect(importUtil.isInsomniaV4Import({ id })).toBe(false);
|
||||
});
|
||||
});
|
||||
|
@ -20,6 +20,8 @@ import {
|
||||
isRequestGroup,
|
||||
isWorkspace,
|
||||
} from '../models/helpers/is-model';
|
||||
import type { Workspace, WorkspaceScope } from '../models/workspace';
|
||||
import type { ApiSpec } from '../models/api-spec';
|
||||
|
||||
const WORKSPACE_ID_KEY = '__WORKSPACE_ID__';
|
||||
const BASE_ENVIRONMENT_ID_KEY = '__BASE_ENVIRONMENT_ID__';
|
||||
@ -61,10 +63,25 @@ export type ImportResult = {
|
||||
summary: { [string]: Array<BaseModel> },
|
||||
};
|
||||
|
||||
export async function importUri(
|
||||
type ConvertResultType = {
|
||||
id: string,
|
||||
name: string,
|
||||
description: string,
|
||||
};
|
||||
|
||||
type ConvertResult = {
|
||||
type: ConvertResultType,
|
||||
data: {
|
||||
resources: Array<Object>,
|
||||
},
|
||||
};
|
||||
|
||||
export type ImportRawConfig = {
|
||||
getWorkspaceId: () => Promise<string | null>,
|
||||
uri: string,
|
||||
): Promise<ImportResult> {
|
||||
getWorkspaceScope?: string => Promise<WorkspaceScope>,
|
||||
};
|
||||
|
||||
export async function importUri(uri: string, importConfig: ImportRawConfig): Promise<ImportResult> {
|
||||
let rawText;
|
||||
|
||||
// If GH preview, force raw
|
||||
@ -86,7 +103,7 @@ export async function importUri(
|
||||
rawText = decodeURIComponent(uri);
|
||||
}
|
||||
|
||||
const result = await importRaw(getWorkspaceId, rawText);
|
||||
const result = await importRaw(rawText, importConfig);
|
||||
const { summary, error } = result;
|
||||
|
||||
if (error) {
|
||||
@ -118,10 +135,10 @@ export async function importUri(
|
||||
}
|
||||
|
||||
export async function importRaw(
|
||||
getWorkspaceId: () => Promise<string | null>,
|
||||
rawContent: string,
|
||||
{ getWorkspaceId, getWorkspaceScope }: ImportRawConfig,
|
||||
): Promise<ImportResult> {
|
||||
let results;
|
||||
let results: ConvertResult;
|
||||
try {
|
||||
results = await convert(rawContent);
|
||||
} catch (err) {
|
||||
@ -132,7 +149,7 @@ export async function importRaw(
|
||||
};
|
||||
}
|
||||
|
||||
const { data } = results;
|
||||
const { data, type: resultsType } = results;
|
||||
|
||||
// Generate all the ids we may need
|
||||
const generatedIds: { [string]: string | Function } = {};
|
||||
@ -147,17 +164,14 @@ export async function importRaw(
|
||||
const workspaceId = await getWorkspaceId();
|
||||
|
||||
// First try getting the workspace to overwrite
|
||||
let workspace = await models.workspace.getById(workspaceId || 'n/a');
|
||||
|
||||
// If none provided, create a new workspace
|
||||
if (workspace === null) {
|
||||
workspace = await models.workspace.create({ name: 'Imported Workspace' });
|
||||
}
|
||||
const workspace = await models.workspace.getById(workspaceId || 'n/a');
|
||||
|
||||
// Update this fn so it doesn't run again
|
||||
generatedIds[WORKSPACE_ID_KEY] = workspace._id;
|
||||
const idToUse = workspace?._id || generateId(models.workspace.prefix);
|
||||
|
||||
return workspace._id;
|
||||
generatedIds[WORKSPACE_ID_KEY] = idToUse;
|
||||
|
||||
return idToUse;
|
||||
};
|
||||
|
||||
// Contains the ID of the base environment to be used with the import
|
||||
@ -240,8 +254,15 @@ export async function importRaw(
|
||||
const existingDoc = await db.get(model.type, resource._id);
|
||||
let newDoc: BaseModel;
|
||||
if (existingDoc) {
|
||||
// If workspace, don't overwrite the existing scope
|
||||
if (isWorkspace(model)) {
|
||||
(resource: Workspace).scope = (existingDoc: Workspace).scope;
|
||||
}
|
||||
newDoc = await db.docUpdate(existingDoc, resource);
|
||||
} else {
|
||||
if (isWorkspace(model)) {
|
||||
await updateWorkspaceScope(resource, resultsType, getWorkspaceScope);
|
||||
}
|
||||
newDoc = await db.docCreate(model.type, resource);
|
||||
|
||||
// Mark as not seen if we created a new workspace from sync
|
||||
@ -256,7 +277,7 @@ export async function importRaw(
|
||||
|
||||
// Store spec under workspace if it's OpenAPI
|
||||
for (const workspace of importedDocs[models.workspace.type]) {
|
||||
if (isApiSpec(results.type.id)) {
|
||||
if (isApiSpecImport(resultsType)) {
|
||||
const spec = await models.apiSpec.updateOrCreateForParentId(workspace._id, {
|
||||
contents: rawContent,
|
||||
contentType: 'yaml',
|
||||
@ -274,17 +295,46 @@ export async function importRaw(
|
||||
|
||||
await db.flushChanges();
|
||||
|
||||
trackEvent('Data', 'Import', results.type.id);
|
||||
trackEvent('Data', 'Import', resultsType.id);
|
||||
|
||||
return {
|
||||
source: results.type && typeof results.type.id === 'string' ? results.type.id : 'unknown',
|
||||
source: resultsType && typeof resultsType.id === 'string' ? resultsType.id : 'unknown',
|
||||
summary: importedDocs,
|
||||
error: null,
|
||||
};
|
||||
}
|
||||
|
||||
export function isApiSpec(content: string): boolean {
|
||||
return content === 'openapi3' || content === 'swagger2';
|
||||
async function updateWorkspaceScope(
|
||||
resource: Workspace,
|
||||
resultType: ConvertResultType,
|
||||
getWorkspaceScope?: string => Promise<WorkspaceScope>,
|
||||
) {
|
||||
// Set the workspace scope if creating a new workspace
|
||||
// IF is creating a new workspace
|
||||
// AND imported resource has no preset scope property OR scope is null
|
||||
// AND we have a function to get scope
|
||||
if ((!resource.hasOwnProperty('scope') || resource.scope === null) && getWorkspaceScope) {
|
||||
const workspaceName = resource.name;
|
||||
let specName;
|
||||
// If is from insomnia v4 and the spec has contents, add to the name when prompting
|
||||
if (isInsomniaV4Import(resultType)) {
|
||||
const spec: ApiSpec | null = await models.apiSpec.getByParentId(resource._id);
|
||||
|
||||
if (spec && spec.contents.trim()) {
|
||||
specName = spec.fileName;
|
||||
}
|
||||
}
|
||||
const nameToPrompt = specName ? `${specName} / ${workspaceName}` : workspaceName;
|
||||
(resource: Workspace).scope = await getWorkspaceScope(nameToPrompt);
|
||||
}
|
||||
}
|
||||
|
||||
export function isApiSpecImport({ id }: ConvertResultType): boolean {
|
||||
return id === 'openapi3' || id === 'swagger2';
|
||||
}
|
||||
|
||||
export function isInsomniaV4Import({ id }: ConvertResultType): boolean {
|
||||
return id === 'insomnia-4';
|
||||
}
|
||||
|
||||
export async function exportWorkspacesHAR(
|
||||
|
@ -29,7 +29,7 @@ export async function migrate(doc: ApiSpec): Promise<ApiSpec> {
|
||||
return doc;
|
||||
}
|
||||
|
||||
export function getByParentId(workspaceId: string): Promise<ApiSpec> {
|
||||
export function getByParentId(workspaceId: string): Promise<ApiSpec | null> {
|
||||
return db.getWhere(type, { parentId: workspaceId });
|
||||
}
|
||||
|
||||
|
@ -11,10 +11,17 @@ export const prefix = 'wrk';
|
||||
export const canDuplicate = true;
|
||||
export const canSync = true;
|
||||
|
||||
export const WorkspaceScopeKeys = {
|
||||
designer: 'designer',
|
||||
collection: 'collection',
|
||||
};
|
||||
|
||||
export type WorkspaceScope = $Keys<typeof WorkspaceScopeKeys>;
|
||||
|
||||
type BaseWorkspace = {
|
||||
name: string,
|
||||
description: string,
|
||||
scope: 'designer' | 'collection',
|
||||
scope: WorkspaceScope,
|
||||
};
|
||||
|
||||
export type Workspace = BaseModel & BaseWorkspace;
|
||||
@ -48,7 +55,7 @@ export async function all(): Promise<Array<Workspace>> {
|
||||
|
||||
if (workspaces.length === 0) {
|
||||
// Create default workspace
|
||||
await create({ name: getAppName(), scope: 'collection' });
|
||||
await create({ name: getAppName(), scope: WorkspaceScopeKeys.collection });
|
||||
return all();
|
||||
} else {
|
||||
return workspaces;
|
||||
@ -112,7 +119,10 @@ async function _migrateEnsureName(workspace: Workspace): Promise<Workspace> {
|
||||
* Ensure workspace scope is set to a valid entry
|
||||
*/
|
||||
function _migrateScope(workspace: Workspace): Workspace {
|
||||
if (workspace.scope === 'designer' || workspace.scope === 'collection') {
|
||||
if (
|
||||
workspace.scope === WorkspaceScopeKeys.designer ||
|
||||
workspace.scope === WorkspaceScopeKeys.collection
|
||||
) {
|
||||
return workspace;
|
||||
}
|
||||
|
||||
@ -120,13 +130,13 @@ function _migrateScope(workspace: Workspace): Workspace {
|
||||
type OldScopeTypes = 'spec' | 'debug' | null;
|
||||
switch ((workspace.scope: OldScopeTypes)) {
|
||||
case 'spec': {
|
||||
workspace.scope = 'designer';
|
||||
workspace.scope = WorkspaceScopeKeys.designer;
|
||||
break;
|
||||
}
|
||||
case 'debug':
|
||||
case null:
|
||||
default:
|
||||
workspace.scope = 'collection';
|
||||
workspace.scope = WorkspaceScopeKeys.collection;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -5,17 +5,20 @@ import {
|
||||
importRaw,
|
||||
importUri,
|
||||
} from '../../common/import';
|
||||
import type { Workspace } from '../../models/workspace';
|
||||
import type { Workspace, WorkspaceScope } from '../../models/workspace';
|
||||
import type { ImportRawConfig } from '../../common/import';
|
||||
|
||||
type PluginImportOptions = { workspaceId?: string, scope?: WorkspaceScope };
|
||||
|
||||
export function init(): { data: { import: Object, export: Object } } {
|
||||
return {
|
||||
data: {
|
||||
import: {
|
||||
async uri(uri: string, options: { workspaceId?: string } = {}): Promise<void> {
|
||||
await importUri(() => Promise.resolve(options.workspaceId || null), uri);
|
||||
async uri(uri: string, options: PluginImportOptions = {}): Promise<void> {
|
||||
await importUri(uri, buildImportRawConfig(options));
|
||||
},
|
||||
async raw(text: string, options: { workspaceId?: string } = {}): Promise<void> {
|
||||
await importRaw(() => Promise.resolve(options.workspaceId || null), text);
|
||||
async raw(text: string, options: PluginImportOptions = {}): Promise<void> {
|
||||
await importRaw(text, buildImportRawConfig(options));
|
||||
},
|
||||
},
|
||||
export: {
|
||||
@ -42,3 +45,9 @@ export function init(): { data: { import: Object, export: Object } } {
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function buildImportRawConfig(options: PluginImportOptions): ImportRawConfig {
|
||||
const getWorkspaceId = () => Promise.resolve(options.workspaceId || null);
|
||||
const getWorkspaceScope = options.scope && (() => Promise.resolve(options.scope));
|
||||
return { getWorkspaceId, getWorkspaceScope };
|
||||
}
|
||||
|
@ -4,12 +4,12 @@ import Hotkey from '../hotkey';
|
||||
import { hotKeyRefs } from '../../../common/hotkeys';
|
||||
import * as hotkeys from '../../../common/hotkeys';
|
||||
import type { Request } from '../../../models/request';
|
||||
import type { ForceToWorkspace } from '../../redux/modules/helpers';
|
||||
import { Pane, PaneBody, PaneHeader } from './pane';
|
||||
import type { HandleImportFileCallback } from '../wrapper';
|
||||
|
||||
type Props = {
|
||||
hotKeyRegistry: hotkeys.HotKeyRegistry,
|
||||
handleImportFile: (forceToWorkspace?: ForceToWorkspace) => void,
|
||||
handleImportFile: HandleImportFileCallback,
|
||||
handleCreateRequest: () => Promise<Request>,
|
||||
};
|
||||
|
||||
|
@ -28,11 +28,11 @@ import RenderedQueryString from '../rendered-query-string';
|
||||
import RequestUrlBar from '../request-url-bar.js';
|
||||
import type { Settings } from '../../../models/settings';
|
||||
import RequestParametersEditor from '../editors/request-parameters-editor';
|
||||
import type { ForceToWorkspace } from '../../redux/modules/helpers';
|
||||
import PlaceholderRequestPane from './placeholder-request-pane';
|
||||
import { Pane, paneBodyClasses, PaneHeader } from './pane';
|
||||
import classnames from 'classnames';
|
||||
import { queryAllWorkspaceUrls } from '../../../models/helpers/query-all-workspace-urls';
|
||||
import type { HandleImportFileCallback } from '../wrapper';
|
||||
|
||||
type Props = {
|
||||
// Functions
|
||||
@ -56,7 +56,7 @@ type Props = {
|
||||
updateSettingsUseBulkHeaderEditor: Function,
|
||||
updateSettingsUseBulkParametersEditor: Function,
|
||||
handleImport: Function,
|
||||
handleImportFile: (forceToWorkspace?: ForceToWorkspace) => void,
|
||||
handleImportFile: HandleImportFileCallback,
|
||||
|
||||
// Other
|
||||
workspace: Workspace,
|
||||
|
@ -2,7 +2,7 @@
|
||||
import * as React from 'react';
|
||||
import { autoBindMethodsForReact } from 'class-autobind-decorator';
|
||||
import PageLayout from './page-layout';
|
||||
import type { WrapperProps } from './wrapper';
|
||||
import type { HandleImportFileCallback, WrapperProps } from './wrapper';
|
||||
import RequestPane from './panes/request-pane';
|
||||
import ErrorBoundary from './error-boundary';
|
||||
import ResponsePane from './panes/response-pane';
|
||||
@ -11,7 +11,6 @@ import SidebarFilter from './sidebar/sidebar-filter';
|
||||
import EnvironmentsDropdown from './dropdowns/environments-dropdown';
|
||||
import { AUTOBIND_CFG } from '../../common/constants';
|
||||
import { isGrpcRequest } from '../../models/helpers/is-model';
|
||||
import type { ForceToWorkspace } from '../redux/modules/helpers';
|
||||
import GrpcRequestPane from './panes/grpc-request-pane';
|
||||
import GrpcResponsePane from './panes/grpc-response-pane';
|
||||
import WorkspacePageHeader from './workspace-page-header';
|
||||
@ -31,7 +30,7 @@ type Props = {
|
||||
handleForceUpdateRequest: Function,
|
||||
handleForceUpdateRequestHeaders: Function,
|
||||
handleImport: Function,
|
||||
handleImportFile: (forceToWorkspace?: ForceToWorkspace) => void,
|
||||
handleImportFile: HandleImportFileCallback,
|
||||
handleRequestCreate: Function,
|
||||
handleRequestGroupCreate: Function,
|
||||
handleSendAndDownloadRequestWithActiveEnvironment: Function,
|
||||
|
@ -37,11 +37,15 @@ import Highlight from './base/highlight';
|
||||
import type { GlobalActivity } from '../../common/constants';
|
||||
|
||||
import { fuzzyMatchAll } from '../../common/misc';
|
||||
import type { WrapperProps } from './wrapper';
|
||||
import type {
|
||||
HandleImportClipboardCallback,
|
||||
HandleImportFileCallback,
|
||||
HandleImportUriCallback,
|
||||
WrapperProps,
|
||||
} from './wrapper';
|
||||
import Notice from './notice';
|
||||
import GitRepositorySettingsModal from '../components/modals/git-repository-settings-modal';
|
||||
import PageLayout from './page-layout';
|
||||
import type { ForceToWorkspace } from '../redux/modules/helpers';
|
||||
import { ForceToWorkspaceKeys } from '../redux/modules/helpers';
|
||||
import coreLogo from '../images/insomnia-core-logo.png';
|
||||
import { MemPlugin } from '../../sync/git/mem-plugin';
|
||||
@ -58,9 +62,9 @@ import AccountDropdown from './dropdowns/account-dropdown';
|
||||
|
||||
type Props = {|
|
||||
wrapperProps: WrapperProps,
|
||||
handleImportFile: (forceToWorkspace: ForceToWorkspace) => void,
|
||||
handleImportUri: (uri: string, forceToWorkspace: ForceToWorkspace) => void,
|
||||
handleImportClipboard: (forceToWorkspace: ForceToWorkspace) => void,
|
||||
handleImportFile: HandleImportFileCallback,
|
||||
handleImportUri: HandleImportUriCallback,
|
||||
handleImportClipboard: HandleImportClipboardCallback,
|
||||
|};
|
||||
|
||||
type State = {|
|
||||
@ -121,11 +125,11 @@ class WrapperHome extends React.PureComponent<Props, State> {
|
||||
}
|
||||
|
||||
_handleImportFile() {
|
||||
this.props.handleImportFile(ForceToWorkspaceKeys.new);
|
||||
this.props.handleImportFile({ forceToWorkspace: ForceToWorkspaceKeys.new });
|
||||
}
|
||||
|
||||
_handleImportClipBoard() {
|
||||
this.props.handleImportClipboard(ForceToWorkspaceKeys.new);
|
||||
this.props.handleImportClipboard({ forceToWorkspace: ForceToWorkspaceKeys.new });
|
||||
}
|
||||
|
||||
_handleImportUri() {
|
||||
@ -135,7 +139,7 @@ class WrapperHome extends React.PureComponent<Props, State> {
|
||||
label: 'URL',
|
||||
placeholder: 'https://website.com/insomnia-import.json',
|
||||
onComplete: uri => {
|
||||
this.props.handleImportUri(uri, ForceToWorkspaceKeys.new);
|
||||
this.props.handleImportUri(uri, { forceToWorkspace: ForceToWorkspaceKeys.new });
|
||||
},
|
||||
});
|
||||
}
|
||||
@ -446,7 +450,7 @@ class WrapperHome extends React.PureComponent<Props, State> {
|
||||
<Dropdown renderButton={button}>
|
||||
<DropdownDivider>New</DropdownDivider>
|
||||
<DropdownItem icon={<i className="fa fa-file-o" />} onClick={this._handleDocumentCreate}>
|
||||
Blank Document
|
||||
Design Document
|
||||
</DropdownItem>
|
||||
<DropdownItem icon={<i className="fa fa-bars" />} onClick={this._handleCollectionCreate}>
|
||||
Request Collection
|
||||
@ -495,7 +499,7 @@ class WrapperHome extends React.PureComponent<Props, State> {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { workspaces } = this.props.wrapperProps;
|
||||
const { workspaces, isLoading } = this.props.wrapperProps;
|
||||
const { filter } = this.state;
|
||||
|
||||
// Render each card, removing all the ones that don't match the filter
|
||||
@ -511,6 +515,7 @@ class WrapperHome extends React.PureComponent<Props, State> {
|
||||
<React.Fragment>
|
||||
<img src={coreLogo} alt="Insomnia" width="24" height="24" />
|
||||
<Breadcrumb className="breadcrumb" crumbs={[getAppName()]} />
|
||||
{isLoading ? <i className="fa fa-refresh fa-spin space-left" /> : null}
|
||||
</React.Fragment>
|
||||
}
|
||||
gridRight={
|
||||
|
@ -6,17 +6,17 @@ import { showPrompt } from './modals';
|
||||
import type { BaseModel } from '../../models';
|
||||
import * as models from '../../models';
|
||||
import { AUTOBIND_CFG, getAppLongName, getAppName } from '../../common/constants';
|
||||
import type { WrapperProps } from './wrapper';
|
||||
import type { HandleImportFileCallback, HandleImportUriCallback, WrapperProps } from './wrapper';
|
||||
import * as db from '../../common/database';
|
||||
import chartSrc from '../images/chart.svg';
|
||||
import type { ForceToWorkspace } from '../redux/modules/helpers';
|
||||
import { ForceToWorkspaceKeys } from '../redux/modules/helpers';
|
||||
import OnboardingContainer from './onboarding-container';
|
||||
import { WorkspaceScopeKeys } from '../../models/workspace';
|
||||
|
||||
type Props = {|
|
||||
wrapperProps: WrapperProps,
|
||||
handleImportFile: (forceToWorkspace: ForceToWorkspace) => any,
|
||||
handleImportUri: (uri: string, forceToWorkspace: ForceToWorkspace) => any,
|
||||
handleImportFile: HandleImportFileCallback,
|
||||
handleImportUri: HandleImportUriCallback,
|
||||
|};
|
||||
|
||||
type State = {|
|
||||
@ -77,7 +77,10 @@ class WrapperOnboarding extends React.PureComponent<Props, State> {
|
||||
|
||||
_handleImportFile() {
|
||||
const { handleImportFile } = this.props;
|
||||
handleImportFile(ForceToWorkspaceKeys.new);
|
||||
handleImportFile({
|
||||
forceToWorkspace: ForceToWorkspaceKeys.new,
|
||||
forceToScope: WorkspaceScopeKeys.designer,
|
||||
});
|
||||
}
|
||||
|
||||
_handleImportUri(defaultValue: string) {
|
||||
@ -89,7 +92,10 @@ class WrapperOnboarding extends React.PureComponent<Props, State> {
|
||||
placeholder: 'https://example.com/openapi-spec.yaml',
|
||||
label: 'URI to Import',
|
||||
onComplete: value => {
|
||||
handleImportUri(value, ForceToWorkspaceKeys.new);
|
||||
handleImportUri(value, {
|
||||
forceToWorkspace: ForceToWorkspaceKeys.new,
|
||||
forceToScope: WorkspaceScopeKeys.designer,
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
@ -86,7 +86,6 @@ import WrapperDebug from './wrapper-debug';
|
||||
import { importRaw } from '../../common/import';
|
||||
import GitSyncDropdown from './dropdowns/git-sync-dropdown';
|
||||
import { DropdownButton } from './base/dropdown';
|
||||
import type { ForceToWorkspace } from '../redux/modules/helpers';
|
||||
import type { UnitTest } from '../../models/unit-test';
|
||||
import type { UnitTestResult } from '../../models/unit-test-result';
|
||||
import type { UnitTestSuite } from '../../models/unit-test-suite';
|
||||
@ -95,6 +94,7 @@ import { Spectral } from '@stoplight/spectral';
|
||||
import ProtoFilesModal from './modals/proto-files-modal';
|
||||
import { GrpcDispatchModalWrapper } from '../context/grpc';
|
||||
import WrapperMigration from './wrapper-migration';
|
||||
import type { ImportOptions } from '../redux/modules/global';
|
||||
|
||||
const spectral = new Spectral();
|
||||
|
||||
@ -103,16 +103,9 @@ export type WrapperProps = {
|
||||
handleActivateRequest: Function,
|
||||
handleSetSidebarFilter: Function,
|
||||
handleToggleMenuBar: Function,
|
||||
handleImportFileToWorkspace: (workspaceId: string, forceToWorkspace?: ForceToWorkspace) => void,
|
||||
handleImportClipBoardToWorkspace: (
|
||||
workspaceId: string,
|
||||
forceToWorkspace?: ForceToWorkspace,
|
||||
) => void,
|
||||
handleImportUriToWorkspace: (
|
||||
workspaceId: string,
|
||||
uri: string,
|
||||
forceToWorkspace?: ForceToWorkspace,
|
||||
) => void,
|
||||
handleImportFileToWorkspace: (workspaceId: string, options?: ImportOptions) => void,
|
||||
handleImportClipBoardToWorkspace: (workspaceId: string, options?: ImportOptions) => void,
|
||||
handleImportUriToWorkspace: (workspaceId: string, uri: string, options?: ImportOptions) => void,
|
||||
handleInitializeEntities: () => Promise<void>,
|
||||
handleExportFile: Function,
|
||||
handleShowExportRequestsModal: Function,
|
||||
@ -205,6 +198,10 @@ export type WrapperProps = {
|
||||
activeResponse: Response | null,
|
||||
};
|
||||
|
||||
export type HandleImportFileCallback = (options?: ImportOptions) => void;
|
||||
export type HandleImportClipboardCallback = (options?: ImportOptions) => void;
|
||||
export type HandleImportUriCallback = (uri: string, options?: ImportOptions) => void;
|
||||
|
||||
type State = {
|
||||
forceRefreshKey: number,
|
||||
activeGitBranch: string,
|
||||
@ -348,7 +345,9 @@ class Wrapper extends React.PureComponent<WrapperProps, State> {
|
||||
// Delaying generation so design to debug mode is smooth
|
||||
handleSetActiveActivity(nextActivity);
|
||||
setTimeout(() => {
|
||||
importRaw(() => Promise.resolve(workspaceId), activeApiSpec.contents);
|
||||
importRaw(activeApiSpec.contents, {
|
||||
getWorkspaceId: () => Promise.resolve(workspaceId),
|
||||
});
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
@ -367,16 +366,16 @@ class Wrapper extends React.PureComponent<WrapperProps, State> {
|
||||
return sUpdate(this.props.settings, { useBulkParametersEditor });
|
||||
}
|
||||
|
||||
_handleImportFile(forceToWorkspace?: ForceToWorkspace): void {
|
||||
this.props.handleImportFileToWorkspace(this.props.activeWorkspace._id, forceToWorkspace);
|
||||
_handleImportFile(options?: ImportOptions): void {
|
||||
this.props.handleImportFileToWorkspace(this.props.activeWorkspace._id, options);
|
||||
}
|
||||
|
||||
_handleImportUri(uri: string, forceToWorkspace?: ForceToWorkspace): void {
|
||||
this.props.handleImportUriToWorkspace(this.props.activeWorkspace._id, uri, forceToWorkspace);
|
||||
_handleImportUri(uri: string, options?: ImportOptions): void {
|
||||
this.props.handleImportUriToWorkspace(this.props.activeWorkspace._id, uri, options);
|
||||
}
|
||||
|
||||
_handleImportClipBoard(forceToWorkspace?: ForceToWorkspace): void {
|
||||
this.props.handleImportClipBoardToWorkspace(this.props.activeWorkspace._id, forceToWorkspace);
|
||||
_handleImportClipBoard(options?: ImportOptions): void {
|
||||
this.props.handleImportClipBoardToWorkspace(this.props.activeWorkspace._id, options);
|
||||
}
|
||||
|
||||
_handleSetActiveResponse(responseId: string | null): void {
|
||||
|
@ -7,7 +7,7 @@ import path from 'path';
|
||||
import AskModal from '../../../ui/components/modals/ask-modal';
|
||||
import * as moment from 'moment';
|
||||
|
||||
import type { ImportResult } from '../../../common/import';
|
||||
import type { ImportRawConfig, ImportResult } from '../../../common/import';
|
||||
import * as importUtils from '../../../common/import';
|
||||
import AlertModal from '../../components/modals/alert-modal';
|
||||
import PaymentNotificationModal from '../../components/modals/payment-notification-modal';
|
||||
@ -24,12 +24,12 @@ import SettingsModal, {
|
||||
} from '../../components/modals/settings-modal';
|
||||
import install from '../../../plugins/install';
|
||||
import type { ForceToWorkspace } from './helpers';
|
||||
import { askToImportIntoWorkspace } from './helpers';
|
||||
import { askToImportIntoWorkspace, askToSetWorkspaceScope } from './helpers';
|
||||
import { createPlugin } from '../../../plugins/create';
|
||||
import { reloadPlugins } from '../../../plugins';
|
||||
import { setTheme } from '../../../plugins/misc';
|
||||
import type { GlobalActivity } from '../../../common/constants';
|
||||
import type { Workspace } from '../../../models/workspace';
|
||||
import type { Workspace, WorkspaceScope } from '../../../models/workspace';
|
||||
import {
|
||||
ACTIVITY_DEBUG,
|
||||
ACTIVITY_HOME,
|
||||
@ -293,7 +293,15 @@ export function setActiveWorkspace(workspaceId: string) {
|
||||
return { type: SET_ACTIVE_WORKSPACE, workspaceId };
|
||||
}
|
||||
|
||||
export function importFile(workspaceId: string, forceToWorkspace?: ForceToWorkspace) {
|
||||
export type ImportOptions = {
|
||||
forceToWorkspace?: ForceToWorkspace,
|
||||
forceToScope?: WorkspaceScope,
|
||||
};
|
||||
|
||||
export function importFile(
|
||||
workspaceId: string,
|
||||
{ forceToScope, forceToWorkspace }: ImportOptions = {},
|
||||
) {
|
||||
return async dispatch => {
|
||||
dispatch(loadStart());
|
||||
|
||||
@ -329,28 +337,22 @@ export function importFile(workspaceId: string, forceToWorkspace?: ForceToWorksp
|
||||
}
|
||||
|
||||
// Let's import all the paths!
|
||||
let importedWorkspaces = [];
|
||||
for (const p of paths) {
|
||||
try {
|
||||
const uri = `file://${p}`;
|
||||
const result = await importUtils.importUri(
|
||||
askToImportIntoWorkspace(workspaceId, forceToWorkspace),
|
||||
uri,
|
||||
);
|
||||
importedWorkspaces = handleImportResult(
|
||||
result,
|
||||
'The file does not contain a valid specification.',
|
||||
);
|
||||
|
||||
const options: ImportRawConfig = {
|
||||
getWorkspaceScope: askToSetWorkspaceScope(forceToScope),
|
||||
getWorkspaceId: askToImportIntoWorkspace(workspaceId, forceToWorkspace),
|
||||
};
|
||||
const result = await importUtils.importUri(uri, options);
|
||||
handleImportResult(result, 'The file does not contain a valid specification.');
|
||||
} catch (err) {
|
||||
showModal(AlertModal, { title: 'Import Failed', message: err + '' });
|
||||
} finally {
|
||||
dispatch(loadStop());
|
||||
}
|
||||
}
|
||||
|
||||
if (importedWorkspaces.length === 1) {
|
||||
dispatch(setActiveWorkspace(importedWorkspaces[0]._id));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -369,7 +371,10 @@ function handleImportResult(result: ImportResult, errorMessage: string): Array<W
|
||||
return summary[models.workspace.type] || [];
|
||||
}
|
||||
|
||||
export function importClipBoard(workspaceId: string, forceToWorkspace?: ForceToWorkspace) {
|
||||
export function importClipBoard(
|
||||
workspaceId: string,
|
||||
{ forceToScope, forceToWorkspace }: ImportOptions = {},
|
||||
) {
|
||||
return async dispatch => {
|
||||
dispatch(loadStart());
|
||||
const schema = electron.clipboard.readText();
|
||||
@ -381,16 +386,13 @@ export function importClipBoard(workspaceId: string, forceToWorkspace?: ForceToW
|
||||
return;
|
||||
}
|
||||
// Let's import all the paths!
|
||||
let importedWorkspaces = [];
|
||||
try {
|
||||
const result = await importUtils.importRaw(
|
||||
askToImportIntoWorkspace(workspaceId, forceToWorkspace),
|
||||
schema,
|
||||
);
|
||||
importedWorkspaces = handleImportResult(
|
||||
result,
|
||||
'Your clipboard does not contain a valid specification.',
|
||||
);
|
||||
const options: ImportRawConfig = {
|
||||
getWorkspaceScope: askToSetWorkspaceScope(forceToScope),
|
||||
getWorkspaceId: askToImportIntoWorkspace(workspaceId, forceToWorkspace),
|
||||
};
|
||||
const result = await importUtils.importRaw(schema, options);
|
||||
handleImportResult(result, 'Your clipboard does not contain a valid specification.');
|
||||
} catch (err) {
|
||||
showModal(AlertModal, {
|
||||
title: 'Import Failed',
|
||||
@ -399,35 +401,29 @@ export function importClipBoard(workspaceId: string, forceToWorkspace?: ForceToW
|
||||
} finally {
|
||||
dispatch(loadStop());
|
||||
}
|
||||
if (importedWorkspaces.length === 1) {
|
||||
dispatch(setActiveWorkspace(importedWorkspaces[0]._id));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function importUri(workspaceId: string, uri: string, forceToWorkspace?: ForceToWorkspace) {
|
||||
export function importUri(
|
||||
workspaceId: string,
|
||||
uri: string,
|
||||
{ forceToScope, forceToWorkspace }: ImportOptions = {},
|
||||
) {
|
||||
return async dispatch => {
|
||||
dispatch(loadStart());
|
||||
|
||||
let importedWorkspaces = [];
|
||||
try {
|
||||
const result = await importUtils.importUri(
|
||||
askToImportIntoWorkspace(workspaceId, forceToWorkspace),
|
||||
uri,
|
||||
);
|
||||
importedWorkspaces = handleImportResult(
|
||||
result,
|
||||
'The URI does not contain a valid specification.',
|
||||
);
|
||||
const options: ImportRawConfig = {
|
||||
getWorkspaceScope: askToSetWorkspaceScope(forceToScope),
|
||||
getWorkspaceId: askToImportIntoWorkspace(workspaceId, forceToWorkspace),
|
||||
};
|
||||
const result = await importUtils.importUri(uri, options);
|
||||
handleImportResult(result, 'The URI does not contain a valid specification.');
|
||||
} catch (err) {
|
||||
showModal(AlertModal, { title: 'Import Failed', message: err + '' });
|
||||
} finally {
|
||||
dispatch(loadStop());
|
||||
}
|
||||
|
||||
if (importedWorkspaces.length === 1) {
|
||||
dispatch(setActiveWorkspace(importedWorkspaces[0]._id));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
// @flow
|
||||
import { showModal } from '../../components/modals';
|
||||
import AskModal from '../../components/modals/ask-modal';
|
||||
import { WorkspaceScopeKeys } from '../../../models/workspace';
|
||||
|
||||
export const ForceToWorkspaceKeys = {
|
||||
new: 'new',
|
||||
@ -31,3 +32,25 @@ export function askToImportIntoWorkspace(workspaceId: string, forceToWorkspace?:
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function askToSetWorkspaceScope(scope?: WorkspaceScope) {
|
||||
return function(name: string) {
|
||||
switch (scope) {
|
||||
case WorkspaceScopeKeys.collection:
|
||||
case WorkspaceScopeKeys.designer:
|
||||
return scope;
|
||||
default:
|
||||
return new Promise(resolve => {
|
||||
showModal(AskModal, {
|
||||
title: 'Import As',
|
||||
message: `How would you like to import "${name}"?`,
|
||||
noText: 'Request Collection',
|
||||
yesText: 'Design Document',
|
||||
onDone: yes => {
|
||||
resolve(yes ? WorkspaceScopeKeys.designer : WorkspaceScopeKeys.collection);
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -60,6 +60,7 @@ module.exports.convert = async function(rawData) {
|
||||
parentId: null,
|
||||
name: `${api.info.title} ${api.info.version}`,
|
||||
description: api.info.description || '',
|
||||
// scope is not set because it could be imported for design OR to generate requests
|
||||
};
|
||||
|
||||
const baseEnv = {
|
||||
|
@ -41,6 +41,7 @@ module.exports.convert = async function(rawData) {
|
||||
parentId: null,
|
||||
name: `${api.info.title} ${api.info.version}`,
|
||||
description: api.info.description || '',
|
||||
// scope is not set because it could be imported for design OR to generate requests
|
||||
};
|
||||
|
||||
const baseEnv = {
|
||||
|
Loading…
Reference in New Issue
Block a user