diff --git a/packages/bruno-app/src/components/CollectionSettings/Auth/AuthMode/index.js b/packages/bruno-app/src/components/CollectionSettings/Auth/AuthMode/index.js index 2c541cc289..c7f157a433 100644 --- a/packages/bruno-app/src/components/CollectionSettings/Auth/AuthMode/index.js +++ b/packages/bruno-app/src/components/CollectionSettings/Auth/AuthMode/index.js @@ -95,7 +95,7 @@ const AuthMode = ({ collection }) => { onModeChange('oauth2'); }} > - Oauth2 + OAuth 2.0
{ - const dispatch = useDispatch(); - const { storedTheme } = useTheme(); - - const oAuth = get(collection, 'root.request.auth.oauth2', {}); - - const handleRun = async () => { - dispatch(sendCollectionOauth2Request(collection.uid)); - }; - - const handleSave = () => dispatch(saveCollectionRoot(collection.uid)); - - const { callbackUrl, authorizationUrl, accessTokenUrl, clientId, clientSecret, scope, state, pkce } = oAuth; - - const handleChange = (key, value) => { - dispatch( - updateCollectionAuth({ - mode: 'oauth2', - collectionUid: collection.uid, - content: { - grantType: 'authorization_code', - callbackUrl, - authorizationUrl, - accessTokenUrl, - clientId, - clientSecret, - scope, - state, - pkce, - [key]: value - } - }) - ); - }; - - const handlePKCEToggle = (e) => { - dispatch( - updateCollectionAuth({ - mode: 'oauth2', - collectionUid: collection.uid, - content: { - grantType: 'authorization_code', - callbackUrl, - authorizationUrl, - accessTokenUrl, - clientId, - clientSecret, - scope, - state, - pkce: !Boolean(oAuth?.['pkce']) - } - }) - ); - }; - - const handleClearCache = (e) => { - clearOauth2Cache(collection?.uid) - .then(() => { - toast.success('cleared cache successfully'); - }) - .catch((err) => { - toast.error(err.message); - }); - }; - - return ( - - {inputsConfig.map((input) => { - const { key, label, isSecret } = input; - return ( -
- -
- handleChange(key, val)} - onRun={handleRun} - collection={collection} - isSecret={isSecret} - /> -
-
- ); - })} -
- - -
-
- - -
-
- ); -}; - -export default OAuth2AuthorizationCode; diff --git a/packages/bruno-app/src/components/CollectionSettings/Auth/OAuth2/AuthorizationCode/inputsConfig.js b/packages/bruno-app/src/components/CollectionSettings/Auth/OAuth2/AuthorizationCode/inputsConfig.js deleted file mode 100644 index a100ce8e53..0000000000 --- a/packages/bruno-app/src/components/CollectionSettings/Auth/OAuth2/AuthorizationCode/inputsConfig.js +++ /dev/null @@ -1,33 +0,0 @@ -const inputsConfig = [ - { - key: 'callbackUrl', - label: 'Callback URL' - }, - { - key: 'authorizationUrl', - label: 'Authorization URL' - }, - { - key: 'accessTokenUrl', - label: 'Access Token URL' - }, - { - key: 'clientId', - label: 'Client ID' - }, - { - key: 'clientSecret', - label: 'Client Secret', - isSecret: true - }, - { - key: 'scope', - label: 'Scope' - }, - { - key: 'state', - label: 'State' - } -]; - -export { inputsConfig }; diff --git a/packages/bruno-app/src/components/CollectionSettings/Auth/OAuth2/ClientCredentials/StyledWrapper.js b/packages/bruno-app/src/components/CollectionSettings/Auth/OAuth2/ClientCredentials/StyledWrapper.js deleted file mode 100644 index 856f35b9b9..0000000000 --- a/packages/bruno-app/src/components/CollectionSettings/Auth/OAuth2/ClientCredentials/StyledWrapper.js +++ /dev/null @@ -1,16 +0,0 @@ -import styled from 'styled-components'; - -const Wrapper = styled.div` - label { - font-size: 0.8125rem; - } - .single-line-editor-wrapper { - max-width: 400px; - padding: 0.15rem 0.4rem; - border-radius: 3px; - border: solid 1px ${(props) => props.theme.input.border}; - background-color: ${(props) => props.theme.input.bg}; - } -`; - -export default Wrapper; diff --git a/packages/bruno-app/src/components/CollectionSettings/Auth/OAuth2/ClientCredentials/index.js b/packages/bruno-app/src/components/CollectionSettings/Auth/OAuth2/ClientCredentials/index.js deleted file mode 100644 index d69122b482..0000000000 --- a/packages/bruno-app/src/components/CollectionSettings/Auth/OAuth2/ClientCredentials/index.js +++ /dev/null @@ -1,70 +0,0 @@ -import React from 'react'; -import get from 'lodash/get'; -import { useTheme } from 'providers/Theme'; -import { useDispatch } from 'react-redux'; -import SingleLineEditor from 'components/SingleLineEditor'; -import { saveCollectionRoot, sendCollectionOauth2Request } from 'providers/ReduxStore/slices/collections/actions'; -import StyledWrapper from './StyledWrapper'; -import { inputsConfig } from './inputsConfig'; -import { updateCollectionAuth } from 'providers/ReduxStore/slices/collections/index'; - -const OAuth2ClientCredentials = ({ collection }) => { - const dispatch = useDispatch(); - const { storedTheme } = useTheme(); - - const oAuth = get(collection, 'root.request.auth.oauth2', {}); - - const handleRun = async () => { - dispatch(sendCollectionOauth2Request(collection.uid)); - }; - - const handleSave = () => dispatch(saveCollectionRoot(collection.uid)); - - const { accessTokenUrl, clientId, clientSecret, scope } = oAuth; - - const handleChange = (key, value) => { - dispatch( - updateCollectionAuth({ - mode: 'oauth2', - collectionUid: collection.uid, - content: { - grantType: 'client_credentials', - accessTokenUrl, - clientId, - clientSecret, - scope, - [key]: value - } - }) - ); - }; - - return ( - - {inputsConfig.map((input) => { - const { key, label, isSecret } = input; - return ( -
- -
- handleChange(key, val)} - onRun={handleRun} - collection={collection} - isSecret={isSecret} - /> -
-
- ); - })} - -
- ); -}; - -export default OAuth2ClientCredentials; diff --git a/packages/bruno-app/src/components/CollectionSettings/Auth/OAuth2/ClientCredentials/inputsConfig.js b/packages/bruno-app/src/components/CollectionSettings/Auth/OAuth2/ClientCredentials/inputsConfig.js deleted file mode 100644 index f2cd88ae3d..0000000000 --- a/packages/bruno-app/src/components/CollectionSettings/Auth/OAuth2/ClientCredentials/inputsConfig.js +++ /dev/null @@ -1,21 +0,0 @@ -const inputsConfig = [ - { - key: 'accessTokenUrl', - label: 'Access Token URL' - }, - { - key: 'clientId', - label: 'Client ID' - }, - { - key: 'clientSecret', - label: 'Client Secret', - isSecret: true - }, - { - key: 'scope', - label: 'Scope' - } -]; - -export { inputsConfig }; diff --git a/packages/bruno-app/src/components/CollectionSettings/Auth/OAuth2/GrantTypeSelector/StyledWrapper.js b/packages/bruno-app/src/components/CollectionSettings/Auth/OAuth2/GrantTypeSelector/StyledWrapper.js deleted file mode 100644 index bb42bdb49b..0000000000 --- a/packages/bruno-app/src/components/CollectionSettings/Auth/OAuth2/GrantTypeSelector/StyledWrapper.js +++ /dev/null @@ -1,54 +0,0 @@ -import styled from 'styled-components'; - -const Wrapper = styled.div` - font-size: 0.8125rem; - - .grant-type-mode-selector { - padding: 0.5rem 0px; - border-radius: 3px; - border: solid 1px ${(props) => props.theme.input.border}; - background-color: ${(props) => props.theme.input.bg}; - - .dropdown { - width: fit-content; - - div[data-tippy-root] { - width: fit-content; - } - .tippy-box { - width: fit-content; - max-width: none !important; - - .tippy-content: { - width: fit-content; - max-width: none !important; - } - } - } - - .grant-type-label { - width: fit-content; - color: ${(props) => props.theme.colors.text.yellow}; - justify-content: space-between; - padding: 0 0.5rem; - } - - .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); - } - label { - font-size: 0.8125rem; - } -`; - -export default Wrapper; diff --git a/packages/bruno-app/src/components/CollectionSettings/Auth/OAuth2/GrantTypeSelector/index.js b/packages/bruno-app/src/components/CollectionSettings/Auth/OAuth2/GrantTypeSelector/index.js deleted file mode 100644 index 5d92893820..0000000000 --- a/packages/bruno-app/src/components/CollectionSettings/Auth/OAuth2/GrantTypeSelector/index.js +++ /dev/null @@ -1,98 +0,0 @@ -import React, { useRef, forwardRef } from 'react'; -import get from 'lodash/get'; -import Dropdown from 'components/Dropdown'; -import { useDispatch } from 'react-redux'; -import StyledWrapper from './StyledWrapper'; -import { IconCaretDown } from '@tabler/icons'; -import { updateAuth } from 'providers/ReduxStore/slices/collections'; -import { humanizeGrantType } from 'utils/collections'; -import { useEffect } from 'react'; -import { updateCollectionAuth, updateCollectionAuthMode } from 'providers/ReduxStore/slices/collections/index'; - -const GrantTypeSelector = ({ collection }) => { - const dispatch = useDispatch(); - const dropdownTippyRef = useRef(); - const onDropdownCreate = (ref) => (dropdownTippyRef.current = ref); - - const oAuth = get(collection, 'root.request.auth.oauth2', {}); - - const Icon = forwardRef((props, ref) => { - return ( -
- {humanizeGrantType(oAuth?.grantType)} -
- ); - }); - - const onGrantTypeChange = (grantType) => { - dispatch( - updateCollectionAuth({ - mode: 'oauth2', - collectionUid: collection.uid, - content: { - grantType - } - }) - ); - }; - - useEffect(() => { - // initialize redux state with a default oauth2 grant type - // authorization_code - default option - !oAuth?.grantType && - dispatch( - updateCollectionAuthMode({ - mode: 'oauth2', - collectionUid: collection.uid - }) - ); - !oAuth?.grantType && - dispatch( - updateCollectionAuth({ - mode: 'oauth2', - collectionUid: collection.uid, - content: { - grantType: 'authorization_code' - } - }) - ); - }, [oAuth]); - - return ( - - -
- } placement="bottom-end"> -
{ - dropdownTippyRef.current.hide(); - onGrantTypeChange('password'); - }} - > - Password Credentials -
-
{ - dropdownTippyRef.current.hide(); - onGrantTypeChange('authorization_code'); - }} - > - Authorization Code -
-
{ - dropdownTippyRef.current.hide(); - onGrantTypeChange('client_credentials'); - }} - > - Client Credentials -
-
-
-
- ); -}; -export default GrantTypeSelector; diff --git a/packages/bruno-app/src/components/CollectionSettings/Auth/OAuth2/PasswordCredentials/StyledWrapper.js b/packages/bruno-app/src/components/CollectionSettings/Auth/OAuth2/PasswordCredentials/StyledWrapper.js deleted file mode 100644 index 856f35b9b9..0000000000 --- a/packages/bruno-app/src/components/CollectionSettings/Auth/OAuth2/PasswordCredentials/StyledWrapper.js +++ /dev/null @@ -1,16 +0,0 @@ -import styled from 'styled-components'; - -const Wrapper = styled.div` - label { - font-size: 0.8125rem; - } - .single-line-editor-wrapper { - max-width: 400px; - padding: 0.15rem 0.4rem; - border-radius: 3px; - border: solid 1px ${(props) => props.theme.input.border}; - background-color: ${(props) => props.theme.input.bg}; - } -`; - -export default Wrapper; diff --git a/packages/bruno-app/src/components/CollectionSettings/Auth/OAuth2/PasswordCredentials/index.js b/packages/bruno-app/src/components/CollectionSettings/Auth/OAuth2/PasswordCredentials/index.js deleted file mode 100644 index d2d9eed1f2..0000000000 --- a/packages/bruno-app/src/components/CollectionSettings/Auth/OAuth2/PasswordCredentials/index.js +++ /dev/null @@ -1,72 +0,0 @@ -import React from 'react'; -import get from 'lodash/get'; -import { useTheme } from 'providers/Theme'; -import { useDispatch } from 'react-redux'; -import SingleLineEditor from 'components/SingleLineEditor'; -import { saveCollectionRoot, sendCollectionOauth2Request } from 'providers/ReduxStore/slices/collections/actions'; -import StyledWrapper from './StyledWrapper'; -import { inputsConfig } from './inputsConfig'; -import { updateCollectionAuth } from 'providers/ReduxStore/slices/collections/index'; - -const OAuth2AuthorizationCode = ({ item, collection }) => { - const dispatch = useDispatch(); - const { storedTheme } = useTheme(); - - const oAuth = get(collection, 'root.request.auth.oauth2', {}); - - const handleRun = async () => { - dispatch(sendCollectionOauth2Request(collection.uid)); - }; - - const handleSave = () => dispatch(saveCollectionRoot(collection.uid)); - - const { accessTokenUrl, username, password, clientId, clientSecret, scope } = oAuth; - - const handleChange = (key, value) => { - dispatch( - updateCollectionAuth({ - mode: 'oauth2', - collectionUid: collection.uid, - content: { - grantType: 'password', - accessTokenUrl, - username, - password, - clientId, - clientSecret, - scope, - [key]: value - } - }) - ); - }; - - return ( - - {inputsConfig.map((input) => { - const { key, label, isSecret } = input; - return ( -
- -
- handleChange(key, val)} - onRun={handleRun} - collection={collection} - isSecret={isSecret} - /> -
-
- ); - })} - -
- ); -}; - -export default OAuth2AuthorizationCode; diff --git a/packages/bruno-app/src/components/CollectionSettings/Auth/OAuth2/PasswordCredentials/inputsConfig.js b/packages/bruno-app/src/components/CollectionSettings/Auth/OAuth2/PasswordCredentials/inputsConfig.js deleted file mode 100644 index ec9efb1a8a..0000000000 --- a/packages/bruno-app/src/components/CollectionSettings/Auth/OAuth2/PasswordCredentials/inputsConfig.js +++ /dev/null @@ -1,29 +0,0 @@ -const inputsConfig = [ - { - key: 'accessTokenUrl', - label: 'Access Token URL' - }, - { - key: 'username', - label: 'Username' - }, - { - key: 'password', - label: 'Password' - }, - { - key: 'clientId', - label: 'Client ID' - }, - { - key: 'clientSecret', - label: 'Client Secret', - isSecret: true - }, - { - key: 'scope', - label: 'Scope' - } -]; - -export { inputsConfig }; diff --git a/packages/bruno-app/src/components/CollectionSettings/Auth/OAuth2/index.js b/packages/bruno-app/src/components/CollectionSettings/Auth/OAuth2/index.js index 1aa674ab95..e29fe7fc0c 100644 --- a/packages/bruno-app/src/components/CollectionSettings/Auth/OAuth2/index.js +++ b/packages/bruno-app/src/components/CollectionSettings/Auth/OAuth2/index.js @@ -1,21 +1,33 @@ import React from 'react'; import get from 'lodash/get'; import StyledWrapper from './StyledWrapper'; -import GrantTypeSelector from './GrantTypeSelector/index'; -import OAuth2PasswordCredentials from './PasswordCredentials/index'; -import OAuth2AuthorizationCode from './AuthorizationCode/index'; -import OAuth2ClientCredentials from './ClientCredentials/index'; +import { saveCollectionRoot } from 'providers/ReduxStore/slices/collections/actions'; +import OAuth2AuthorizationCode from 'components/RequestPane/Auth/OAuth2/AuthorizationCode/index'; +import { updateCollectionAuth } from 'providers/ReduxStore/slices/collections/index'; +import { useDispatch } from 'react-redux'; +import OAuth2PasswordCredentials from 'components/RequestPane/Auth/OAuth2/PasswordCredentials/index'; +import OAuth2ClientCredentials from 'components/RequestPane/Auth/OAuth2/ClientCredentials/index'; +import GrantTypeSelector from 'components/RequestPane/Auth/OAuth2/GrantTypeSelector/index'; + +const grantTypeComponentMap = (collection) => { + const dispatch = useDispatch(); + + const save = () => { + dispatch(saveCollectionRoot(collection.uid)); + }; + + let request = collection.draft ? get(collection, 'draft.request', {}) : get(collection, 'root.request', {}); + const grantType = get(request, 'auth.oauth2.grantType', {}); -const grantTypeComponentMap = (grantType, collection) => { switch (grantType) { case 'password': - return ; + return ; break; case 'authorization_code': - return ; + return ; break; case 'client_credentials': - return ; + return ; break; default: return
TBD
; @@ -24,12 +36,12 @@ const grantTypeComponentMap = (grantType, collection) => { }; const OAuth2 = ({ collection }) => { - const oAuth = get(collection, 'root.request.auth.oauth2', {}); + let request = collection.draft ? get(collection, 'draft.request', {}) : get(collection, 'root.request', {}); return ( - - {grantTypeComponentMap(oAuth?.grantType, collection)} + + {grantTypeComponentMap(collection)} ); }; diff --git a/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/AuthorizationCode/StyledWrapper.js b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/AuthorizationCode/StyledWrapper.js index 856f35b9b9..b06deaedf5 100644 --- a/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/AuthorizationCode/StyledWrapper.js +++ b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/AuthorizationCode/StyledWrapper.js @@ -11,6 +11,47 @@ const Wrapper = styled.div` border: solid 1px ${(props) => props.theme.input.border}; background-color: ${(props) => props.theme.input.bg}; } + + .token-placement-selector { + padding: 0.5rem 0px; + border-radius: 3px; + border: solid 1px ${(props) => props.theme.input.border}; + background-color: ${(props) => props.theme.input.bg}; + min-width: 100px; + + .dropdown { + width: fit-content; + min-width: 100px; + + div[data-tippy-root] { + width: fit-content; + min-width: 100px; + } + .tippy-box { + width: fit-content; + max-width: none !important; + min-width: 100px; + + .tippy-content: { + width: fit-content; + max-width: none !important; + min-width: 100px; + } + } + } + + .token-placement-label { + width: fit-content; + // color: ${(props) => props.theme.colors.text.yellow}; + justify-content: space-between; + padding: 0 0.5rem; + min-width: 100px; + } + + .dropdown-item { + padding: 0.2rem 0.6rem !important; + } + } `; export default Wrapper; diff --git a/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/AuthorizationCode/index.js b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/AuthorizationCode/index.js index 2bb5dcc355..3ffad90671 100644 --- a/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/AuthorizationCode/index.js +++ b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/AuthorizationCode/index.js @@ -1,28 +1,66 @@ -import React from 'react'; +import React, { useRef, forwardRef, useState } from 'react'; import get from 'lodash/get'; import { useTheme } from 'providers/Theme'; import { useDispatch } from 'react-redux'; +import { IconCaretDown, IconLoader2, IconSettings, IconKey } from '@tabler/icons'; +import Dropdown from 'components/Dropdown'; import SingleLineEditor from 'components/SingleLineEditor'; -import { updateAuth } from 'providers/ReduxStore/slices/collections'; -import { saveRequest, sendRequest } from 'providers/ReduxStore/slices/collections/actions'; +import { clearOauth2Cache, fetchOauth2Credentials } from 'providers/ReduxStore/slices/collections/actions'; import StyledWrapper from './StyledWrapper'; import { inputsConfig } from './inputsConfig'; -import { clearOauth2Cache } from 'utils/network/index'; import toast from 'react-hot-toast'; +import Oauth2TokenViewer from '../Oauth2TokenViewer/index'; +import { cloneDeep } from 'lodash'; +import { interpolateStringUsingCollectionAndItem } from 'utils/collections/index'; -const OAuth2AuthorizationCode = ({ item, collection }) => { +const OAuth2AuthorizationCode = ({ save, item = {}, request, handleRun, updateAuth, collection }) => { const dispatch = useDispatch(); const { storedTheme } = useTheme(); + const dropdownTippyRef = useRef(); + const onDropdownCreate = (ref) => (dropdownTippyRef.current = ref); + const [fetchingToken, toggleFetchingToken] = useState(false); - const oAuth = item.draft ? get(item, 'draft.request.auth.oauth2', {}) : get(item, 'request.auth.oauth2', {}); + const oAuth = get(request, 'auth.oauth2', {}); + + const { callbackUrl, authorizationUrl, accessTokenUrl, clientId, clientSecret, scope, credentialsPlacement, state, pkce, credentialsId, tokenPlacement, tokenHeaderPrefix, tokenQueryKey, reuseToken } = oAuth; - const handleRun = async () => { - dispatch(sendRequest(item, collection.uid)); - }; + const TokenPlacementIcon = forwardRef((props, ref) => { + return ( +
+ {tokenPlacement == 'url' ? 'URL' : 'Headers'} + +
+ ); + }); + + const CredentialsPlacementIcon = forwardRef((props, ref) => { + return ( +
+ {credentialsPlacement == 'body' ? 'Request Body' : 'Basic Auth Header'} + +
+ ); + }); - const handleSave = () => dispatch(saveRequest(item.uid, collection.uid)); - const { callbackUrl, authorizationUrl, accessTokenUrl, clientId, clientSecret, scope, state, pkce } = oAuth; + const handleFetchOauth2Credentials = async () => { + let requestCopy = cloneDeep(request); + requestCopy.oauth2 = requestCopy?.auth.oauth2; + requestCopy.headers = {}; + toggleFetchingToken(true); + try { + await dispatch(fetchOauth2Credentials({ itemUid: item.uid, request: requestCopy, collection })); + toggleFetchingToken(false); + toast.success('token fetched successfully!'); + } + catch(error) { + console.error(error); + toggleFetchingToken(false); + toast.error('An error occured while fetching token!'); + } + } + + const handleSave = () => {save();}; const handleChange = (key, value) => { dispatch( @@ -40,6 +78,12 @@ const OAuth2AuthorizationCode = ({ item, collection }) => { state, scope, pkce, + credentialsPlacement, + credentialsId, + tokenPlacement, + tokenHeaderPrefix, + tokenQueryKey, + reuseToken, [key]: value } }) @@ -61,6 +105,12 @@ const OAuth2AuthorizationCode = ({ item, collection }) => { clientSecret, state, scope, + credentialsPlacement, + credentialsId, + tokenPlacement, + tokenHeaderPrefix, + tokenQueryKey, + reuseToken, pkce: !Boolean(oAuth?.['pkce']) } }) @@ -68,7 +118,8 @@ const OAuth2AuthorizationCode = ({ item, collection }) => { }; const handleClearCache = (e) => { - clearOauth2Cache(collection?.uid) + const interpolatedAccessTokenUrl = interpolateStringUsingCollectionAndItem({ collection, item, string: accessTokenUrl }); + dispatch(clearOauth2Cache({ collectionUid: collection?.uid, url: interpolatedAccessTokenUrl, credentialsId })) .then(() => { toast.success('cleared cache successfully'); }) @@ -79,12 +130,21 @@ const OAuth2AuthorizationCode = ({ item, collection }) => { return ( + +
+
+ +
+ + Configuration + +
{inputsConfig.map((input) => { const { key, label, isSecret } = input; return ( -
- -
+
+ +
{
); })} +
+ +
+ } placement="bottom-end"> +
{ + dropdownTippyRef.current.hide(); + handleChange('credentialsPlacement', 'body'); + }} + > + Request Body +
+
{ + dropdownTippyRef.current.hide(); + handleChange('credentialsPlacement', 'basic_auth_header'); + }} + > + Basic Auth Header +
+
+
+
- + { onChange={handlePKCEToggle} />
-
- +
+ +
+ } placement="bottom-end"> +
{ + dropdownTippyRef.current.hide(); + handleChange('credentialsPlacement', 'body'); + }} + > + Request Body +
+
{ + dropdownTippyRef.current.hide(); + handleChange('credentialsPlacement', 'basic_auth_header'); + }} + > + Basic Auth Header +
+
+
+
+
+
+ +
+ + Token + +
+
+ +
+ handleChange('credentialsId', val)} + onRun={handleRun} + collection={collection} + item={item} + /> +
+
+
+ +
+ } placement="bottom-end"> +
{ + dropdownTippyRef.current.hide(); + handleChange('tokenPlacement', 'header'); + }} + > + Header +
+
{ + dropdownTippyRef.current.hide(); + handleChange('tokenPlacement', 'url'); + }} + > + URL +
+
+
+
+ { + tokenPlacement === 'header' ? +
+ +
+ handleChange('tokenHeaderPrefix', val)} + onRun={handleRun} + collection={collection} + /> +
+
+ : +
+ +
+ handleChange('tokenQueryKey', val)} + onRun={handleRun} + collection={collection} + /> +
+
+ } +
+ + +
); }; diff --git a/packages/bruno-app/src/components/CollectionSettings/Auth/OAuth2/AuthorizationCode/StyledWrapper.js b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/CredentialsPreview/StyledWrapper.js similarity index 76% rename from packages/bruno-app/src/components/CollectionSettings/Auth/OAuth2/AuthorizationCode/StyledWrapper.js rename to packages/bruno-app/src/components/RequestPane/Auth/OAuth2/CredentialsPreview/StyledWrapper.js index 856f35b9b9..a1f84cfe6c 100644 --- a/packages/bruno-app/src/components/CollectionSettings/Auth/OAuth2/AuthorizationCode/StyledWrapper.js +++ b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/CredentialsPreview/StyledWrapper.js @@ -2,12 +2,13 @@ import styled from 'styled-components'; const Wrapper = styled.div` label { + display: block; font-size: 0.8125rem; } - .single-line-editor-wrapper { + + textarea { + height: fit-content; max-width: 400px; - padding: 0.15rem 0.4rem; - border-radius: 3px; border: solid 1px ${(props) => props.theme.input.border}; background-color: ${(props) => props.theme.input.bg}; } diff --git a/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/CredentialsPreview/index.js b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/CredentialsPreview/index.js new file mode 100644 index 0000000000..7734affd4a --- /dev/null +++ b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/CredentialsPreview/index.js @@ -0,0 +1,80 @@ +import React, { useEffect, useState } from 'react'; +import { readOauth2CachedCredentials } from 'utils/network'; +import { sendCollectionOauth2Request, sendRequest, clearOauth2Cache } from 'providers/ReduxStore/slices/collections/actions'; +import toast from 'react-hot-toast'; +import { useDispatch } from 'react-redux'; +import StyledWrapper from './StyledWrapper'; + +const CredentialsPreview = ({ item, collection }) => { + const oauth2CredentialsAreaRef = React.createRef(); + const [oauth2Credentials, setOauth2Credentials] = useState({}); + + const dispatch = useDispatch(); + useEffect(() => { + oauth2CredentialsAreaRef.current.value = oauth2Credentials; + readOauth2CachedCredentials(collection.uid).then((credentials) => setOauth2Credentials(credentials)); + }, [oauth2CredentialsAreaRef]); + + const handleRun = async () => { + if (item) { + dispatch(sendRequest(item, collection.uid)); + } else { + dispatch(sendCollectionOauth2Request(collection.uid)); + } + }; + + const handleClearCache = (e) => { + dispatch(clearOauth2Cache({ collectionUid: collection?.uid, url: '' })) + .then(() => { + readOauth2CachedCredentials(collection.uid).then((credentials) => { + setOauth2Credentials(credentials); + toast.success('Cleared cache successfully'); + }); + }) + .catch((err) => { + toast.error(err.message); + }); + }; + + const sortedFields = () => { + const tokens = {}; + const extras = {}; + Object.entries(oauth2Credentials).forEach(([key, value]) => { + if (key.endsWith('_token')) { + tokens[key] = value; + } else { + extras[key] = value; + } + }); + return { ...tokens, ...extras }; + }; + + return ( + +
+ {Object.entries(oauth2Credentials).length > 0 ? ( + <> + +
+ Cached OAuth2 Credentials + {Object.entries(sortedFields()).map(([field, value]) => ( +
+ +