mirror of
https://github.com/usebruno/bruno.git
synced 2025-02-02 10:59:22 +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",
|
"graphiql": "^1.5.9",
|
||||||
"graphql": "^16.6.0",
|
"graphql": "^16.6.0",
|
||||||
"graphql-request": "^3.7.0",
|
"graphql-request": "^3.7.0",
|
||||||
|
"handlebars": "^4.7.8",
|
||||||
"httpsnippet": "^3.0.1",
|
"httpsnippet": "^3.0.1",
|
||||||
"idb": "^7.0.0",
|
"idb": "^7.0.0",
|
||||||
"immer": "^9.0.15",
|
"immer": "^9.0.15",
|
||||||
|
@ -1,21 +1,21 @@
|
|||||||
import CodeEditor from 'components/CodeEditor/index';
|
import CodeEditor from 'components/CodeEditor/index';
|
||||||
import HTTPSnippet from 'httpsnippet';
|
import { HTTPSnippet } from 'httpsnippet';
|
||||||
import { useTheme } from 'providers/Theme/index';
|
import { useTheme } from 'providers/Theme/index';
|
||||||
import { buildHarRequest } from 'utils/codegenerator/har';
|
import { buildHarRequest } from 'utils/codegenerator/har';
|
||||||
|
|
||||||
const index = ({ language, item }) => {
|
const CodeView = ({ language, item }) => {
|
||||||
const { target, client, language: lang } = language;
|
|
||||||
const snippet = new HTTPSnippet(buildHarRequest(item.request)).convert(target, client);
|
|
||||||
const { storedTheme } = useTheme();
|
const { storedTheme } = useTheme();
|
||||||
return (
|
const { target, client, language: lang } = language;
|
||||||
<CodeEditor
|
let snippet = '';
|
||||||
readOnly
|
|
||||||
// value={JSON.stringify(item, null, 2)}
|
try {
|
||||||
value={snippet}
|
snippet = new HTTPSnippet(buildHarRequest(item.request)).convert(target, client);
|
||||||
theme={storedTheme}
|
} catch (e) {
|
||||||
mode={lang}
|
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`
|
const StyledWrapper = styled.div`
|
||||||
margin-inline: -1rem;
|
margin-inline: -1rem;
|
||||||
margin-block: -1.5rem;
|
margin-block: -1.5rem;
|
||||||
position: absolute;
|
|
||||||
background-color: ${(props) => props.theme.collection.environment.settings.bg};
|
background-color: ${(props) => props.theme.collection.environment.settings.bg};
|
||||||
|
|
||||||
.generate-code-sidebar {
|
.generate-code-sidebar {
|
||||||
|
@ -2,8 +2,28 @@ import Modal from 'components/Modal/index';
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import CodeView from './CodeView';
|
import CodeView from './CodeView';
|
||||||
import StyledWrapper from './StyledWrapper';
|
import StyledWrapper from './StyledWrapper';
|
||||||
import ErrorBoundary from 'src/pages/ErrorBoundary/index';
|
|
||||||
import { isValidUrl } from 'utils/url/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 = [
|
const languages = [
|
||||||
{
|
{
|
||||||
@ -52,12 +72,32 @@ const languages = [
|
|||||||
client: 'httpie'
|
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]);
|
const [selectedLanguage, setSelectedLanguage] = useState(languages[0]);
|
||||||
return (
|
return (
|
||||||
<StyledWrapper>
|
|
||||||
<Modal size="lg" title="Generate Code" handleCancel={onClose} hideFooter={true}>
|
<Modal size="lg" title="Generate Code" handleCancel={onClose} hideFooter={true}>
|
||||||
<div className="flex">
|
<StyledWrapper>
|
||||||
|
<div className="flex w-full">
|
||||||
<div>
|
<div>
|
||||||
<div className="generate-code-sidebar">
|
<div className="generate-code-sidebar">
|
||||||
{languages &&
|
{languages &&
|
||||||
@ -75,20 +115,31 @@ const index = ({ item, onClose }) => {
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{isValidUrl(item.request.url) ? (
|
<div className="flex-grow p-4">
|
||||||
<CodeView language={selectedLanguage} item={item} />
|
{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="flex flex-col justify-center items-center w-full">
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
<h1 className="text-2xl font-bold">Invalid URL</h1>
|
<h1 className="text-2xl font-bold">Invalid URL: {interpolatedUrl}</h1>
|
||||||
<p className="text-gray-500">Please check the URL and try again</p>
|
<p className="text-gray-500">Please check the URL and try again</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</div>
|
||||||
</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)} />
|
<RunCollectionItem collection={collection} item={item} onClose={() => setRunCollectionModalOpen(false)} />
|
||||||
)}
|
)}
|
||||||
{generateCodeItemModalOpen && (
|
{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={itemRowClassName} ref={(node) => drag(drop(node))}>
|
||||||
<div className="flex items-center h-full w-full">
|
<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
|
// 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
|
// and take some extra action based on that
|
||||||
// for example, when a env is created, we want to auto select it the env modal
|
// 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;
|
collection.lastAction = null;
|
||||||
console.log(collection)
|
|
||||||
|
|
||||||
collapseCollection(collection);
|
collapseCollection(collection);
|
||||||
addDepth(collection.items);
|
addDepth(collection.items);
|
||||||
@ -73,16 +72,16 @@ export const collectionsSlice = createSlice({
|
|||||||
state.collections = filter(state.collections, (c) => c.uid !== action.payload.collectionUid);
|
state.collections = filter(state.collections, (c) => c.uid !== action.payload.collectionUid);
|
||||||
},
|
},
|
||||||
sortCollections: (state, action) => {
|
sortCollections: (state, action) => {
|
||||||
state.collectionSortOrder = action.payload.order
|
state.collectionSortOrder = action.payload.order;
|
||||||
switch (action.payload.order) {
|
switch (action.payload.order) {
|
||||||
case 'default':
|
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;
|
break;
|
||||||
case 'alphabetical':
|
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;
|
break;
|
||||||
case 'reverseAlphabetical':
|
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;
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -30,12 +30,11 @@ const createHeaders = (headers, mode) => {
|
|||||||
return headersArray;
|
return headersArray;
|
||||||
};
|
};
|
||||||
|
|
||||||
const createQuery = (url) => {
|
const createQuery = (queryParams = []) => {
|
||||||
const params = new URLSearchParams(url);
|
return queryParams.map((param) => {
|
||||||
return params.forEach((value, name) => {
|
|
||||||
return {
|
return {
|
||||||
name,
|
name: param.name,
|
||||||
value
|
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) => {
|
export const buildHarRequest = (request) => {
|
||||||
return {
|
return {
|
||||||
method: request.method,
|
method: request.method,
|
||||||
url: createUrl(request),
|
url: request.url,
|
||||||
httpVersion: 'HTTP/1.1',
|
httpVersion: 'HTTP/1.1',
|
||||||
cookies: [],
|
cookies: [],
|
||||||
headers: createHeaders(request.headers, request.body.mode),
|
headers: createHeaders(request.headers, request.body.mode),
|
||||||
queryString: createQuery(request.url),
|
queryString: createQuery(request.params),
|
||||||
postData: createPostData(request.body),
|
postData: createPostData(request.body),
|
||||||
headersSize: 0,
|
headersSize: 0,
|
||||||
bodySize: 0
|
bodySize: 0
|
||||||
|
Loading…
Reference in New Issue
Block a user