mirror of
https://github.com/usebruno/bruno.git
synced 2025-01-22 21:58:44 +01:00
feat(#280): code generator polishing and support url interpolation
This commit is contained in:
parent
4603ec4d5e
commit
95532102ba
@ -30,6 +30,7 @@
|
||||
"graphiql": "^1.5.9",
|
||||
"graphql": "^16.6.0",
|
||||
"graphql-request": "^3.7.0",
|
||||
"handlebars": "^4.7.8",
|
||||
"httpsnippet": "^3.0.1",
|
||||
"idb": "^7.0.0",
|
||||
"immer": "^9.0.15",
|
||||
|
@ -1,21 +1,21 @@
|
||||
import CodeEditor from 'components/CodeEditor/index';
|
||||
import HTTPSnippet from 'httpsnippet';
|
||||
import { HTTPSnippet } from 'httpsnippet';
|
||||
import { useTheme } from 'providers/Theme/index';
|
||||
import { buildHarRequest } from 'utils/codegenerator/har';
|
||||
|
||||
const index = ({ language, item }) => {
|
||||
const { target, client, language: lang } = language;
|
||||
const snippet = new HTTPSnippet(buildHarRequest(item.request)).convert(target, client);
|
||||
const CodeView = ({ language, item }) => {
|
||||
const { storedTheme } = useTheme();
|
||||
return (
|
||||
<CodeEditor
|
||||
readOnly
|
||||
// value={JSON.stringify(item, null, 2)}
|
||||
value={snippet}
|
||||
theme={storedTheme}
|
||||
mode={lang}
|
||||
/>
|
||||
);
|
||||
const { target, client, language: lang } = language;
|
||||
let snippet = '';
|
||||
|
||||
try {
|
||||
snippet = new HTTPSnippet(buildHarRequest(item.request)).convert(target, client);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
snippet = 'Error generating code snippet';
|
||||
}
|
||||
|
||||
return <CodeEditor readOnly value={snippet} theme={storedTheme} mode={lang} />;
|
||||
};
|
||||
|
||||
export default index;
|
||||
export default CodeView;
|
||||
|
@ -3,7 +3,6 @@ import styled from 'styled-components';
|
||||
const StyledWrapper = styled.div`
|
||||
margin-inline: -1rem;
|
||||
margin-block: -1.5rem;
|
||||
position: absolute;
|
||||
background-color: ${(props) => props.theme.collection.environment.settings.bg};
|
||||
|
||||
.generate-code-sidebar {
|
||||
|
@ -2,8 +2,28 @@ import Modal from 'components/Modal/index';
|
||||
import { useState } from 'react';
|
||||
import CodeView from './CodeView';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
import ErrorBoundary from 'src/pages/ErrorBoundary/index';
|
||||
import { isValidUrl } from 'utils/url/index';
|
||||
import get from 'lodash/get';
|
||||
import handlebars from 'handlebars';
|
||||
import { findEnvironmentInCollection } from 'utils/collections';
|
||||
|
||||
const interpolateUrl = ({ url, envVars, collectionVariables, processEnvVars }) => {
|
||||
if (!url || !url.length || typeof url !== 'string') {
|
||||
return str;
|
||||
}
|
||||
|
||||
const template = handlebars.compile(url, { noEscape: true });
|
||||
|
||||
return template({
|
||||
...envVars,
|
||||
...collectionVariables,
|
||||
process: {
|
||||
env: {
|
||||
...processEnvVars
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const languages = [
|
||||
{
|
||||
@ -52,12 +72,32 @@ const languages = [
|
||||
client: 'httpie'
|
||||
}
|
||||
];
|
||||
const index = ({ item, onClose }) => {
|
||||
|
||||
const GenerateCodeItem = ({ collection, item, onClose }) => {
|
||||
const url = get(item, 'request.url') || '';
|
||||
const environment = findEnvironmentInCollection(collection, collection.activeEnvironmentUid);
|
||||
|
||||
let envVars = {};
|
||||
if (environment) {
|
||||
const vars = get(environment, 'variables', []);
|
||||
envVars = vars.reduce((acc, curr) => {
|
||||
acc[curr.name] = curr.value;
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
|
||||
const interpolatedUrl = interpolateUrl({
|
||||
url,
|
||||
envVars,
|
||||
collectionVariables: collection.collectionVariables,
|
||||
processEnvVars: collection.processEnvVariables
|
||||
});
|
||||
|
||||
const [selectedLanguage, setSelectedLanguage] = useState(languages[0]);
|
||||
return (
|
||||
<StyledWrapper>
|
||||
<Modal size="lg" title="Generate Code" handleCancel={onClose} hideFooter={true}>
|
||||
<div className="flex">
|
||||
<Modal size="lg" title="Generate Code" handleCancel={onClose} hideFooter={true}>
|
||||
<StyledWrapper>
|
||||
<div className="flex w-full">
|
||||
<div>
|
||||
<div className="generate-code-sidebar">
|
||||
{languages &&
|
||||
@ -75,20 +115,31 @@ const index = ({ item, onClose }) => {
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
{isValidUrl(item.request.url) ? (
|
||||
<CodeView language={selectedLanguage} item={item} />
|
||||
) : (
|
||||
<div className="flex flex-col justify-center items-center w-full">
|
||||
<div className="text-center">
|
||||
<h1 className="text-2xl font-bold">Invalid URL</h1>
|
||||
<p className="text-gray-500">Please check the URL and try again</p>
|
||||
<div className="flex-grow p-4">
|
||||
{isValidUrl(interpolatedUrl) ? (
|
||||
<CodeView
|
||||
language={selectedLanguage}
|
||||
item={{
|
||||
...item,
|
||||
request: {
|
||||
...item.request,
|
||||
url: interpolatedUrl
|
||||
}
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<div className="flex flex-col justify-center items-center w-full">
|
||||
<div className="text-center">
|
||||
<h1 className="text-2xl font-bold">Invalid URL: {interpolatedUrl}</h1>
|
||||
<p className="text-gray-500">Please check the URL and try again</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
</StyledWrapper>
|
||||
</StyledWrapper>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default index;
|
||||
export default GenerateCodeItem;
|
||||
|
@ -169,7 +169,7 @@ const CollectionItem = ({ item, collection, searchText }) => {
|
||||
<RunCollectionItem collection={collection} item={item} onClose={() => setRunCollectionModalOpen(false)} />
|
||||
)}
|
||||
{generateCodeItemModalOpen && (
|
||||
<GenerateCodeItem item={item} onClose={() => setGenerateCodeItemModalOpen(false)} />
|
||||
<GenerateCodeItem collection={collection} item={item} onClose={() => setGenerateCodeItemModalOpen(false)} />
|
||||
)}
|
||||
<div className={itemRowClassName} ref={(node) => drag(drop(node))}>
|
||||
<div className="flex items-center h-full w-full">
|
||||
|
@ -44,9 +44,8 @@ export const collectionsSlice = createSlice({
|
||||
// this is used in scenarios where we want to know the last action performed on the collection
|
||||
// and take some extra action based on that
|
||||
// for example, when a env is created, we want to auto select it the env modal
|
||||
collection.importedAt = new Date().getTime()
|
||||
collection.importedAt = new Date().getTime();
|
||||
collection.lastAction = null;
|
||||
console.log(collection)
|
||||
|
||||
collapseCollection(collection);
|
||||
addDepth(collection.items);
|
||||
@ -73,16 +72,16 @@ export const collectionsSlice = createSlice({
|
||||
state.collections = filter(state.collections, (c) => c.uid !== action.payload.collectionUid);
|
||||
},
|
||||
sortCollections: (state, action) => {
|
||||
state.collectionSortOrder = action.payload.order
|
||||
state.collectionSortOrder = action.payload.order;
|
||||
switch (action.payload.order) {
|
||||
case 'default':
|
||||
state.collections = state.collections.sort((a, b) => a.importedAt - b.importedAt)
|
||||
state.collections = state.collections.sort((a, b) => a.importedAt - b.importedAt);
|
||||
break;
|
||||
case 'alphabetical':
|
||||
state.collections = state.collections.sort((a, b) => a.name.localeCompare(b.name))
|
||||
state.collections = state.collections.sort((a, b) => a.name.localeCompare(b.name));
|
||||
break;
|
||||
case 'reverseAlphabetical':
|
||||
state.collections = state.collections.sort((a, b) => b.name.localeCompare(a.name))
|
||||
state.collections = state.collections.sort((a, b) => b.name.localeCompare(a.name));
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
@ -30,12 +30,11 @@ const createHeaders = (headers, mode) => {
|
||||
return headersArray;
|
||||
};
|
||||
|
||||
const createQuery = (url) => {
|
||||
const params = new URLSearchParams(url);
|
||||
return params.forEach((value, name) => {
|
||||
const createQuery = (queryParams = []) => {
|
||||
return queryParams.map((param) => {
|
||||
return {
|
||||
name,
|
||||
value
|
||||
name: param.name,
|
||||
value: param.value
|
||||
};
|
||||
});
|
||||
};
|
||||
@ -57,28 +56,14 @@ const createPostData = (body) => {
|
||||
}
|
||||
};
|
||||
|
||||
const createUrl = (request) => {
|
||||
let url = request.url;
|
||||
const variablePattern = /\{\{([^}]+)\}\}/g;
|
||||
const variables = request.url.match(variablePattern);
|
||||
if (variables) {
|
||||
variables.forEach((variable) => {
|
||||
const variableName = variable.replaceAll('{', '').replaceAll('}', '');
|
||||
const variableValue = request.vars.req.find((v) => v.name === variableName).value;
|
||||
url = url.replace(variable, variableValue);
|
||||
});
|
||||
}
|
||||
return url;
|
||||
};
|
||||
|
||||
export const buildHarRequest = (request) => {
|
||||
return {
|
||||
method: request.method,
|
||||
url: createUrl(request),
|
||||
url: request.url,
|
||||
httpVersion: 'HTTP/1.1',
|
||||
cookies: [],
|
||||
headers: createHeaders(request.headers, request.body.mode),
|
||||
queryString: createQuery(request.url),
|
||||
queryString: createQuery(request.params),
|
||||
postData: createPostData(request.body),
|
||||
headersSize: 0,
|
||||
bodySize: 0
|
||||
|
Loading…
Reference in New Issue
Block a user