feat(#245): Add HTML preview to response

This commit is contained in:
Its-treason 2023-10-02 14:26:24 +02:00
parent 78e5cd3c03
commit e720fed63b
4 changed files with 79 additions and 15 deletions

View File

@ -1,9 +1,28 @@
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: 50px calc(100% - 50px);
/* If there is only one element (the preview, not tabs) make it span over both grid rows */
> *:last-child:first-child {
grid-row: 1 / 3;
margin-top: 1.25rem;
height: 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%;
} }
`; `;

View File

@ -3,11 +3,15 @@ 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 StyledWrapper from './StyledWrapper'; import StyledWrapper from './StyledWrapper';
import { useState } from 'react';
import { useMemo } from 'react';
const QueryResult = ({ item, collection, value, width, disableRunEventListener, mode }) => { const QueryResult = ({ item, collection, value, width, disableRunEventListener, mode }) => {
const { storedTheme } = useTheme(); const { storedTheme } = useTheme();
const [tab, setTab] = useState('raw');
const dispatch = useDispatch(); const dispatch = useDispatch();
const onRun = () => { const onRun = () => {
@ -17,9 +21,39 @@ const QueryResult = ({ item, collection, value, width, disableRunEventListener,
dispatch(sendRequest(item, collection.uid)); dispatch(sendRequest(item, collection.uid));
}; };
const getTabClassname = (tabName) => {
return classnames(`tab select-none ${tabName}`, {
active: tabName === tab
});
};
const tabs = [(
<div className={getTabClassname('raw')} role="tab" onClick={() => setTab('raw')}>
Raw
</div>
)];
if (mode.includes('text/html')) {
tabs.push(
<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 = value.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 ( return (
<StyledWrapper className="px-3 w-full" style={{ maxWidth: width }}>
<div className="h-full">
<CodeEditor <CodeEditor
collection={collection} collection={collection}
theme={storedTheme} theme={storedTheme}
@ -28,7 +62,17 @@ const QueryResult = ({ item, collection, value, width, disableRunEventListener,
mode={mode} mode={mode}
readOnly readOnly
/> />
);
}, [tab, collection, storedTheme, onRun, value, mode]);
return (
<StyledWrapper className="px-3 w-full h-full" style={{ maxWidth: width }}>
{tabs.length > 1 ? (
<div className="flex flex-wrap items-center px-3 tabs mb-3" role="tablist">
{tabs}
</div> </div>
) : null}
{activeResult}
</StyledWrapper> </StyledWrapper>
); );
}; };

View File

@ -116,7 +116,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>
); );
}; };

View File

@ -35,7 +35,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,
} }
}); });