feat(#119): ui placeholders for basic and bearer auths

This commit is contained in:
Anoop M D 2023-09-29 02:11:04 +05:30
parent 51ee37cf96
commit 0f1e330dc5
9 changed files with 202 additions and 2 deletions

View File

@ -0,0 +1,25 @@
import styled from 'styled-components';
const Wrapper = styled.div`
font-size: 0.8125rem;
.auth-mode-selector {
background: ${(props) => props.theme.requestTabPanel.bodyModeSelect.color};
border-radius: 3px;
.dropdown-item {
padding: 0.2rem 0.6rem !important;
}
.label-item {
padding: 0.2rem 0.6rem !important;
}
}
.caret {
color: rgb(140, 140, 140);
fill: rgb(140 140 140);
}
`;
export default Wrapper;

View File

@ -0,0 +1,70 @@
import React, { useRef, forwardRef } from 'react';
import get from 'lodash/get';
import { IconCaretDown } from '@tabler/icons';
import Dropdown from 'components/Dropdown';
import { useDispatch } from 'react-redux';
import { updateRequestAuthMode } from 'providers/ReduxStore/slices/collections';
import { humanizeRequestAuthMode } from 'utils/collections';
import StyledWrapper from './StyledWrapper';
const AuthMode = ({ item, collection }) => {
const dispatch = useDispatch();
const dropdownTippyRef = useRef();
const onDropdownCreate = (ref) => (dropdownTippyRef.current = ref);
const authMode = item.draft ? get(item, 'draft.request.auth.mode') : get(item, 'request.auth.mode');
const Icon = forwardRef((props, ref) => {
return (
<div ref={ref} className="flex items-center justify-center pl-3 py-1 select-none">
{humanizeRequestAuthMode(authMode)} <IconCaretDown className="caret ml-2 mr-2" size={14} strokeWidth={2} />
</div>
);
});
const onModeChange = (value) => {
dispatch(
updateRequestAuthMode({
itemUid: item.uid,
collectionUid: collection.uid,
mode: value
})
);
};
return (
<StyledWrapper>
<div className="inline-flex items-center cursor-pointer auth-mode-selector">
<Dropdown onCreate={onDropdownCreate} icon={<Icon />} placement="bottom-end">
<div
className="dropdown-item"
onClick={() => {
dropdownTippyRef.current.hide();
onModeChange('basic');
}}
>
Basic Auth
</div>
<div
className="dropdown-item"
onClick={() => {
dropdownTippyRef.current.hide();
onModeChange('bearer');
}}
>
Bearer Token
</div>
<div
className="dropdown-item"
onClick={() => {
dropdownTippyRef.current.hide();
onModeChange('none');
}}
>
No Auth
</div>
</Dropdown>
</div>
</StyledWrapper>
);
};
export default AuthMode;

View File

@ -0,0 +1,5 @@
import styled from 'styled-components';
const Wrapper = styled.div``;
export default Wrapper;

View File

@ -0,0 +1,32 @@
import React from 'react';
import get from 'lodash/get';
import { useDispatch } from 'react-redux';
import { updateRequestBody } from 'providers/ReduxStore/slices/collections';
import { sendRequest, saveRequest } from 'providers/ReduxStore/slices/collections/actions';
import StyledWrapper from './StyledWrapper';
const RequestBody = ({ item, collection }) => {
const dispatch = useDispatch();
const authMode = item.draft ? get(item, 'draft.request.auth.mode') : get(item, 'request.auth.mode');
const onEdit = (value) => {
// dispatch(
// updateRequestBody({
// content: value,
// itemUid: item.uid,
// collectionUid: collection.uid
// })
// );
};
if (authMode === 'basic') {
return <div>Basic Auth</div>;
}
if (authMode === 'bearer') {
return <div>Bearer Token</div>;
}
return <StyledWrapper className="w-full">No Auth</StyledWrapper>;
};
export default RequestBody;

View File

@ -7,6 +7,8 @@ import QueryParams from 'components/RequestPane/QueryParams';
import RequestHeaders from 'components/RequestPane/RequestHeaders'; import RequestHeaders from 'components/RequestPane/RequestHeaders';
import RequestBody from 'components/RequestPane/RequestBody'; import RequestBody from 'components/RequestPane/RequestBody';
import RequestBodyMode from 'components/RequestPane/RequestBody/RequestBodyMode'; import RequestBodyMode from 'components/RequestPane/RequestBody/RequestBodyMode';
import Auth from 'components/RequestPane/Auth';
import AuthMode from 'components/RequestPane/Auth/AuthMode';
import Vars from 'components/RequestPane/Vars'; import Vars from 'components/RequestPane/Vars';
import Assertions from 'components/RequestPane/Assertions'; import Assertions from 'components/RequestPane/Assertions';
import Script from 'components/RequestPane/Script'; import Script from 'components/RequestPane/Script';
@ -38,6 +40,9 @@ const HttpRequestPane = ({ item, collection, leftPaneWidth }) => {
case 'headers': { case 'headers': {
return <RequestHeaders item={item} collection={collection} />; return <RequestHeaders item={item} collection={collection} />;
} }
case 'auth': {
return <Auth item={item} collection={collection} />;
}
case 'vars': { case 'vars': {
return <Vars item={item} collection={collection} />; return <Vars item={item} collection={collection} />;
} }
@ -83,6 +88,9 @@ const HttpRequestPane = ({ item, collection, leftPaneWidth }) => {
<div className={getTabClassname('headers')} role="tab" onClick={() => selectTab('headers')}> <div className={getTabClassname('headers')} role="tab" onClick={() => selectTab('headers')}>
Headers Headers
</div> </div>
<div className={getTabClassname('auth')} role="tab" onClick={() => selectTab('auth')}>
Auth
</div>
<div className={getTabClassname('vars')} role="tab" onClick={() => selectTab('vars')}> <div className={getTabClassname('vars')} role="tab" onClick={() => selectTab('vars')}>
Vars Vars
</div> </div>
@ -95,13 +103,16 @@ const HttpRequestPane = ({ item, collection, leftPaneWidth }) => {
<div className={getTabClassname('tests')} role="tab" onClick={() => selectTab('tests')}> <div className={getTabClassname('tests')} role="tab" onClick={() => selectTab('tests')}>
Tests Tests
</div> </div>
{/* Moved to post mvp */}
{/* <div className={getTabClassname('auth')} role="tab" onClick={() => selectTab('auth')}>Auth</div> */}
{focusedTab.requestPaneTab === 'body' ? ( {focusedTab.requestPaneTab === 'body' ? (
<div className="flex flex-grow justify-end items-center"> <div className="flex flex-grow justify-end items-center">
<RequestBodyMode item={item} collection={collection} /> <RequestBodyMode item={item} collection={collection} />
</div> </div>
) : null} ) : null}
{focusedTab.requestPaneTab === 'auth' ? (
<div className="flex flex-grow justify-end items-center">
<AuthMode item={item} collection={collection} />
</div>
) : null}
</div> </div>
<section className={`flex w-full ${['script', 'vars'].includes(focusedTab.requestPaneTab) ? '' : 'mt-5'}`}> <section className={`flex w-full ${['script', 'vars'].includes(focusedTab.requestPaneTab) ? '' : 'mt-5'}`}>
{getTabPanel(focusedTab.requestPaneTab)} {getTabPanel(focusedTab.requestPaneTab)}

View File

@ -563,6 +563,20 @@ export const collectionsSlice = createSlice({
} }
} }
}, },
updateRequestAuthMode: (state, action) => {
const collection = findCollectionByUid(state.collections, action.payload.collectionUid);
if (collection && collection.items && collection.items.length) {
const item = findItemInCollection(collection, action.payload.itemUid);
if (item && isItemARequest(item)) {
if (!item.draft) {
item.draft = cloneDeep(item);
}
item.draft.request.auth.mode = action.payload.mode;
}
}
},
updateRequestBodyMode: (state, action) => { updateRequestBodyMode: (state, action) => {
const collection = findCollectionByUid(state.collections, action.payload.collectionUid); const collection = findCollectionByUid(state.collections, action.payload.collectionUid);
@ -1170,6 +1184,7 @@ export const {
addMultipartFormParam, addMultipartFormParam,
updateMultipartFormParam, updateMultipartFormParam,
deleteMultipartFormParam, deleteMultipartFormParam,
updateRequestAuthMode,
updateRequestBodyMode, updateRequestBodyMode,
updateRequestBody, updateRequestBody,
updateRequestGraphqlQuery, updateRequestGraphqlQuery,

View File

@ -445,6 +445,22 @@ export const humanizeRequestBodyMode = (mode) => {
return label; return label;
}; };
export const humanizeRequestAuthMode = (mode) => {
let label = 'No Auth';
switch (mode) {
case 'basic': {
label = 'Basic Auth';
break;
}
case 'bearer': {
label = 'Bearer Token';
break;
}
}
return label;
};
export const refreshUidsInItem = (item) => { export const refreshUidsInItem = (item) => {
item.uid = uuid(); item.uid = uuid();

View File

@ -61,6 +61,7 @@ const bruToJson = (bru) => {
url: _.get(json, 'http.url'), url: _.get(json, 'http.url'),
params: _.get(json, 'query', []), params: _.get(json, 'query', []),
headers: _.get(json, 'headers', []), headers: _.get(json, 'headers', []),
auth: _.get(json, 'auth', {}),
body: _.get(json, 'body', {}), body: _.get(json, 'body', {}),
script: _.get(json, 'script', {}), script: _.get(json, 'script', {}),
vars: _.get(json, 'vars', {}), vars: _.get(json, 'vars', {}),
@ -69,6 +70,7 @@ const bruToJson = (bru) => {
} }
}; };
transformedJson.request.auth.mode = _.get(json, 'http.auth', 'none');
transformedJson.request.body.mode = _.get(json, 'http.body', 'none'); transformedJson.request.body.mode = _.get(json, 'http.body', 'none');
return transformedJson; return transformedJson;
@ -104,10 +106,12 @@ const jsonToBru = (json) => {
http: { http: {
method: _.lowerCase(_.get(json, 'request.method')), method: _.lowerCase(_.get(json, 'request.method')),
url: _.get(json, 'request.url'), url: _.get(json, 'request.url'),
auth: _.get(json, 'request.auth.mode', 'none'),
body: _.get(json, 'request.body.mode', 'none') body: _.get(json, 'request.body.mode', 'none')
}, },
query: _.get(json, 'request.params', []), query: _.get(json, 'request.params', []),
headers: _.get(json, 'request.headers', []), headers: _.get(json, 'request.headers', []),
auth: _.get(json, 'request.auth', {}),
body: _.get(json, 'request.body', {}), body: _.get(json, 'request.body', {}),
script: _.get(json, 'request.script', {}), script: _.get(json, 'request.script', {}),
vars: { vars: {

View File

@ -69,6 +69,27 @@ const requestBodySchema = Yup.object({
.noUnknown(true) .noUnknown(true)
.strict(); .strict();
const authBasicSchema = Yup.object({
username: Yup.string().nullable(),
password: Yup.string().nullable()
})
.noUnknown(true)
.strict();
const authBearerSchema = Yup.object({
token: Yup.string().nullable()
})
.noUnknown(true)
.strict();
const authSchema = Yup.object({
mode: Yup.string().oneOf(['none', 'basic', 'bearer']).required('mode is required'),
basic: authBasicSchema.nullable(),
bearer: authBearerSchema.nullable()
})
.noUnknown(true)
.strict();
// Right now, the request schema is very tightly coupled with http request // Right now, the request schema is very tightly coupled with http request
// As we introduce more request types in the future, we will improve the definition to support // As we introduce more request types in the future, we will improve the definition to support
// schema structure based on other request type // schema structure based on other request type
@ -77,6 +98,7 @@ const requestSchema = Yup.object({
method: requestMethodSchema, method: requestMethodSchema,
headers: Yup.array().of(keyValueSchema).required('headers are required'), headers: Yup.array().of(keyValueSchema).required('headers are required'),
params: Yup.array().of(keyValueSchema).required('params are required'), params: Yup.array().of(keyValueSchema).required('params are required'),
auth: authSchema,
body: requestBodySchema, body: requestBodySchema,
script: Yup.object({ script: Yup.object({
req: Yup.string().nullable(), req: Yup.string().nullable(),