mirror of
https://github.com/Kong/insomnia.git
synced 2026-04-22 07:08:16 -04:00
chore(pre-req): improve the snippets menu for the pre-request script - INS-3319 (#7173)
* chore: add more helper snippets * chore: add more helper snippets for pre-req scripting * fix: use correct icons * feat: enable basic auto code completing * feedback --------- Co-authored-by: jackkav <jackkav@gmail.com>
This commit is contained in:
@@ -15,12 +15,12 @@ export class InsomniaObject {
|
||||
public baseEnvironment: Environment;
|
||||
public variables: Variables;
|
||||
public request: ScriptRequest;
|
||||
private settings: Settings;
|
||||
private clientCertificates: ClientCertificate[];
|
||||
|
||||
// TODO: follows will be enabled after Insomnia supports them
|
||||
private _globals: Environment;
|
||||
private _iterationData: Environment;
|
||||
private _settings: Settings;
|
||||
|
||||
constructor(
|
||||
rawObj: {
|
||||
@@ -41,7 +41,7 @@ export class InsomniaObject {
|
||||
this._iterationData = rawObj.iterationData;
|
||||
this.variables = rawObj.variables;
|
||||
this.request = rawObj.request;
|
||||
this.settings = rawObj.settings;
|
||||
this._settings = rawObj.settings;
|
||||
this.clientCertificates = rawObj.clientCertificates;
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ export class InsomniaObject {
|
||||
cb: (error?: string, response?: ScriptResponse) => void
|
||||
) {
|
||||
// TODO: hook to settings later
|
||||
return sendRequest(request, cb, this.settings);
|
||||
return sendRequest(request, cb, this._settings);
|
||||
}
|
||||
|
||||
// TODO: remove this after enabled globals
|
||||
@@ -63,6 +63,11 @@ export class InsomniaObject {
|
||||
throw unsupportedError('iterationData', 'environment');
|
||||
}
|
||||
|
||||
// TODO: remove this after enabled iterationData
|
||||
get settings() {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
toObject = () => {
|
||||
return {
|
||||
globals: this._globals.toObject(),
|
||||
|
||||
@@ -333,7 +333,7 @@ export class Request extends Property {
|
||||
return headersObj;
|
||||
}
|
||||
|
||||
removeHeader(toRemove: string | Header, options: { ignoreCase: boolean }) {
|
||||
removeHeader(toRemove: string | Header, options?: { ignoreCase: boolean }) {
|
||||
const filteredHeaders = this.headers.filter(
|
||||
header => {
|
||||
if (!header.key) {
|
||||
@@ -341,7 +341,7 @@ export class Request extends Property {
|
||||
}
|
||||
|
||||
if (typeof toRemove === 'string') {
|
||||
return options.ignoreCase ?
|
||||
return options != null && options.ignoreCase ?
|
||||
header.key.toLocaleLowerCase() !== toRemove.toLocaleLowerCase() :
|
||||
header.key !== toRemove;
|
||||
} else if (toRemove instanceof Header) {
|
||||
@@ -349,7 +349,7 @@ export class Request extends Property {
|
||||
return false;
|
||||
}
|
||||
|
||||
return options.ignoreCase ?
|
||||
return options != null && options.ignoreCase ?
|
||||
header.key.toLocaleLowerCase() !== toRemove.key.toLocaleLowerCase() :
|
||||
header.key !== toRemove.key;
|
||||
} else {
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
import { Snippet } from 'codemirror';
|
||||
import React, { FC, Fragment, useRef } from 'react';
|
||||
|
||||
import { Settings } from '../../../models/settings';
|
||||
import { Environment, Variables } from '../../../sdk/objects/environments';
|
||||
import { InsomniaObject } from '../../../sdk/objects/insomnia';
|
||||
import { Request as ScriptRequest } from '../../../sdk/objects/request';
|
||||
import { Url } from '../../../sdk/objects/urls';
|
||||
import { Dropdown, DropdownButton, DropdownItem, ItemContent } from '../base/dropdown';
|
||||
import { CodeEditor, CodeEditorHandle } from '../codemirror/code-editor';
|
||||
|
||||
@@ -8,19 +14,20 @@ interface Props {
|
||||
defaultValue: string;
|
||||
uniquenessKey: string;
|
||||
className?: string;
|
||||
settings: Settings;
|
||||
}
|
||||
|
||||
const getEnvVar = 'insomnia.environment.get("variable_name");\n';
|
||||
// const getGlbVar = 'insomnia.globals.get("variable_name");\n';
|
||||
const getVar = 'insomnia.variables.get("variable_name");\n';
|
||||
const getCollectionVar = 'insomnia.collectionVariables.get("variable_name");\n';
|
||||
const setEnvVar = 'insomnia.environment.set("variable_name", "variable_value");\n';
|
||||
// const setGlbVar = 'insomnia.globals.set("variable_name", "variable_value");\n';
|
||||
const setVar = 'insomnia.variables.set("variable_name", "variable_value");\n';
|
||||
const setCollectionVar = 'insomnia.collectionVariables.set("variable_name", "variable_value");\n';
|
||||
const unsetEnvVar = 'insomnia.environment.unset("variable_name");\n';
|
||||
// const unsetGlbVar = 'insomnia.globals.unset("variable_name");\n';
|
||||
const unsetCollectionVar = 'insomnia.collectionVariables.unset("variable_name");\n';
|
||||
const getEnvVar = 'insomnia.environment.get("variable_name");';
|
||||
// const getGlbVar = 'insomnia.globals.get("variable_name");';
|
||||
const getVar = 'insomnia.variables.get("variable_name");';
|
||||
const getCollectionVar = 'insomnia.collectionVariables.get("variable_name");';
|
||||
const setEnvVar = 'insomnia.environment.set("variable_name", "variable_value");';
|
||||
// const setGlbVar = 'insomnia.globals.set("variable_name", "variable_value");';
|
||||
const setVar = 'insomnia.variables.set("variable_name", "variable_value");';
|
||||
const setCollectionVar = 'insomnia.collectionVariables.set("variable_name", "variable_value");';
|
||||
const unsetEnvVar = 'insomnia.environment.unset("variable_name");';
|
||||
// const unsetGlbVar = 'insomnia.globals.unset("variable_name");';
|
||||
const unsetCollectionVar = 'insomnia.collectionVariables.unset("variable_name");';
|
||||
const sendReq =
|
||||
`const resp = await new Promise((resolve, reject) => {
|
||||
insomnia.sendRequest(
|
||||
@@ -29,8 +36,28 @@ const sendReq =
|
||||
err != null ? reject(err) : resolve(resp);
|
||||
}
|
||||
);
|
||||
});\n`;
|
||||
const logValue = 'console.log("log", variableName);\n';
|
||||
});`;
|
||||
const logValue = 'console.log("log", variableName);';
|
||||
const addHeader = "insomnia.request.addHeader({key: 'X-Header-Name', value: 'header_value' });";
|
||||
const removeHeader = "insomnia.request.removeHeader('X-Header-Name');";
|
||||
const setMethod = "insomnia.request.method = 'GET';";
|
||||
const addQueryParams = "insomnia.request.url.addQueryParams('k1=v1');";
|
||||
const updateRequestBody =
|
||||
`insomnia.request.body.update({
|
||||
mode: 'raw',
|
||||
raw: 'rawContent',
|
||||
});`;
|
||||
|
||||
const updateRequestAuth =
|
||||
`insomnia.request.auth.update(
|
||||
{
|
||||
type: 'bearer',
|
||||
bearer: [
|
||||
{key: 'token', value: 'tokenValue'},
|
||||
],
|
||||
},
|
||||
'bearer'
|
||||
);`;
|
||||
|
||||
const lintOptions = {
|
||||
globals: {
|
||||
@@ -48,11 +75,64 @@ const lintOptions = {
|
||||
esversion: 8, // ES8 syntax (async/await, etc)
|
||||
};
|
||||
|
||||
// TODO: We probably don't want to expose every property like .toObject() so we need a way to filter those out
|
||||
// or make those properties private
|
||||
// TODO: introduce this functionality for other objects, such as Url, UrlMatchPattern and so on
|
||||
// TODO: introduce function arguments
|
||||
// TODO: provide snippets for environment keys if possible
|
||||
function getPreRequestScriptSnippets(insomniaObject: InsomniaObject, path: string): Snippet[] {
|
||||
let snippets: Snippet[] = [];
|
||||
|
||||
const refs = new Set();
|
||||
const insomniaRecords = insomniaObject as Record<string, any>;
|
||||
|
||||
for (const key in insomniaObject) {
|
||||
const isPrivate = typeof key === 'string' && key.startsWith('_');
|
||||
if (isPrivate) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const value = insomniaRecords[key];
|
||||
|
||||
if (typeof key === 'object') {
|
||||
if (refs.has(value)) {
|
||||
// avoid cyclic referring
|
||||
continue;
|
||||
} else {
|
||||
refs.add(value);
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
|
||||
snippets.push({
|
||||
displayValue: `${path}.${value}`,
|
||||
name: `${path}.${key}`,
|
||||
value: `${path}.${key}`,
|
||||
});
|
||||
} else if (typeof value === 'function') {
|
||||
snippets.push({
|
||||
displayValue: `${path}.${key}()`,
|
||||
name: `${path}.${key}()`,
|
||||
value: `${path}.${key}()`,
|
||||
});
|
||||
} else if (Array.isArray(value)) {
|
||||
for (const item of value) {
|
||||
snippets = snippets.concat(getPreRequestScriptSnippets(item, `${path}.${key}`));
|
||||
}
|
||||
} else {
|
||||
snippets = snippets.concat(getPreRequestScriptSnippets(value, `${path}.${key}`));
|
||||
}
|
||||
}
|
||||
|
||||
return snippets;
|
||||
}
|
||||
|
||||
export const PreRequestScriptEditor: FC<Props> = ({
|
||||
className,
|
||||
defaultValue,
|
||||
onChange,
|
||||
uniquenessKey,
|
||||
settings,
|
||||
}) => {
|
||||
const editorRef = useRef<CodeEditorHandle>(null);
|
||||
|
||||
@@ -65,6 +145,7 @@ export const PreRequestScriptEditor: FC<Props> = ({
|
||||
editorRef.current?.setValue([
|
||||
...value.split('\n').slice(0, nextRow),
|
||||
snippet,
|
||||
'\n',
|
||||
...value.split('\n').slice(nextRow),
|
||||
].join('\n'));
|
||||
|
||||
@@ -72,6 +153,28 @@ export const PreRequestScriptEditor: FC<Props> = ({
|
||||
editorRef.current?.setCursorLine(cursorRow + snippet.split('\n').length);
|
||||
};
|
||||
|
||||
// TODO(george): Add more to this object to provide improved autocomplete
|
||||
const preRequestScriptSnippets = getPreRequestScriptSnippets(
|
||||
new InsomniaObject({
|
||||
globals: new Environment({}),
|
||||
iterationData: new Environment({}),
|
||||
environment: new Environment({}),
|
||||
baseEnvironment: new Environment({}),
|
||||
variables: new Variables({
|
||||
globals: new Environment({}),
|
||||
environment: new Environment({}),
|
||||
collection: new Environment({}),
|
||||
data: new Environment({}),
|
||||
}),
|
||||
request: new ScriptRequest({
|
||||
url: new Url('http://placeholder.com'),
|
||||
}),
|
||||
settings,
|
||||
clientCertificates: [],
|
||||
}),
|
||||
'insomnia',
|
||||
);
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<div className="h-[calc(100%-var(--line-height-xs))]">
|
||||
@@ -88,18 +191,18 @@ export const PreRequestScriptEditor: FC<Props> = ({
|
||||
placeholder="..."
|
||||
lintOptions={lintOptions}
|
||||
ref={editorRef}
|
||||
getAutocompleteSnippets={() => preRequestScriptSnippets}
|
||||
/>
|
||||
</div>
|
||||
<div className="h-[calc(var(--line-height-xs))] border-solid border-t border-[var(--hl-md)] text-[var(--font-size-sm)] p-[var(--padding-xs)]">
|
||||
<Dropdown
|
||||
aria-label='Snippets'
|
||||
aria-label='Variable Snippets'
|
||||
placement='top left'
|
||||
triggerButton={
|
||||
<DropdownButton>
|
||||
<ItemContent
|
||||
icon="code"
|
||||
label='Add Snippets'
|
||||
onClick={() => addSnippet(getEnvVar)}
|
||||
label='Variable Snippets'
|
||||
/>
|
||||
</DropdownButton>
|
||||
}
|
||||
@@ -181,6 +284,75 @@ export const PreRequestScriptEditor: FC<Props> = ({
|
||||
onClick={() => addSnippet(unsetCollectionVar)}
|
||||
/>
|
||||
</DropdownItem>
|
||||
</Dropdown>
|
||||
|
||||
<Dropdown
|
||||
aria-label='Request Manipulation'
|
||||
placement='top left'
|
||||
triggerButton={
|
||||
<DropdownButton>
|
||||
<ItemContent
|
||||
icon="code"
|
||||
label='Request Manipulation'
|
||||
/>
|
||||
</DropdownButton>
|
||||
}
|
||||
>
|
||||
<DropdownItem textValue='Add query param' arial-label={'Add query param'}>
|
||||
<ItemContent
|
||||
icon="p"
|
||||
label='Add a query param'
|
||||
onClick={() => addSnippet(addQueryParams)}
|
||||
/>
|
||||
</DropdownItem>
|
||||
<DropdownItem textValue='Set method' arial-label={'Set method'}>
|
||||
<ItemContent
|
||||
icon="m"
|
||||
label='Set method'
|
||||
onClick={() => addSnippet(setMethod)}
|
||||
/>
|
||||
</DropdownItem>
|
||||
<DropdownItem textValue='Add a header' arial-label={'Add a header'}>
|
||||
<ItemContent
|
||||
icon="h"
|
||||
label='Add a header'
|
||||
onClick={() => addSnippet(addHeader)}
|
||||
/>
|
||||
</DropdownItem>
|
||||
<DropdownItem textValue='Remove header' arial-label={'Remove header'}>
|
||||
<ItemContent
|
||||
icon="h"
|
||||
label='Remove a header'
|
||||
onClick={() => addSnippet(removeHeader)}
|
||||
/>
|
||||
</DropdownItem>
|
||||
<DropdownItem textValue='Update body as raw' arial-label={'Update body as raw'}>
|
||||
<ItemContent
|
||||
icon="b"
|
||||
label='Update body as raw'
|
||||
onClick={() => addSnippet(updateRequestBody)}
|
||||
/>
|
||||
</DropdownItem>
|
||||
<DropdownItem textValue='Update auth method' arial-label={'Update auth method'}>
|
||||
<ItemContent
|
||||
icon="circle-user"
|
||||
label='Update auth method'
|
||||
onClick={() => addSnippet(updateRequestAuth)}
|
||||
/>
|
||||
</DropdownItem>
|
||||
</Dropdown>
|
||||
<Dropdown
|
||||
aria-label='Misc'
|
||||
placement='top left'
|
||||
triggerButton={
|
||||
<DropdownButton>
|
||||
<ItemContent
|
||||
icon="code"
|
||||
label='Misc'
|
||||
/>
|
||||
</DropdownButton>
|
||||
}
|
||||
>
|
||||
<DropdownItem textValue='Send a request' arial-label={'Send a request'}>
|
||||
<ItemContent
|
||||
icon="circle-play"
|
||||
|
||||
@@ -310,6 +310,7 @@ export const RequestPane: FC<Props> = ({
|
||||
uniquenessKey={uniqueKey}
|
||||
defaultValue={activeRequest.preRequestScript || ''}
|
||||
onChange={preRequestScript => patchRequest(requestId, { preRequestScript })}
|
||||
settings={settings}
|
||||
/>
|
||||
</ErrorBoundary>
|
||||
</TabItem>
|
||||
|
||||
Reference in New Issue
Block a user