mirror of
https://github.com/usebruno/bruno.git
synced 2025-02-17 02:00:49 +01:00
Merge pull request #282 from Its-treason/feature/preview-response-html
feature/preview-response-html
This commit is contained in:
commit
1a8feb8029
@ -1,9 +1,21 @@
|
|||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
const StyledWrapper = styled.div`
|
const StyledWrapper = styled.div`
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 100%;
|
||||||
|
grid-template-rows: 1.25rem calc(100% - 1.25rem);
|
||||||
|
|
||||||
|
/* This is a hack to force Codemirror to use all available space */
|
||||||
|
> div {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
div.CodeMirror {
|
div.CodeMirror {
|
||||||
/* todo: find a better way */
|
position: absolute;
|
||||||
height: calc(100vh - 220px);
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
@ -3,22 +3,18 @@ import CodeEditor from 'components/CodeEditor';
|
|||||||
import { useTheme } from 'providers/Theme';
|
import { useTheme } from 'providers/Theme';
|
||||||
import { useDispatch } from 'react-redux';
|
import { useDispatch } from 'react-redux';
|
||||||
import { sendRequest } from 'providers/ReduxStore/slices/collections/actions';
|
import { sendRequest } from 'providers/ReduxStore/slices/collections/actions';
|
||||||
|
import classnames from 'classnames';
|
||||||
import { getContentType, safeStringifyJSON, safeParseXML } from 'utils/common';
|
import { getContentType, safeStringifyJSON, safeParseXML } from 'utils/common';
|
||||||
import { getCodeMirrorModeBasedOnContentType } from 'utils/common/codemirror';
|
import { getCodeMirrorModeBasedOnContentType } from 'utils/common/codemirror';
|
||||||
|
|
||||||
import StyledWrapper from './StyledWrapper';
|
import StyledWrapper from './StyledWrapper';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
const QueryResult = ({ item, collection, data, width, disableRunEventListener, headers }) => {
|
const QueryResult = ({ item, collection, data, width, disableRunEventListener, headers }) => {
|
||||||
const { storedTheme } = useTheme();
|
const { storedTheme } = useTheme();
|
||||||
|
const [tab, setTab] = useState('raw');
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
const onRun = () => {
|
|
||||||
if (disableRunEventListener) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
dispatch(sendRequest(item, collection.uid));
|
|
||||||
};
|
|
||||||
|
|
||||||
const contentType = getContentType(headers);
|
const contentType = getContentType(headers);
|
||||||
const mode = getCodeMirrorModeBasedOnContentType(contentType);
|
const mode = getCodeMirrorModeBasedOnContentType(contentType);
|
||||||
|
|
||||||
@ -59,11 +55,68 @@ const QueryResult = ({ item, collection, data, width, disableRunEventListener, h
|
|||||||
|
|
||||||
const value = formatResponse(data, mode);
|
const value = formatResponse(data, mode);
|
||||||
|
|
||||||
|
const onRun = () => {
|
||||||
|
if (disableRunEventListener) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dispatch(sendRequest(item, collection.uid));
|
||||||
|
};
|
||||||
|
|
||||||
|
const getTabClassname = (tabName) => {
|
||||||
|
return classnames(`select-none ${tabName}`, {
|
||||||
|
'text-yellow-500': tabName === tab,
|
||||||
|
'cursor-pointer': tabName !== tab,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const getTabs = () => {
|
||||||
|
if (!mode.includes('html')) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledWrapper className="px-3 w-full" style={{ maxWidth: width }}>
|
<>
|
||||||
<div className="h-full">
|
<div className={getTabClassname('raw')} role="tab" onClick={() => setTab('raw')}>
|
||||||
<CodeEditor collection={collection} theme={storedTheme} onRun={onRun} value={value} mode={mode} readOnly />
|
Raw
|
||||||
</div>
|
</div>
|
||||||
|
<div className={getTabClassname('preview')} role="tab" onClick={() => setTab('preview')}>
|
||||||
|
Preview
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const activeResult = useMemo(() => {
|
||||||
|
if (tab === 'preview') {
|
||||||
|
// Add the Base tag to the head so content loads proparly. This also needs the correct CSP settings
|
||||||
|
const webViewSrc = data.replace('<head>', `<head><base href="${item.requestSent.url}">`);
|
||||||
|
return (
|
||||||
|
<webview
|
||||||
|
src={`data:text/html; charset=utf-8,${encodeURIComponent(webViewSrc)}`}
|
||||||
|
webpreferences="disableDialogs=true, javascript=yes"
|
||||||
|
className="h-full bg-white"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<CodeEditor
|
||||||
|
collection={collection}
|
||||||
|
theme={storedTheme}
|
||||||
|
onRun={onRun}
|
||||||
|
value={value}
|
||||||
|
mode={mode}
|
||||||
|
readOnly
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}, [tab, collection, storedTheme, onRun, value, mode]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<StyledWrapper className="px-3 w-full h-full" style={{ maxWidth: width }}>
|
||||||
|
<div className="flex justify-end gap-2 text-xs" role="tablist">
|
||||||
|
{getTabs()}
|
||||||
|
</div>
|
||||||
|
{activeResult}
|
||||||
</StyledWrapper>
|
</StyledWrapper>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -115,7 +115,7 @@ const ResponsePane = ({ rightPaneWidth, item, collection }) => {
|
|||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
<section className="flex flex-grow mt-5">{getTabPanel(focusedTab.responsePaneTab)}</section>
|
<section className="flex flex-grow">{getTabPanel(focusedTab.responsePaneTab)}</section>
|
||||||
</StyledWrapper>
|
</StyledWrapper>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -16,9 +16,7 @@ setContentSecurityPolicy(`
|
|||||||
default-src * 'unsafe-inline' 'unsafe-eval';
|
default-src * 'unsafe-inline' 'unsafe-eval';
|
||||||
script-src * 'unsafe-inline' 'unsafe-eval';
|
script-src * 'unsafe-inline' 'unsafe-eval';
|
||||||
connect-src * 'unsafe-inline';
|
connect-src * 'unsafe-inline';
|
||||||
base-uri 'none';
|
|
||||||
form-action 'none';
|
form-action 'none';
|
||||||
img-src 'self' data:image/svg+xml;
|
|
||||||
`);
|
`);
|
||||||
|
|
||||||
const menu = Menu.buildFromTemplate(menuTemplate);
|
const menu = Menu.buildFromTemplate(menuTemplate);
|
||||||
@ -35,7 +33,8 @@ app.on('ready', async () => {
|
|||||||
webPreferences: {
|
webPreferences: {
|
||||||
nodeIntegration: true,
|
nodeIntegration: true,
|
||||||
contextIsolation: true,
|
contextIsolation: true,
|
||||||
preload: path.join(__dirname, 'preload.js')
|
preload: path.join(__dirname, 'preload.js'),
|
||||||
|
webviewTag: true,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user