mirror of
https://github.com/Kong/insomnia
synced 2024-11-07 22:30:15 +00:00
Prompt Template Tag and Plugin arg validation (#673)
* Plugin arg validation, prompt tag, and some changes needed * Version bumps
This commit is contained in:
parent
4e0fe5d78a
commit
aba3c8ed86
@ -382,4 +382,30 @@ describe('render()', () => {
|
||||
expect(err.message).toBe('unknown block tag: invalid');
|
||||
}
|
||||
});
|
||||
|
||||
it('outputs correct error path', async () => {
|
||||
const template = {
|
||||
foo: [{bar: '{% foo %}'}]
|
||||
};
|
||||
|
||||
try {
|
||||
await renderUtils.render(template);
|
||||
fail('Should have failed to render');
|
||||
} catch (err) {
|
||||
expect(err.path).toBe('foo[0].bar');
|
||||
}
|
||||
});
|
||||
|
||||
it('outputs correct error path when private first node', async () => {
|
||||
const template = {
|
||||
_foo: {_bar: {baz: '{% foo %}'}}
|
||||
};
|
||||
|
||||
try {
|
||||
await renderUtils.render(template);
|
||||
fail('Should have failed to render');
|
||||
} catch (err) {
|
||||
expect(err.path).toBe('_bar.baz');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -12,6 +12,8 @@ import type {Environment} from '../models/environment';
|
||||
|
||||
export const KEEP_ON_ERROR = 'keep';
|
||||
export const THROW_ON_ERROR = 'throw';
|
||||
export const RENDER_PURPOSE_SEND = 'send';
|
||||
export const RENDER_PURPOSE_GENERAL = 'general';
|
||||
|
||||
export type RenderedRequest = Request & {
|
||||
cookies: Array<{name: string, value: string, disabled?: boolean}>,
|
||||
@ -112,7 +114,7 @@ export async function render<T> (
|
||||
// Make a deep copy so no one gets mad :)
|
||||
const newObj = clone(obj);
|
||||
|
||||
async function next (x: any, path: string = name): Promise<any> {
|
||||
async function next (x: any, path: string, first: boolean = false): Promise<any> {
|
||||
if (blacklistPathRegex && path.match(blacklistPathRegex)) {
|
||||
return x;
|
||||
}
|
||||
@ -158,21 +160,26 @@ export async function render<T> (
|
||||
|
||||
const keys = Object.keys(x);
|
||||
for (const key of keys) {
|
||||
if (first && key.indexOf('_') === 0) {
|
||||
x[key] = await next(x[key], path);
|
||||
} else {
|
||||
const pathPrefix = path ? path + '.' : '';
|
||||
x[key] = await next(x[key], `${pathPrefix}${key}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
return next(newObj);
|
||||
return next(newObj, name, true);
|
||||
}
|
||||
|
||||
export async function getRenderContext (
|
||||
request: Request,
|
||||
environmentId: string,
|
||||
ancestors: Array<BaseModel> | null = null
|
||||
ancestors: Array<BaseModel> | null = null,
|
||||
purpose: string | null = null
|
||||
): Promise<Object> {
|
||||
if (!request) {
|
||||
return {};
|
||||
@ -201,21 +208,22 @@ export async function getRenderContext (
|
||||
workspaceId: workspace ? workspace._id : 'n/a'
|
||||
});
|
||||
|
||||
baseContext.getPurpose = () => purpose;
|
||||
|
||||
// Generate the context we need to render
|
||||
const context = await buildRenderContext(
|
||||
return await buildRenderContext(
|
||||
ancestors,
|
||||
rootEnvironment,
|
||||
subEnvironment,
|
||||
baseContext
|
||||
);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
export async function getRenderedRequest (
|
||||
export async function getRenderedRequestAndContext (
|
||||
request: Request,
|
||||
environmentId: string
|
||||
): Promise<RenderedRequest> {
|
||||
environmentId: string,
|
||||
purpose?: string
|
||||
): Promise<{request: RenderedRequest, context: Object}> {
|
||||
const ancestors = await db.withAncestors(request, [
|
||||
models.request.type,
|
||||
models.requestGroup.type,
|
||||
@ -225,20 +233,17 @@ export async function getRenderedRequest (
|
||||
const parentId = workspace ? workspace._id : 'n/a';
|
||||
const cookieJar = await models.cookieJar.getOrCreateForParentId(parentId);
|
||||
|
||||
const renderContext = await getRenderContext(request, environmentId, ancestors);
|
||||
const renderContext = await getRenderContext(request, environmentId, ancestors, purpose);
|
||||
|
||||
// Render all request properties
|
||||
const renderedRequest = await render(
|
||||
request,
|
||||
const renderResult = await render(
|
||||
{_request: request, _cookieJar: cookieJar},
|
||||
renderContext,
|
||||
request.settingDisableRenderRequestBody ? /^body.*/ : null
|
||||
);
|
||||
|
||||
// Render cookies
|
||||
const renderedCookieJar = await render(
|
||||
cookieJar,
|
||||
renderContext
|
||||
);
|
||||
const renderedRequest = renderResult._request;
|
||||
const renderedCookieJar = renderResult._cookieJar;
|
||||
|
||||
// Remove disabled params
|
||||
renderedRequest.parameters = renderedRequest.parameters.filter(p => !p.disabled);
|
||||
@ -260,6 +265,8 @@ export async function getRenderedRequest (
|
||||
renderedRequest.url = setDefaultProtocol(renderedRequest.url);
|
||||
|
||||
return {
|
||||
context: renderContext,
|
||||
request: {
|
||||
// Add the yummy cookies
|
||||
// TODO: Eventually get rid of RenderedRequest type and put these elsewhere
|
||||
cookieJar: renderedCookieJar,
|
||||
@ -285,9 +292,19 @@ export async function getRenderedRequest (
|
||||
settingStoreCookies: renderedRequest.settingStoreCookies,
|
||||
type: renderedRequest.type,
|
||||
url: renderedRequest.url
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export async function getRenderedRequest (
|
||||
request: Request,
|
||||
environmentId: string,
|
||||
purpose?: string
|
||||
): Promise<RenderedRequest> {
|
||||
const result = await getRenderedRequestAndContext(request, environmentId, purpose);
|
||||
return result.request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort the keys that may have Nunjucks last, so that other keys get
|
||||
* defined first. Very important if env variables defined in same obj
|
||||
|
@ -4,7 +4,7 @@ import type {Request, RequestHeader} from '../models/request';
|
||||
import type {Workspace} from '../models/workspace';
|
||||
import type {Settings} from '../models/settings';
|
||||
import type {RenderedRequest} from '../common/render';
|
||||
import {getRenderContext, getRenderedRequest} from '../common/render';
|
||||
import {getRenderedRequest, getRenderedRequestAndContext, RENDER_PURPOSE_SEND} from '../common/render';
|
||||
import mkdirp from 'mkdirp';
|
||||
import clone from 'clone';
|
||||
import {parse as urlParse, resolve as urlResolve} from 'url';
|
||||
@ -15,7 +15,7 @@ import * as electron from 'electron';
|
||||
import * as models from '../models';
|
||||
import {AUTH_AWS_IAM, AUTH_BASIC, AUTH_DIGEST, AUTH_NETRC, AUTH_NTLM, CONTENT_TYPE_FORM_DATA, CONTENT_TYPE_FORM_URLENCODED, getAppVersion, getTempDir, STATUS_CODE_PLUGIN_ERROR} from '../common/constants';
|
||||
import {delay, describeByteSize, getContentTypeHeader, getLocationHeader, getSetCookieHeaders, hasAcceptEncodingHeader, hasAcceptHeader, hasAuthHeader, hasContentTypeHeader, hasUserAgentHeader, waitForStreamToFinish} from '../common/misc';
|
||||
import {setDefaultProtocol, smartEncodeUrl, buildQueryStringFromParams, joinUrlAndQueryString} from 'insomnia-url';
|
||||
import {buildQueryStringFromParams, joinUrlAndQueryString, setDefaultProtocol, smartEncodeUrl} from 'insomnia-url';
|
||||
import fs from 'fs';
|
||||
import * as db from '../common/database';
|
||||
import * as CACerts from './cacert';
|
||||
@ -733,8 +733,14 @@ export async function send (
|
||||
throw new Error(`Failed to find request to send for ${requestId}`);
|
||||
}
|
||||
|
||||
const renderedRequestBeforePlugins = await getRenderedRequest(request, environmentId);
|
||||
const renderedContextBeforePlugins = await getRenderContext(request, environmentId, ancestors);
|
||||
const renderResult = await getRenderedRequestAndContext(
|
||||
request,
|
||||
environmentId,
|
||||
RENDER_PURPOSE_SEND
|
||||
);
|
||||
|
||||
const renderedRequestBeforePlugins = renderResult.request;
|
||||
const renderedContextBeforePlugins = renderResult.context;
|
||||
|
||||
const workspaceDoc = ancestors.find(doc => doc.type === models.workspace.type);
|
||||
const workspace = await models.workspace.getById(workspaceDoc ? workspaceDoc._id : 'n/a');
|
||||
@ -775,8 +781,8 @@ async function _applyRequestPluginHooks (
|
||||
newRenderedRequest = clone(newRenderedRequest);
|
||||
|
||||
const context = {
|
||||
...pluginContexts.app.init(plugin),
|
||||
...pluginContexts.request.init(plugin, newRenderedRequest, renderedContext)
|
||||
...pluginContexts.app.init(),
|
||||
...pluginContexts.request.init(newRenderedRequest, renderedContext)
|
||||
};
|
||||
|
||||
try {
|
||||
@ -795,8 +801,8 @@ async function _applyResponsePluginHooks (
|
||||
): Promise<void> {
|
||||
for (const {plugin, hook} of await plugins.getResponseHooks()) {
|
||||
const context = {
|
||||
...pluginContexts.app.init(plugin),
|
||||
...pluginContexts.response.init(plugin, response)
|
||||
...pluginContexts.app.init(),
|
||||
...pluginContexts.response.init(response)
|
||||
};
|
||||
|
||||
try {
|
||||
|
@ -1,22 +1,17 @@
|
||||
import * as plugin from '../app';
|
||||
import * as modals from '../../../ui/components/modals';
|
||||
import {globalBeforeEach} from '../../../__jest__/before-each';
|
||||
|
||||
const PLUGIN = {
|
||||
name: 'my-plugin',
|
||||
version: '1.0.0',
|
||||
directory: '/plugins/my-plugin',
|
||||
module: {}
|
||||
};
|
||||
import {RENDER_PURPOSE_SEND} from '../../../common/render';
|
||||
|
||||
describe('init()', () => {
|
||||
beforeEach(globalBeforeEach);
|
||||
it('initializes correctly', async () => {
|
||||
const result = plugin.init({name: PLUGIN});
|
||||
const result = plugin.init();
|
||||
expect(Object.keys(result)).toEqual(['app']);
|
||||
expect(Object.keys(result.app).sort()).toEqual([
|
||||
'alert',
|
||||
'getPath',
|
||||
'prompt',
|
||||
'showSaveDialog'
|
||||
]);
|
||||
});
|
||||
@ -24,18 +19,56 @@ describe('init()', () => {
|
||||
|
||||
describe('app.alert()', () => {
|
||||
beforeEach(globalBeforeEach);
|
||||
it('shows alert with message', async () => {
|
||||
it('does not show alert when not sending', async () => {
|
||||
modals.showAlert = jest.fn();
|
||||
const result = plugin.init();
|
||||
|
||||
result.app.alert();
|
||||
|
||||
// Make sure it passes correct arguments
|
||||
expect(modals.showAlert.mock.calls).toEqual([]);
|
||||
});
|
||||
|
||||
it('shows alert with message when sending', async () => {
|
||||
modals.showAlert = jest.fn().mockReturnValue('dummy-return-value');
|
||||
const result = plugin.init(PLUGIN);
|
||||
const result = plugin.init(RENDER_PURPOSE_SEND);
|
||||
|
||||
// Make sure it returns result of showAlert()
|
||||
expect(result.app.alert()).toBe('dummy-return-value');
|
||||
expect(result.app.alert('My message')).toBe('dummy-return-value');
|
||||
expect(result.app.alert({title: 'My message'})).toBe('dummy-return-value');
|
||||
|
||||
// Make sure it passes correct arguments
|
||||
expect(modals.showAlert.mock.calls).toEqual([
|
||||
[{message: '', title: 'Plugin my-plugin'}],
|
||||
[{message: 'My message', title: 'Plugin my-plugin'}]
|
||||
[{}],
|
||||
[{title: 'My message'}]
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('app.prompt()', () => {
|
||||
beforeEach(globalBeforeEach);
|
||||
it('does not show prompt when not sending', async () => {
|
||||
modals.showPrompt = jest.fn();
|
||||
const result = plugin.init();
|
||||
|
||||
result.app.prompt();
|
||||
|
||||
// Make sure it passes correct arguments
|
||||
expect(modals.showPrompt.mock.calls).toEqual([]);
|
||||
});
|
||||
|
||||
it('shows alert with message when sending', async () => {
|
||||
modals.showPrompt = jest.fn();
|
||||
const result = plugin.init(RENDER_PURPOSE_SEND);
|
||||
|
||||
// Make sure it returns result of showAlert()
|
||||
result.app.prompt();
|
||||
result.app.prompt({title: 'My message'});
|
||||
|
||||
// Make sure it passes correct arguments
|
||||
expect(modals.showPrompt.mock.calls).toEqual([
|
||||
[{cancelable: false, onComplete: expect.any(Function)}],
|
||||
[{cancelable: false, onComplete: expect.any(Function), title: 'My message'}]
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
@ -2,13 +2,6 @@ import * as plugin from '../request';
|
||||
import * as models from '../../../models';
|
||||
import {globalBeforeEach} from '../../../__jest__/before-each';
|
||||
|
||||
const PLUGIN = {
|
||||
name: 'my-plugin',
|
||||
version: '1.0.0',
|
||||
directory: '/plugins/my-plugin',
|
||||
module: {}
|
||||
};
|
||||
|
||||
const CONTEXT = {
|
||||
user_key: 'my_user_key',
|
||||
hello: 'world',
|
||||
@ -25,7 +18,7 @@ describe('init()', () => {
|
||||
});
|
||||
|
||||
it('initializes correctly', async () => {
|
||||
const result = plugin.init(PLUGIN, await models.request.getById('req_1'), CONTEXT);
|
||||
const result = plugin.init(await models.request.getById('req_1'), CONTEXT);
|
||||
expect(Object.keys(result)).toEqual(['request']);
|
||||
expect(Object.keys(result.request).sort()).toEqual([
|
||||
'addHeader',
|
||||
@ -49,7 +42,7 @@ describe('init()', () => {
|
||||
});
|
||||
|
||||
it('fails to initialize without request', () => {
|
||||
expect(() => plugin.init(PLUGIN))
|
||||
expect(() => plugin.init())
|
||||
.toThrowError('contexts.request initialized without request');
|
||||
});
|
||||
});
|
||||
@ -70,7 +63,7 @@ describe('request.*', () => {
|
||||
});
|
||||
|
||||
it('works for basic getters', async () => {
|
||||
const result = plugin.init(PLUGIN, await models.request.getById('req_1'), CONTEXT);
|
||||
const result = plugin.init(await models.request.getById('req_1'), CONTEXT);
|
||||
expect(result.request.getId()).toBe('req_1');
|
||||
expect(result.request.getName()).toBe('My Request');
|
||||
expect(result.request.getUrl()).toBe('');
|
||||
@ -78,7 +71,7 @@ describe('request.*', () => {
|
||||
});
|
||||
|
||||
it('works for headers', async () => {
|
||||
const result = plugin.init(PLUGIN, await models.request.getById('req_1'), CONTEXT);
|
||||
const result = plugin.init(await models.request.getById('req_1'), CONTEXT);
|
||||
|
||||
// getHeaders()
|
||||
expect(result.request.getHeaders()).toEqual([
|
||||
@ -112,7 +105,7 @@ describe('request.*', () => {
|
||||
const request = await models.request.getById('req_1');
|
||||
request.cookies = []; // Because the plugin technically needs a RenderedRequest
|
||||
|
||||
const result = plugin.init(PLUGIN, request, CONTEXT);
|
||||
const result = plugin.init(request, CONTEXT);
|
||||
|
||||
result.request.setCookie('foo', 'bar');
|
||||
result.request.setCookie('foo', 'baz');
|
||||
@ -123,7 +116,7 @@ describe('request.*', () => {
|
||||
const request = await models.request.getById('req_1');
|
||||
request.cookies = []; // Because the plugin technically needs a RenderedRequest
|
||||
|
||||
const result = plugin.init(PLUGIN, request, CONTEXT);
|
||||
const result = plugin.init(request, CONTEXT);
|
||||
|
||||
// getEnvironment
|
||||
expect(result.request.getEnvironment()).toEqual({
|
||||
|
@ -5,17 +5,10 @@ import fs from 'fs';
|
||||
import path from 'path';
|
||||
import * as models from '../../../models/index';
|
||||
|
||||
const PLUGIN = {
|
||||
name: 'my-plugin',
|
||||
version: '1.0.0',
|
||||
directory: '/plugins/my-plugin',
|
||||
module: {}
|
||||
};
|
||||
|
||||
describe('init()', () => {
|
||||
beforeEach(globalBeforeEach);
|
||||
it('initializes correctly', async () => {
|
||||
const result = plugin.init(PLUGIN, {});
|
||||
const result = plugin.init({});
|
||||
expect(Object.keys(result)).toEqual(['response']);
|
||||
expect(Object.keys(result.response)).toEqual([
|
||||
'getRequestId',
|
||||
@ -31,7 +24,7 @@ describe('init()', () => {
|
||||
});
|
||||
|
||||
it('fails to initialize without response', () => {
|
||||
expect(() => plugin.init(PLUGIN))
|
||||
expect(() => plugin.init())
|
||||
.toThrowError('contexts.response initialized without response');
|
||||
});
|
||||
});
|
||||
@ -51,7 +44,7 @@ describe('response.*', () => {
|
||||
bytesRead: 123,
|
||||
elapsedTime: 321
|
||||
});
|
||||
const result = plugin.init(PLUGIN, response);
|
||||
const result = plugin.init(response);
|
||||
expect(result.response.getRequestId()).toBe('req_1');
|
||||
expect(result.response.getStatusCode()).toBe(200);
|
||||
expect(result.response.getBytesRead()).toBe(123);
|
||||
@ -60,7 +53,7 @@ describe('response.*', () => {
|
||||
});
|
||||
|
||||
it('works for basic and empty response', async () => {
|
||||
const result = plugin.init(PLUGIN, {});
|
||||
const result = plugin.init({});
|
||||
expect(result.response.getRequestId()).toBe('');
|
||||
expect(result.response.getStatusCode()).toBe(0);
|
||||
expect(result.response.getBytesRead()).toBe(0);
|
||||
@ -76,7 +69,7 @@ describe('response.*', () => {
|
||||
{name: 'set-cookie', value: 'baz=qux'}
|
||||
]
|
||||
};
|
||||
const result = plugin.init(PLUGIN, response);
|
||||
const result = plugin.init(response);
|
||||
expect(result.response.getHeader('Does-Not-Exist')).toBeNull();
|
||||
expect(result.response.getHeader('CONTENT-TYPE')).toBe('application/json');
|
||||
expect(result.response.getHeader('set-cookie')).toEqual(['foo=bar', 'baz=qux']);
|
||||
|
@ -1,13 +1,35 @@
|
||||
// @flow
|
||||
import type {Plugin} from '../';
|
||||
import * as electron from 'electron';
|
||||
import {showAlert} from '../../ui/components/modals/index';
|
||||
import {showPrompt} from '../../ui/components/modals';
|
||||
import {RENDER_PURPOSE_SEND} from '../../common/render';
|
||||
|
||||
export function init (plugin: Plugin): {app: Object} {
|
||||
export function init (renderPurpose?: string): {app: Object} {
|
||||
return {
|
||||
app: {
|
||||
alert (message: string): Promise<void> {
|
||||
return showAlert({title: `Plugin ${plugin.name}`, message: message || ''});
|
||||
alert (options: {title: string, message: string}): Promise<void> {
|
||||
if (renderPurpose !== RENDER_PURPOSE_SEND) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return showAlert(options || {});
|
||||
},
|
||||
prompt (options: {title: string, label?: string, defaultValue?: string, submitName?: string}): Promise<string> {
|
||||
options = options || {};
|
||||
|
||||
if (renderPurpose !== RENDER_PURPOSE_SEND) {
|
||||
return Promise.resolve(options.defaultValue || '');
|
||||
}
|
||||
|
||||
return new Promise(resolve => {
|
||||
showPrompt({
|
||||
...(options || {}),
|
||||
cancelable: false,
|
||||
onComplete (value: string) {
|
||||
resolve(value);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
getPath (name: string): string {
|
||||
switch (name.toLowerCase()) {
|
||||
@ -18,6 +40,10 @@ export function init (plugin: Plugin): {app: Object} {
|
||||
}
|
||||
},
|
||||
async showSaveDialog (options: {defaultPath?: string} = {}): Promise<string | null> {
|
||||
if (renderPurpose !== RENDER_PURPOSE_SEND) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
return new Promise(resolve => {
|
||||
const saveOptions = {
|
||||
title: 'Save File',
|
||||
|
@ -1,8 +1,7 @@
|
||||
// @flow
|
||||
import type {Plugin} from '../';
|
||||
import {exportHAR, exportJSON, importRaw, importUri} from '../../common/import';
|
||||
|
||||
export function init (plugin: Plugin): {'import': Object, 'export': Object} {
|
||||
export function init (): {'import': Object, 'export': Object} {
|
||||
return {
|
||||
'import': {
|
||||
async uri (uri: string, options: {workspaceId?: string} = {}): Promise<void> {
|
||||
|
@ -1,10 +1,8 @@
|
||||
// @flow
|
||||
import type {Plugin} from '../';
|
||||
import type {RenderedRequest} from '../../common/render';
|
||||
import * as misc from '../../common/misc';
|
||||
|
||||
export function init (
|
||||
plugin: Plugin,
|
||||
renderedRequest: RenderedRequest,
|
||||
renderedContext: Object
|
||||
): {request: Object} {
|
||||
|
@ -1,5 +1,4 @@
|
||||
// @flow
|
||||
import type {Plugin} from '../';
|
||||
import type {ResponseHeader} from '../../models/response';
|
||||
import * as models from '../../models/index';
|
||||
import {Readable} from 'stream';
|
||||
@ -16,7 +15,6 @@ type MaybeResponse = {
|
||||
}
|
||||
|
||||
export function init (
|
||||
plugin: Plugin,
|
||||
response: MaybeResponse,
|
||||
bodyBuffer: Buffer | null = null
|
||||
): {response: Object} {
|
||||
|
@ -37,6 +37,7 @@ const CORE_PLUGINS = [
|
||||
'insomnia-plugin-file',
|
||||
'insomnia-plugin-now',
|
||||
'insomnia-plugin-uuid',
|
||||
'insomnia-plugin-prompt',
|
||||
'insomnia-plugin-request',
|
||||
'insomnia-plugin-response'
|
||||
];
|
||||
|
@ -1,5 +1,6 @@
|
||||
import * as models from '../models/index';
|
||||
import * as templating from './index';
|
||||
import * as pluginContexts from '../plugins/context';
|
||||
|
||||
const EMPTY_ARG = '__EMPTY_NUNJUCKS_ARG__';
|
||||
|
||||
@ -60,6 +61,9 @@ export default class BaseExtension {
|
||||
// Pull out the meta helper
|
||||
const renderMeta = renderContext.getMeta ? renderContext.getMeta() : {};
|
||||
|
||||
// Pull out the purpose
|
||||
const renderPurpose = renderContext.getPurpose ? renderContext.getPurpose() : null;
|
||||
|
||||
// Extract the rest of the args
|
||||
const args = runArgs
|
||||
.slice(0, runArgs.length - 1)
|
||||
@ -67,6 +71,7 @@ export default class BaseExtension {
|
||||
|
||||
// Define a helper context with utils
|
||||
const helperContext = {
|
||||
...pluginContexts.app.init(renderPurpose),
|
||||
context: renderContext,
|
||||
meta: renderMeta,
|
||||
util: {
|
||||
|
@ -82,5 +82,6 @@ export type PluginTemplateTag = {
|
||||
description: string,
|
||||
run: (context: PluginTemplateTagContext, ...arg: Array<any>) => Promise<any> | any,
|
||||
deprecated?: boolean,
|
||||
validate?: (value: any) => ?string,
|
||||
priority?: number
|
||||
};
|
||||
|
@ -54,7 +54,7 @@ export function render (text: string, config: Object = {}): Promise<string> {
|
||||
: 'error';
|
||||
|
||||
const newError = new RenderError(sanitizedMsg);
|
||||
newError.path = path || null;
|
||||
newError.path = path || '';
|
||||
newError.message = sanitizedMsg;
|
||||
newError.location = {line, column};
|
||||
newError.type = 'render';
|
||||
|
@ -20,6 +20,7 @@ class PromptModal extends PureComponent {
|
||||
upperCase: false,
|
||||
hint: null,
|
||||
inputType: 'text',
|
||||
cancelable: true,
|
||||
hints: []
|
||||
};
|
||||
}
|
||||
@ -66,6 +67,7 @@ class PromptModal extends PureComponent {
|
||||
selectText,
|
||||
upperCase,
|
||||
hint,
|
||||
cancelable,
|
||||
inputType,
|
||||
placeholder,
|
||||
label,
|
||||
@ -82,6 +84,7 @@ class PromptModal extends PureComponent {
|
||||
defaultValue,
|
||||
submitName,
|
||||
selectText,
|
||||
cancelable,
|
||||
placeholder,
|
||||
upperCase,
|
||||
hint,
|
||||
@ -107,7 +110,7 @@ class PromptModal extends PureComponent {
|
||||
);
|
||||
|
||||
return (
|
||||
<div type="button" key={hint} className={classes}>
|
||||
<div key={hint} className={classes}>
|
||||
<Button className="tall" onClick={this._handleSelectHint} value={hint}>
|
||||
{hint}
|
||||
</Button>
|
||||
@ -131,7 +134,8 @@ class PromptModal extends PureComponent {
|
||||
placeholder,
|
||||
label,
|
||||
upperCase,
|
||||
hints
|
||||
hints,
|
||||
cancelable
|
||||
} = this.state;
|
||||
|
||||
const input = (
|
||||
@ -152,7 +156,7 @@ class PromptModal extends PureComponent {
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal ref={this._setModalRef}>
|
||||
<Modal ref={this._setModalRef} noEscape={!cancelable}>
|
||||
<ModalHeader>{title}</ModalHeader>
|
||||
<ModalBody className="wide">
|
||||
<form onSubmit={this._handleSubmit} className="wide pad">
|
||||
|
@ -509,6 +509,12 @@ class TagEditor extends React.PureComponent<Props, State> {
|
||||
typeof argDefinition.displayName === 'function'
|
||||
) ? fnOrString(argDefinition.displayName, argDatas) : '';
|
||||
|
||||
let validationError = '';
|
||||
const canValidate = argDefinition.type === 'string' || argDefinition.type === 'number';
|
||||
if (canValidate && typeof argDefinition.validate === 'function') {
|
||||
validationError = argDefinition.validate(strValue) || '';
|
||||
}
|
||||
|
||||
const formControlClasses = classnames({
|
||||
'form-control': true,
|
||||
'form-control--thin': argDefinition.type === 'boolean',
|
||||
@ -522,6 +528,7 @@ class TagEditor extends React.PureComponent<Props, State> {
|
||||
{fnOrString(displayName, argDatas)}
|
||||
{isVariable && <span className="faded space-left">(Variable)</span>}
|
||||
{help && <HelpTooltip className="space-left">{help}</HelpTooltip>}
|
||||
{validationError && <span className="font-error space-left">{validationError}</span>}
|
||||
{argInputVariable || argInput}
|
||||
</label>
|
||||
</div>
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"private": true,
|
||||
"version": "1.0.5",
|
||||
"version": "1.0.6",
|
||||
"name": "insomnia-app",
|
||||
"app": {
|
||||
"name": "insomnia",
|
||||
@ -108,6 +108,7 @@
|
||||
"insomnia-plugin-file": "^1.0.3",
|
||||
"insomnia-plugin-hash": "^1.0.3",
|
||||
"insomnia-plugin-now": "^1.0.3",
|
||||
"insomnia-plugin-prompt": "^1.0.1",
|
||||
"insomnia-plugin-request": "^1.0.4",
|
||||
"insomnia-plugin-response": "^1.0.5",
|
||||
"insomnia-plugin-uuid": "^1.0.3",
|
||||
|
5
plugins/insomnia-plugin-prompt/README.md
Normal file
5
plugins/insomnia-plugin-prompt/README.md
Normal file
@ -0,0 +1,5 @@
|
||||
# Insomnia Prompt Template Tag
|
||||
|
||||
[![Npm Version](https://img.shields.io/npm/v/insomnia-plugin-prompt.svg)](https://www.npmjs.com/package/insomnia-plugin-prompt)
|
||||
|
||||
This is a core Insomnia plugin.
|
21
plugins/insomnia-plugin-prompt/index.js
Normal file
21
plugins/insomnia-plugin-prompt/index.js
Normal file
@ -0,0 +1,21 @@
|
||||
module.exports.templateTags = [{
|
||||
displayName: 'Prompt',
|
||||
name: 'prompt',
|
||||
description: 'prompt user for input',
|
||||
args: [{
|
||||
displayName: 'Title',
|
||||
type: 'string'
|
||||
}, {
|
||||
displayName: 'Label',
|
||||
type: 'string'
|
||||
}, {
|
||||
displayName: 'Default Value',
|
||||
type: 'string',
|
||||
help: 'This value is used to pre-populate the prompt dialog, but is ALSO used ' +
|
||||
'when the app renders preview values (like the one below). This is to prevent the ' +
|
||||
'prompt from displaying too frequently during general app use.'
|
||||
}],
|
||||
run (context, title, label, defaultValue) {
|
||||
return context.app.prompt({title, label, defaultValue});
|
||||
}
|
||||
}];
|
18
plugins/insomnia-plugin-prompt/package.json
Normal file
18
plugins/insomnia-plugin-prompt/package.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "insomnia-plugin-prompt",
|
||||
"version": "1.0.1",
|
||||
"author": "Gregory Schier <gschier1990@gmail.com>",
|
||||
"description": "Insomnia prompt template tag",
|
||||
"license": "MIT",
|
||||
"repository": "https://github.com/getinsomnia/insomnia/tree/master/plugins/insomnia-plugin-prompt",
|
||||
"bugs": {
|
||||
"url": "https://github.com/getinsomnia/insomnia"
|
||||
},
|
||||
"main": "index.js",
|
||||
"insomnia": {
|
||||
"name": "prompt"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "node --version"
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user