Custom swagger endpoint for docs (#3869)
* custom swagger endpoint metadata graphql remove /rest from endpoint * fixed pseudo scheme creation * move graphql playground creation to own file, added navbar to change baseurl and token * add schema switcher, fix changing url not applied, add invalid overlay * fix link color * removed path on Graphql Playground, naming fixes subdoc * - fixed overflow issue Rest docs * history replace & goBack * Small fix GraphQL playground broken --------- Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
This commit is contained in:
@ -1,5 +1,6 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { TbLoader2 } from 'react-icons/tb';
|
||||
import { useHistory, useLocation } from '@docusaurus/router';
|
||||
import { TbApi, TbChevronLeft, TbLink } from '@theme/icons';
|
||||
import { parseJson } from 'nx/src/utils/json';
|
||||
|
||||
import tokenForm from '!css-loader!./token-form.css';
|
||||
@ -7,21 +8,38 @@ import tokenForm from '!css-loader!./token-form.css';
|
||||
export type TokenFormProps = {
|
||||
setOpenApiJson?: (json: object) => void;
|
||||
setToken?: (token: string) => void;
|
||||
setBaseUrl?: (baseUrl: string) => void;
|
||||
isTokenValid: boolean;
|
||||
setIsTokenValid: (boolean) => void;
|
||||
setLoadingState: (boolean) => void;
|
||||
subDoc?: string;
|
||||
};
|
||||
|
||||
const TokenForm = ({
|
||||
setOpenApiJson,
|
||||
setToken,
|
||||
setBaseUrl: submitBaseUrl,
|
||||
isTokenValid,
|
||||
setIsTokenValid,
|
||||
subDoc,
|
||||
setLoadingState,
|
||||
}: TokenFormProps) => {
|
||||
const history = useHistory();
|
||||
const location = useLocation();
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [baseUrl, setBaseUrl] = useState(
|
||||
parseJson(localStorage.getItem('baseUrl'))?.baseUrl ??
|
||||
'https://api.twenty.com',
|
||||
);
|
||||
const token =
|
||||
parseJson(localStorage.getItem('TryIt_securitySchemeValues'))?.bearerAuth ??
|
||||
'';
|
||||
|
||||
const updateLoading = (loading: boolean) => {
|
||||
setIsLoading(loading);
|
||||
setLoadingState(loading);
|
||||
};
|
||||
|
||||
const updateToken = async (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
localStorage.setItem(
|
||||
'TryIt_securitySchemeValues',
|
||||
@ -30,22 +48,33 @@ const TokenForm = ({
|
||||
await submitToken(event.target.value);
|
||||
};
|
||||
|
||||
const validateToken = (openApiJson) => setIsTokenValid(!!openApiJson.tags);
|
||||
const updateBaseUrl = (baseUrl) => {
|
||||
setBaseUrl(baseUrl);
|
||||
submitBaseUrl?.(baseUrl);
|
||||
localStorage.setItem('baseUrl', JSON.stringify({ baseUrl: baseUrl }));
|
||||
};
|
||||
|
||||
const validateToken = (openApiJson) => {
|
||||
setIsTokenValid(!!openApiJson.tags);
|
||||
};
|
||||
|
||||
const getJson = async (token: string) => {
|
||||
setIsLoading(true);
|
||||
updateLoading(true);
|
||||
|
||||
return await fetch('https://api.twenty.com/open-api', {
|
||||
return await fetch(baseUrl + '/open-api/' + (subDoc ?? 'core'), {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then((result) => {
|
||||
validateToken(result);
|
||||
setIsLoading(false);
|
||||
updateLoading(false);
|
||||
|
||||
return result;
|
||||
})
|
||||
.catch(() => setIsLoading(false));
|
||||
.catch(() => {
|
||||
updateLoading(false);
|
||||
setIsTokenValid(false);
|
||||
});
|
||||
};
|
||||
|
||||
const submitToken = async (token) => {
|
||||
@ -60,6 +89,7 @@ const TokenForm = ({
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
updateBaseUrl(baseUrl);
|
||||
await submitToken(token);
|
||||
})();
|
||||
}, []);
|
||||
@ -74,46 +104,61 @@ const TokenForm = ({
|
||||
}, []);
|
||||
|
||||
return (
|
||||
!isTokenValid && (
|
||||
<div>
|
||||
<div className="container">
|
||||
<form className="form">
|
||||
<label>
|
||||
To load your playground schema,{' '}
|
||||
<a
|
||||
className="link"
|
||||
href="https://app.twenty.com/settings/developers"
|
||||
>
|
||||
generate an API key
|
||||
</a>{' '}
|
||||
and paste it here:
|
||||
</label>
|
||||
<p>
|
||||
<input
|
||||
className={token && !isLoading ? 'input invalid' : 'input'}
|
||||
type="text"
|
||||
readOnly={isLoading}
|
||||
placeholder="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIyMD..."
|
||||
defaultValue={token}
|
||||
onChange={updateToken}
|
||||
/>
|
||||
<span
|
||||
className={`token-invalid ${
|
||||
(!token || isLoading) && 'not-visible'
|
||||
}`}
|
||||
>
|
||||
Token invalid
|
||||
</span>
|
||||
<div className="loader-container">
|
||||
<TbLoader2
|
||||
className={`loader ${!isLoading && 'not-visible'}`}
|
||||
/>
|
||||
</div>
|
||||
</p>
|
||||
</form>
|
||||
<div className="form-container">
|
||||
<form className="form">
|
||||
<div className="backButton" onClick={() => history.goBack()}>
|
||||
<TbChevronLeft size={18} />
|
||||
<span>Back</span>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
<div className="inputWrapper">
|
||||
<div className="inputIcon" title="Api Key">
|
||||
<TbApi size={20} />
|
||||
</div>
|
||||
<input
|
||||
className={!isTokenValid && !isLoading ? 'input invalid' : 'input'}
|
||||
type="text"
|
||||
readOnly={isLoading}
|
||||
placeholder="API Key"
|
||||
defaultValue={token}
|
||||
onChange={updateToken}
|
||||
/>
|
||||
</div>
|
||||
<div className="inputWrapper">
|
||||
<div className="inputIcon" title="Base URL">
|
||||
<TbLink size={20} />
|
||||
</div>
|
||||
<input
|
||||
className={'input'}
|
||||
type="text"
|
||||
readOnly={isLoading}
|
||||
placeholder="Base URL"
|
||||
defaultValue={baseUrl}
|
||||
onChange={(event) => updateBaseUrl(event.target.value)}
|
||||
onBlur={() => submitToken(token)}
|
||||
/>
|
||||
</div>
|
||||
{!location.pathname.includes('rest-api') && (
|
||||
<div className="inputWrapper" style={{ maxWidth: '100px' }}>
|
||||
<select
|
||||
className="select"
|
||||
onChange={(event) =>
|
||||
history.replace(
|
||||
'/' +
|
||||
location.pathname.split('/').at(-2) +
|
||||
'/' +
|
||||
event.target.value,
|
||||
)
|
||||
}
|
||||
value={location.pathname.split('/').at(-1)}
|
||||
>
|
||||
<option value="core">Core</option>
|
||||
<option value="metadata">Metadata</option>
|
||||
</select>
|
||||
</div>
|
||||
)}
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user