mirror of
https://github.com/Kong/insomnia
synced 2024-11-07 22:30:15 +00:00
New 'request' tag and a lot of improvements (#296)
* New 'request' tag and a lot of improvements * Update request extension to render all values * Custom value of tag editor now inherits current
This commit is contained in:
parent
1d7090e36c
commit
fd7a25e1ac
@ -270,3 +270,11 @@ export function clickLink (href) {
|
||||
shell.openExternal(href);
|
||||
}
|
||||
}
|
||||
|
||||
export function fnOrString (v, ...args) {
|
||||
if (typeof v === 'string') {
|
||||
return v;
|
||||
} else {
|
||||
return v(...args);
|
||||
}
|
||||
}
|
||||
|
@ -154,7 +154,15 @@ export async function getRenderContext (request, environmentId, ancestors = null
|
||||
const subEnvironment = await models.environment.getById(environmentId);
|
||||
|
||||
// Generate the context we need to render
|
||||
return buildRenderContext(ancestors, rootEnvironment, subEnvironment, variablesOnly);
|
||||
const context = await buildRenderContext(ancestors, rootEnvironment, subEnvironment, variablesOnly);
|
||||
|
||||
// Add meta data
|
||||
context.getMeta = () => ({
|
||||
requestId: request._id,
|
||||
workspaceId: workspace._id
|
||||
});
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
export async function getRenderedRequest (request, environmentId) {
|
||||
|
@ -426,14 +426,6 @@ export function _actuallySend (renderedRequest, workspace, settings) {
|
||||
}
|
||||
|
||||
const cookies = await cookiesFromJar(jar);
|
||||
|
||||
// Make sure domains are prefixed with dots (Curl does this)
|
||||
for (const cookie of cookies) {
|
||||
if (cookie.domain && cookie.domain[0] !== '.') {
|
||||
cookie.domain = `.${cookie.domain}`;
|
||||
}
|
||||
}
|
||||
|
||||
models.cookieJar.update(renderedRequest.cookieJar, {cookies});
|
||||
|
||||
const n = setCookieHeaders.length;
|
||||
|
@ -1,5 +1,6 @@
|
||||
const EMPTY_ARG = '__EMPTY_NUNJUCKS_ARG__';
|
||||
import * as models from '../models/index';
|
||||
import * as templating from './index';
|
||||
|
||||
export default class BaseExtension {
|
||||
constructor (ext) {
|
||||
@ -19,24 +20,6 @@ export default class BaseExtension {
|
||||
return this._ext.displayName || this.getTag();
|
||||
}
|
||||
|
||||
getDefaultFill () {
|
||||
const args = this.getArgs().map(argDefinition => {
|
||||
if (argDefinition.type === 'enum') {
|
||||
const {defaultValue, options} = argDefinition;
|
||||
const value = defaultValue !== undefined ? defaultValue : options[0].value;
|
||||
return `'${value}'`;
|
||||
} else if (argDefinition.type === 'number') {
|
||||
const {defaultValue} = argDefinition;
|
||||
return defaultValue !== undefined ? defaultValue : 0;
|
||||
} else {
|
||||
const {defaultValue} = argDefinition;
|
||||
return defaultValue !== undefined ? `'${defaultValue}'` : "''";
|
||||
}
|
||||
});
|
||||
|
||||
return `${this.getTag()} ${args.join(', ')}`;
|
||||
}
|
||||
|
||||
getDescription () {
|
||||
return this._ext.description || 'no description';
|
||||
}
|
||||
@ -69,30 +52,37 @@ export default class BaseExtension {
|
||||
return new nodes.CallExtensionAsync(this, 'asyncRun', args);
|
||||
}
|
||||
|
||||
asyncRun (...runArgs) {
|
||||
asyncRun ({ctx: renderContext}, ...runArgs) {
|
||||
// Pull the callback off the end
|
||||
const callback = runArgs[runArgs.length - 1];
|
||||
|
||||
// Only pass render context, not the entire Nunjucks instance
|
||||
const renderContext = runArgs[0].ctx;
|
||||
// Pull out the meta
|
||||
const renderMeta = renderContext.getMeta ? renderContext.getMeta() : {};
|
||||
delete renderContext.getMeta;
|
||||
|
||||
// Extract the rest of the args
|
||||
const args = runArgs
|
||||
.slice(1, runArgs.length - 1)
|
||||
.slice(0, runArgs.length - 1)
|
||||
.filter(a => a !== EMPTY_ARG);
|
||||
|
||||
// Define a plugin context with helpers
|
||||
const pluginContext = {
|
||||
// Define a helper context with utils
|
||||
const helperContext = {
|
||||
context: renderContext,
|
||||
models: {
|
||||
request: {getById: models.request.getById},
|
||||
response: {getLatestForRequestId: models.response.getLatestForRequest}
|
||||
meta: renderMeta,
|
||||
util: {
|
||||
render: str => templating.render(str, {context: renderContext}),
|
||||
models: {
|
||||
request: {getById: models.request.getById},
|
||||
workspace: {getById: models.workspace.getById},
|
||||
cookieJar: {getOrCreateForWorkspace: models.cookieJar.getOrCreateForWorkspace},
|
||||
response: {getLatestForRequestId: models.response.getLatestForRequest}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let result;
|
||||
try {
|
||||
result = this.run(pluginContext, ...args);
|
||||
result = this.run(helperContext, ...args);
|
||||
} catch (err) {
|
||||
callback(err);
|
||||
return;
|
||||
|
@ -0,0 +1,88 @@
|
||||
import * as templating from '../../index';
|
||||
import * as db from '../../../common/database';
|
||||
import * as models from '../../../models';
|
||||
import {cookiesFromJar, jarFromCookies} from '../../../common/cookies';
|
||||
import {getRenderContext} from '../../../common/render';
|
||||
|
||||
describe('RequestExtension cookie', async () => {
|
||||
beforeEach(() => db.init(models.types(), {inMemoryOnly: true}, true));
|
||||
|
||||
it('should get cookie by name', async () => {
|
||||
// Create necessary models
|
||||
const workspace = await models.workspace.create({name: 'Workspace'});
|
||||
const request = await models.request.create({
|
||||
parentId: workspace._id,
|
||||
url: 'https://insomnia.rest/foo/bar'
|
||||
});
|
||||
const cookieJar = await models.cookieJar.getOrCreateForWorkspace(workspace);
|
||||
const jar = jarFromCookies(cookieJar.cookies);
|
||||
jar.setCookieSync([
|
||||
'foo=bar',
|
||||
'path=/',
|
||||
'domain=.insomnia.rest',
|
||||
'HttpOnly Cache-Control: public, no-cache'
|
||||
].join('; '), request.url);
|
||||
|
||||
const cookies = await cookiesFromJar(jar);
|
||||
await models.cookieJar.update(cookieJar, {cookies});
|
||||
const context = await getRenderContext(request);
|
||||
const result = await templating.render(`{% request 'cookie', 'foo' %}`, {context});
|
||||
|
||||
expect(result).toBe('bar');
|
||||
});
|
||||
});
|
||||
|
||||
describe('RequestExtension url', async () => {
|
||||
beforeEach(() => db.init(models.types(), {inMemoryOnly: true}, true));
|
||||
|
||||
it('should get url', async () => {
|
||||
// Create necessary models
|
||||
const workspace = await models.workspace.create({name: 'Workspace'});
|
||||
const request = await models.request.create({
|
||||
parentId: workspace._id,
|
||||
url: 'https://insomnia.rest/foo/bar',
|
||||
parameters: [{name: 'foo', value: 'bar'}]
|
||||
});
|
||||
|
||||
const context = await getRenderContext(request);
|
||||
const result = await templating.render(`{% request 'url' %}`, {context});
|
||||
|
||||
expect(result).toBe('https://insomnia.rest/foo/bar?foo=bar');
|
||||
});
|
||||
|
||||
it('should get rendered url', async () => {
|
||||
// Create necessary models
|
||||
const workspace = await models.workspace.create({name: 'Workspace'});
|
||||
const request = await models.request.create({
|
||||
parentId: workspace._id,
|
||||
url: 'https://insomnia.rest/foo/bar',
|
||||
parameters: [{name: 'foo', value: '{{ foo }}'}]
|
||||
});
|
||||
|
||||
const context = await getRenderContext(request);
|
||||
context.foo = 'Hello World!';
|
||||
const result = await templating.render(`{% request 'url' %}`, {context});
|
||||
|
||||
expect(result).toBe('https://insomnia.rest/foo/bar?foo=Hello%20World!');
|
||||
});
|
||||
});
|
||||
|
||||
describe('RequestExtension header', async () => {
|
||||
beforeEach(() => db.init(models.types(), {inMemoryOnly: true}, true));
|
||||
|
||||
it('should get url', async () => {
|
||||
// Create necessary models
|
||||
const workspace = await models.workspace.create({name: 'Workspace'});
|
||||
const request = await models.request.create({
|
||||
parentId: workspace._id,
|
||||
url: 'https://insomnia.rest/foo/bar',
|
||||
headers: [{name: 'foo', value: '{{ foo }}'}]
|
||||
});
|
||||
|
||||
const context = await getRenderContext(request);
|
||||
context.foo = 'Hello World!';
|
||||
const result = await templating.render(`{% request 'header', 'foo' %}`, {context});
|
||||
|
||||
expect(result).toBe('Hello World!');
|
||||
});
|
||||
});
|
@ -2,7 +2,6 @@ export default {
|
||||
name: 'base64',
|
||||
displayName: 'Base64',
|
||||
description: 'encode or decode values',
|
||||
defaultFill: "base64 'encode', ''",
|
||||
args: [
|
||||
{
|
||||
displayName: 'Action',
|
||||
|
@ -5,12 +5,14 @@ import uuidExtension from './uuid-extension';
|
||||
import NowExtension from './now-extension';
|
||||
import responseExtension from './response-extension';
|
||||
import base64Extension from './base-64-extension';
|
||||
import requestExtension from './request-extension';
|
||||
|
||||
const DEFAULT_EXTENSIONS = [
|
||||
timestampExtension,
|
||||
NowExtension,
|
||||
uuidExtension,
|
||||
base64Extension,
|
||||
requestExtension,
|
||||
responseExtension
|
||||
];
|
||||
|
||||
|
@ -1,8 +1,7 @@
|
||||
export default {
|
||||
name: 'now',
|
||||
displayName: 'Now Timestamp',
|
||||
displayName: 'Timestamp',
|
||||
description: 'get the current time',
|
||||
defaultFill: "now 'iso-8601'",
|
||||
args: [{
|
||||
displayName: 'Timestamp Format',
|
||||
type: 'enum',
|
||||
|
108
app/templating/extensions/request-extension.js
Normal file
108
app/templating/extensions/request-extension.js
Normal file
@ -0,0 +1,108 @@
|
||||
import * as querystring from '../../common/querystring';
|
||||
import {prepareUrlForSending} from '../../common/misc';
|
||||
import {jarFromCookies} from '../../common/cookies';
|
||||
|
||||
export default {
|
||||
name: 'request',
|
||||
displayName: 'Request',
|
||||
description: 'reference value from current request',
|
||||
args: [
|
||||
{
|
||||
displayName: 'Attribute',
|
||||
type: 'enum',
|
||||
options: [
|
||||
{displayName: 'URL', value: 'url', description: 'fully qualified URL'},
|
||||
{displayName: 'Cookie', value: 'cookie', description: 'cookie value by name'},
|
||||
{displayName: 'Header', value: 'header', description: 'header value by name'}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'string',
|
||||
hide: args => ['url'].includes(args[0].value),
|
||||
displayName: args => {
|
||||
switch (args[0].value) {
|
||||
case 'cookie':
|
||||
return 'Cookie Name';
|
||||
case 'header':
|
||||
return 'Header Name';
|
||||
default:
|
||||
return 'Name';
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
async run (context, attribute, name) {
|
||||
const {meta} = context;
|
||||
|
||||
if (!meta.requestId || !meta.workspaceId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const request = await context.util.models.request.getById(meta.requestId);
|
||||
const workspace = await context.util.models.workspace.getById(meta.workspaceId);
|
||||
|
||||
if (!request) {
|
||||
throw new Error(`Request not found for ${meta.requestId}`);
|
||||
}
|
||||
|
||||
if (!workspace) {
|
||||
throw new Error(`Workspace not found for ${meta.workspaceId}`);
|
||||
}
|
||||
|
||||
switch (attribute) {
|
||||
case 'url':
|
||||
return getRequestUrl(context, request);
|
||||
case 'cookie':
|
||||
const cookieJar = await context.util.models.cookieJar.getOrCreateForWorkspace(workspace);
|
||||
const url = await getRequestUrl(context, request);
|
||||
const value = await getCookieValue(cookieJar, url, name);
|
||||
return value;
|
||||
case 'header':
|
||||
for (const header of request.headers) {
|
||||
const currentName = await context.util.render(name);
|
||||
if (currentName.toLowerCase() === name.toLowerCase()) {
|
||||
return context.util.render(header.value);
|
||||
}
|
||||
}
|
||||
throw new Error(`No header for name "${name}"`);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
async function getRequestUrl (context, request) {
|
||||
const url = await context.util.render(request.url);
|
||||
const parameters = [];
|
||||
for (const p of request.parameters) {
|
||||
parameters.push({
|
||||
name: await context.util.render(p.name),
|
||||
value: await context.util.render(p.value)
|
||||
});
|
||||
}
|
||||
|
||||
const qs = querystring.buildFromParams(parameters);
|
||||
const finalUrl = querystring.joinUrl(url, qs);
|
||||
|
||||
return prepareUrlForSending(finalUrl, request.settingEncodeUrl);
|
||||
}
|
||||
|
||||
function getCookieValue (cookieJar, url, name) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const jar = jarFromCookies(cookieJar.cookies);
|
||||
|
||||
jar.getCookies(url, {}, (err, cookies) => {
|
||||
if (err) {
|
||||
console.warn(`Failed to find cookie for ${url}`, err);
|
||||
}
|
||||
|
||||
const cookie = cookies.find(cookie => cookie.key === name);
|
||||
if (!cookie) {
|
||||
reject(new Error(`No cookie found with name "${name}"`));
|
||||
} else {
|
||||
resolve(cookie ? cookie.value : null);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
@ -4,9 +4,8 @@ import xpath from 'xpath';
|
||||
|
||||
export default {
|
||||
name: 'response',
|
||||
displayName: 'Response Value',
|
||||
displayName: 'Response',
|
||||
description: 'reference values from other requests',
|
||||
defaultFill: "response 'body', '', ''",
|
||||
args: [
|
||||
{
|
||||
displayName: 'Attribute',
|
||||
@ -47,12 +46,12 @@ export default {
|
||||
throw new Error(`No ${field} filter specified`);
|
||||
}
|
||||
|
||||
const request = await context.models.request.getById(id);
|
||||
const request = await context.util.models.request.getById(id);
|
||||
if (!request) {
|
||||
throw new Error(`Could not find request ${id}`);
|
||||
}
|
||||
|
||||
const response = await context.models.response.getLatestForRequestId(id);
|
||||
const response = await context.util.models.response.getLatestForRequestId(id);
|
||||
|
||||
if (!response) {
|
||||
throw new Error('No responses for request');
|
||||
|
@ -3,7 +3,6 @@ export default {
|
||||
name: 'timestamp',
|
||||
displayName: 'Timestamp',
|
||||
description: 'generate timestamp in milliseconds',
|
||||
defaultFill: 'timestamp',
|
||||
run (context) {
|
||||
return Date.now();
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ import uuid from 'uuid';
|
||||
export default {
|
||||
displayName: 'UUID',
|
||||
name: 'uuid',
|
||||
defaultFill: "uuid 'v4'",
|
||||
description: 'generate v1 or v4 UUIDs',
|
||||
args: [{
|
||||
displayName: 'Version',
|
||||
|
@ -76,7 +76,6 @@ export function getTagDefinitions () {
|
||||
.map(ext => ({
|
||||
name: ext.getTag(),
|
||||
displayName: ext.getName(),
|
||||
defaultFill: ext.getDefaultFill(),
|
||||
description: ext.getDescription(),
|
||||
args: ext.getArgs()
|
||||
}));
|
||||
@ -125,7 +124,7 @@ function getNunjucks (variablesOnly) {
|
||||
const ext = allExtensions[i];
|
||||
ext.priority = ext.priority || i * 100;
|
||||
const instance = new BaseExtension(ext);
|
||||
nj.addExtension(instance.getName(), instance);
|
||||
nj.addExtension(instance.getTag(), instance);
|
||||
}
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~ //
|
||||
|
@ -143,3 +143,27 @@ export function unTokenizeTag (tagData) {
|
||||
const argsStr = args.join(', ');
|
||||
return `{% ${tagData.name} ${argsStr} %}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default Nunjucks string for an extension
|
||||
* @param {string} name
|
||||
* @param {object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
export function getDefaultFill (name, args) {
|
||||
const stringArgs = (args || []).map(argDefinition => {
|
||||
if (argDefinition.type === 'enum') {
|
||||
const {defaultValue, options} = argDefinition;
|
||||
const value = defaultValue !== undefined ? defaultValue : options[0].value;
|
||||
return `'${value}'`;
|
||||
} else if (argDefinition.type === 'number') {
|
||||
const {defaultValue} = argDefinition;
|
||||
return defaultValue !== undefined ? defaultValue : 0;
|
||||
} else {
|
||||
const {defaultValue} = argDefinition;
|
||||
return defaultValue !== undefined ? `'${defaultValue}'` : "''";
|
||||
}
|
||||
});
|
||||
|
||||
return `${name} ${stringArgs.join(', ')}`;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ import React, {PureComponent, PropTypes} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import CodeMirror from 'codemirror';
|
||||
import classnames from 'classnames';
|
||||
import clone from 'clone';
|
||||
import jq from 'jsonpath';
|
||||
import vkBeautify from 'vkbeautify';
|
||||
import {DOMParser} from 'xmldom';
|
||||
@ -409,7 +410,25 @@ class CodeEditor extends PureComponent {
|
||||
};
|
||||
|
||||
// Only allow tags if we have variables too
|
||||
getTags = getTagDefinitions;
|
||||
getTags = () => {
|
||||
const expandedTags = [];
|
||||
for (const tagDef of getTagDefinitions()) {
|
||||
if (tagDef.args[0].type !== 'enum') {
|
||||
expandedTags.push(tagDef);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const option of tagDef.args[0].options) {
|
||||
const optionName = misc.fnOrString(option.displayName, tagDef.args) || option.name;
|
||||
const newDef = clone(tagDef);
|
||||
newDef.displayName = `${tagDef.displayName} ⇒ ${optionName}`;
|
||||
newDef.args[0].defaultValue = option.value;
|
||||
expandedTags.push(newDef);
|
||||
}
|
||||
}
|
||||
|
||||
return expandedTags;
|
||||
};
|
||||
}
|
||||
options.environmentAutocomplete = {
|
||||
getVariables,
|
||||
|
@ -1,6 +1,7 @@
|
||||
import CodeMirror from 'codemirror';
|
||||
import 'codemirror/addon/mode/overlay';
|
||||
import * as misc from '../../../../common/misc';
|
||||
import {getDefaultFill} from '../../../../templating/utils';
|
||||
|
||||
const NAME_MATCH_FLEXIBLE = /[\w.\][\-/]+$/;
|
||||
const NAME_MATCH = /[\w.\][]+$/;
|
||||
@ -298,7 +299,7 @@ function matchSegments (listOfThings, segment, type, limit = -1) {
|
||||
const name = typeof t === 'string' ? t : t.name;
|
||||
const value = typeof t === 'string' ? '' : t.value;
|
||||
const displayName = t.displayName || name;
|
||||
const defaultFill = t.defaultFill || name;
|
||||
const defaultFill = getDefaultFill(t.name, t.args);
|
||||
|
||||
const matchSegment = segment.toLowerCase();
|
||||
const matchName = displayName.toLowerCase();
|
||||
|
@ -5,6 +5,7 @@ import {createPlugin, getPlugins} from '../../../plugins/index';
|
||||
import Button from '../base/button';
|
||||
import CopyButton from '../base/copy-button';
|
||||
import {showPrompt} from '../modals/index';
|
||||
import {trackEvent} from '../../../analytics/index';
|
||||
|
||||
@autobind
|
||||
class Plugins extends PureComponent {
|
||||
@ -30,12 +31,14 @@ class Plugins extends PureComponent {
|
||||
onComplete: async name => {
|
||||
await createPlugin(name);
|
||||
this._handleRefreshPlugins();
|
||||
trackEvent('Plugins', 'Generate');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_handleRefreshPlugins () {
|
||||
this.setState({plugins: getPlugins(true)});
|
||||
trackEvent('Plugins', 'Refresh');
|
||||
}
|
||||
|
||||
render () {
|
||||
|
@ -6,6 +6,8 @@ import * as templateUtils from '../../../templating/utils';
|
||||
import * as db from '../../../common/database';
|
||||
import * as models from '../../../models';
|
||||
import HelpTooltip from '../help-tooltip';
|
||||
import {fnOrString} from '../../../common/misc';
|
||||
import {trackEvent} from '../../../analytics/index';
|
||||
|
||||
@autobind
|
||||
class TagEditor extends PureComponent {
|
||||
@ -91,6 +93,7 @@ class TagEditor extends PureComponent {
|
||||
const name = e.target.value;
|
||||
const tagDefinition = templating.getTagDefinitions().find(d => d.name === name);
|
||||
this._update(tagDefinition, false);
|
||||
trackEvent('Tag Editor', 'Change Tag', name);
|
||||
}
|
||||
|
||||
_setSelectRef (n) {
|
||||
@ -102,19 +105,6 @@ class TagEditor extends PureComponent {
|
||||
}, 100);
|
||||
}
|
||||
|
||||
_buildArgFromDefinition (argDefinition) {
|
||||
if (argDefinition.type === 'enum') {
|
||||
const {defaultValue, options} = argDefinition;
|
||||
return {type: 'string', value: defaultValue || options[0].value};
|
||||
} else if (argDefinition.type === 'number') {
|
||||
const {defaultValue} = argDefinition;
|
||||
const value = defaultValue !== undefined ? defaultValue : 0;
|
||||
return {type: 'number', value};
|
||||
} else {
|
||||
return {type: 'string', value: argDefinition.defaultValue || ''};
|
||||
}
|
||||
}
|
||||
|
||||
async _update (tagDefinition, tagData, noCallback = false) {
|
||||
const {handleRender} = this.props;
|
||||
|
||||
@ -123,13 +113,13 @@ class TagEditor extends PureComponent {
|
||||
|
||||
let activeTagData = tagData;
|
||||
if (!activeTagData && tagDefinition) {
|
||||
activeTagData = {
|
||||
name: tagDefinition.name,
|
||||
rawValue: null,
|
||||
args: tagDefinition.args.map(this._buildArgFromDefinition)
|
||||
};
|
||||
const defaultFill = templateUtils.getDefaultFill(tagDefinition.name, tagDefinition.args);
|
||||
activeTagData = templateUtils.tokenizeTag(defaultFill);
|
||||
} else if (!activeTagData && !tagDefinition) {
|
||||
activeTagData = {name: 'custom', rawValue: "{% tag 'arg1', 'arg2' %}"};
|
||||
activeTagData = {
|
||||
name: 'custom',
|
||||
rawValue: templateUtils.unTokenizeTag(this.state.activeTagData)
|
||||
};
|
||||
}
|
||||
|
||||
let template;
|
||||
@ -219,7 +209,7 @@ class TagEditor extends PureComponent {
|
||||
const parentId = request ? request.parentId : 'n/a';
|
||||
const requestGroups = allDocs[models.requestGroup.type] || [];
|
||||
const requestGroup = requestGroups.find(rg => rg._id === parentId);
|
||||
namePrefix = requestGroup ? `${requestGroup.name} ⇒ ` : null;
|
||||
namePrefix = requestGroup ? `[${requestGroup.name}] ` : null;
|
||||
}
|
||||
|
||||
return (
|
||||
@ -260,7 +250,7 @@ class TagEditor extends PureComponent {
|
||||
return (
|
||||
<div key={argIndex} className="form-control form-control--outlined">
|
||||
<label>
|
||||
{typeof displayName === 'function' ? displayName(args) : displayName}
|
||||
{fnOrString(displayName, args)}
|
||||
{argDefinition.help && <HelpTooltip>{argDefinition.help}</HelpTooltip>}
|
||||
<div data-arg-index={argIndex}>
|
||||
{argInput}
|
||||
@ -285,7 +275,7 @@ class TagEditor extends PureComponent {
|
||||
{tagDefinition.displayName} – {tagDefinition.description}
|
||||
</option>
|
||||
))}
|
||||
<option value="">-- Custom --</option>
|
||||
<option value="custom">-- Custom --</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
|
@ -1,5 +1,6 @@
|
||||
import React, {PropTypes, PureComponent} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import {trackEvent} from '../../../analytics/index';
|
||||
|
||||
@autobind
|
||||
class VariableEditor extends PureComponent {
|
||||
@ -23,7 +24,9 @@ class VariableEditor extends PureComponent {
|
||||
}
|
||||
|
||||
_handleChange (e) {
|
||||
this._update(e.target.value);
|
||||
const name = e.target.value;
|
||||
trackEvent('Variable Editor', 'Change Variable', name);
|
||||
this._update(name);
|
||||
}
|
||||
|
||||
_setSelectRef (n) {
|
||||
|
Loading…
Reference in New Issue
Block a user