Client:PortalSettings:OAuth: add generate and revoke developer token dialogs
This commit is contained in:
parent
b3dd681065
commit
b89bea7123
@ -18,6 +18,9 @@ export interface OAuthProps {
|
||||
previewDialogVisible?: boolean;
|
||||
disableDialogVisible?: boolean;
|
||||
deleteDialogVisible?: boolean;
|
||||
generateDeveloperTokenDialogVisible?: boolean;
|
||||
revokeDeveloperTokenDialogVisible?: boolean;
|
||||
|
||||
isInit: boolean;
|
||||
setIsInit: (value: boolean) => void;
|
||||
}
|
||||
|
@ -18,6 +18,8 @@ import DisableDialog from "./sub-components/DisableDialog";
|
||||
import DeleteDialog from "./sub-components/DeleteDialog";
|
||||
import OAuthEmptyScreen from "./sub-components/EmptyScreen";
|
||||
import List from "./sub-components/List";
|
||||
import GenerateDeveloperTokenDialog from "./sub-components/GenerateDeveloperTokenDialog";
|
||||
import RevokeDeveloperTokenDialog from "./sub-components/RevokeDeveloperTokenDialog";
|
||||
|
||||
const MIN_LOADER_TIME = 500;
|
||||
|
||||
@ -35,6 +37,8 @@ const OAuth = ({
|
||||
setIsInit,
|
||||
disableDialogVisible,
|
||||
deleteDialogVisible,
|
||||
generateDeveloperTokenDialogVisible,
|
||||
revokeDeveloperTokenDialogVisible,
|
||||
}: OAuthProps) => {
|
||||
const { t } = useTranslation(["OAuth"]);
|
||||
|
||||
@ -102,6 +106,8 @@ const OAuth = ({
|
||||
{disableDialogVisible && <DisableDialog />}
|
||||
{previewDialogVisible && <PreviewDialog visible={previewDialogVisible} />}
|
||||
{deleteDialogVisible && <DeleteDialog />}
|
||||
{generateDeveloperTokenDialogVisible && <GenerateDeveloperTokenDialog />}
|
||||
{revokeDeveloperTokenDialogVisible && <RevokeDeveloperTokenDialog />}
|
||||
</OAuthContainer>
|
||||
);
|
||||
};
|
||||
@ -128,6 +134,8 @@ export default inject(
|
||||
setIsInit,
|
||||
disableDialogVisible,
|
||||
deleteDialogVisible,
|
||||
generateDeveloperTokenDialogVisible,
|
||||
revokeDeveloperTokenDialogVisible,
|
||||
} = oauthStore;
|
||||
return {
|
||||
viewAs,
|
||||
@ -143,6 +151,8 @@ export default inject(
|
||||
setIsInit,
|
||||
disableDialogVisible,
|
||||
deleteDialogVisible,
|
||||
generateDeveloperTokenDialogVisible,
|
||||
revokeDeveloperTokenDialogVisible,
|
||||
};
|
||||
},
|
||||
)(observer(OAuth));
|
||||
|
@ -1,26 +0,0 @@
|
||||
import React from "react";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import styled from "styled-components";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { OAuthStoreProps } from "SRC_DIR/store/OAuthStore";
|
||||
|
||||
const GenerateDeveloperTokenDialog = () => {
|
||||
return <div></div>;
|
||||
};
|
||||
|
||||
export default inject(({ oauthStore }: { oauthStore: OAuthStoreProps }) => {
|
||||
const {
|
||||
setInfoDialogVisible,
|
||||
bufferSelection,
|
||||
scopeList,
|
||||
getContextMenuItems,
|
||||
} = oauthStore;
|
||||
|
||||
return {
|
||||
setInfoDialogVisible,
|
||||
client: bufferSelection,
|
||||
scopeList,
|
||||
getContextMenuItems,
|
||||
};
|
||||
})(observer(GenerateDeveloperTokenDialog));
|
@ -0,0 +1,210 @@
|
||||
import React from "react";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import styled, { useTheme } from "styled-components";
|
||||
import { i18n } from "i18next";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import copy from "copy-to-clipboard";
|
||||
import moment from "moment-timezone";
|
||||
|
||||
import api from "@docspace/shared/api";
|
||||
import { IClientProps } from "@docspace/shared/utils/oauth/types";
|
||||
import {
|
||||
ModalDialog,
|
||||
ModalDialogType,
|
||||
} from "@docspace/shared/components/modal-dialog";
|
||||
import { Button, ButtonSize } from "@docspace/shared/components/button";
|
||||
import { Text } from "@docspace/shared/components/text";
|
||||
import { toastr } from "@docspace/shared/components/toast";
|
||||
import { TData } from "@docspace/shared/components/toast/Toast.type";
|
||||
import { InputBlock } from "@docspace/shared/components/input-block";
|
||||
import { InputSize, InputType } from "@docspace/shared/components/text-input";
|
||||
|
||||
import CopyReactSvgUrl from "PUBLIC_DIR/images/copy.react.svg?url";
|
||||
|
||||
import { OAuthStoreProps } from "SRC_DIR/store/OAuthStore";
|
||||
import { UserStore } from "@docspace/shared/store/UserStore";
|
||||
import { globalColors } from "@docspace/shared/themes";
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
p {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.dates {
|
||||
margin-top: 16px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
`;
|
||||
|
||||
type GenerateDeveloperTokenDialogProps = {
|
||||
client?: IClientProps;
|
||||
|
||||
email?: string;
|
||||
|
||||
setGenerateDeveloperTokenDialogVisible?: (value: boolean) => void;
|
||||
};
|
||||
|
||||
const getDate = (date: Date, i18nArg: i18n) => {
|
||||
return moment(date)
|
||||
.locale(i18nArg.language)
|
||||
.tz(window.timezone)
|
||||
.format("MMM D, YYYY, h:mm:ss A");
|
||||
};
|
||||
|
||||
const GenerateDeveloperTokenDialog = ({
|
||||
client,
|
||||
email,
|
||||
|
||||
setGenerateDeveloperTokenDialogVisible,
|
||||
}: GenerateDeveloperTokenDialogProps) => {
|
||||
const { i18n: i18nParam } = useTranslation(["OAuth", "Common"]);
|
||||
|
||||
const theme = useTheme();
|
||||
const [token, setToken] = React.useState("");
|
||||
const [dates, setDates] = React.useState({
|
||||
created: getDate(new Date(), i18nParam),
|
||||
expires: getDate(new Date(), i18nParam),
|
||||
});
|
||||
const [requestRunning, setRequestRunning] = React.useState(false);
|
||||
|
||||
const onGenerate = async () => {
|
||||
if (token || !client || requestRunning) return;
|
||||
|
||||
try {
|
||||
const { clientId, clientSecret, scopes } = client;
|
||||
|
||||
setRequestRunning(true);
|
||||
|
||||
const data = await api.oauth.generateDevelopToken(
|
||||
clientId,
|
||||
clientSecret,
|
||||
scopes,
|
||||
);
|
||||
|
||||
setRequestRunning(false);
|
||||
|
||||
if (!data) return;
|
||||
|
||||
const { access_token: accessToken, expires_in: expiresIn } = data;
|
||||
|
||||
const created = new Date();
|
||||
// convert sec to ms
|
||||
const expires = new Date(created.getTime() + expiresIn * 1000);
|
||||
|
||||
if (accessToken) {
|
||||
setToken(accessToken);
|
||||
setDates({
|
||||
created: getDate(created, i18nParam),
|
||||
expires: getDate(expires, i18nParam),
|
||||
});
|
||||
toastr.success("Copied");
|
||||
}
|
||||
} catch (e) {
|
||||
toastr.error(e as TData);
|
||||
}
|
||||
};
|
||||
|
||||
const onCopyClick = async () => {
|
||||
copy(token);
|
||||
toastr.success("Copied");
|
||||
};
|
||||
|
||||
const onClose = () => {
|
||||
if (requestRunning) return;
|
||||
|
||||
setGenerateDeveloperTokenDialogVisible?.(false);
|
||||
};
|
||||
return (
|
||||
<ModalDialog
|
||||
visible
|
||||
onClose={onClose}
|
||||
displayType={ModalDialogType.modal}
|
||||
autoMaxHeight
|
||||
scale
|
||||
>
|
||||
<ModalDialog.Header>Generate developer token</ModalDialog.Header>
|
||||
<ModalDialog.Body>
|
||||
<StyledContainer>
|
||||
<Text>
|
||||
By generating an developer access token, you will be able to make
|
||||
API calls for your own account without going through the
|
||||
authorization flow. To obtain access tokens for other users, use the
|
||||
standard OAuth flow.
|
||||
</Text>
|
||||
<Text>
|
||||
For scoped apps, the token will have the same scope as the app.
|
||||
</Text>
|
||||
{token ? (
|
||||
<>
|
||||
<Text
|
||||
color={
|
||||
theme.isBase
|
||||
? globalColors.lightErrorStatus
|
||||
: globalColors.darkErrorStatus
|
||||
}
|
||||
>
|
||||
This access token can be used to access your account ({email})
|
||||
via the API. Don`t share your access token with anyone.
|
||||
</Text>
|
||||
<InputBlock
|
||||
value={token}
|
||||
scale
|
||||
isReadOnly
|
||||
isDisabled
|
||||
size={InputSize.base}
|
||||
iconName={CopyReactSvgUrl}
|
||||
onIconClick={onCopyClick}
|
||||
type={InputType.text}
|
||||
/>
|
||||
<Text className="dates">
|
||||
Created: {dates.created}
|
||||
<br />
|
||||
Expires: {dates.expires}{" "}
|
||||
</Text>
|
||||
</>
|
||||
) : null}
|
||||
</StyledContainer>
|
||||
</ModalDialog.Body>
|
||||
<ModalDialog.Footer>
|
||||
<Button
|
||||
label="Generate developer token"
|
||||
primary
|
||||
scale
|
||||
onClick={onGenerate}
|
||||
isDisabled={!!token}
|
||||
isLoading={requestRunning}
|
||||
size={ButtonSize.small}
|
||||
/>
|
||||
<Button
|
||||
label="Cancel"
|
||||
scale
|
||||
onClick={onClose}
|
||||
size={ButtonSize.small}
|
||||
isDisabled={requestRunning}
|
||||
/>
|
||||
</ModalDialog.Footer>
|
||||
</ModalDialog>
|
||||
);
|
||||
};
|
||||
|
||||
export default inject(
|
||||
({
|
||||
oauthStore,
|
||||
userStore,
|
||||
}: {
|
||||
oauthStore: OAuthStoreProps;
|
||||
userStore: UserStore;
|
||||
}) => {
|
||||
const { setGenerateDeveloperTokenDialogVisible, bufferSelection } =
|
||||
oauthStore;
|
||||
|
||||
const { user } = userStore;
|
||||
|
||||
return {
|
||||
setGenerateDeveloperTokenDialogVisible,
|
||||
client: bufferSelection,
|
||||
|
||||
email: user?.email,
|
||||
};
|
||||
},
|
||||
)(observer(GenerateDeveloperTokenDialog));
|
@ -0,0 +1,141 @@
|
||||
import React from "react";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import styled from "styled-components";
|
||||
|
||||
import api from "@docspace/shared/api";
|
||||
import { IClientProps } from "@docspace/shared/utils/oauth/types";
|
||||
import {
|
||||
ModalDialog,
|
||||
ModalDialogType,
|
||||
} from "@docspace/shared/components/modal-dialog";
|
||||
import { Button, ButtonSize } from "@docspace/shared/components/button";
|
||||
import { Text } from "@docspace/shared/components/text";
|
||||
import { toastr } from "@docspace/shared/components/toast";
|
||||
import { TData } from "@docspace/shared/components/toast/Toast.type";
|
||||
import { InputBlock } from "@docspace/shared/components/input-block";
|
||||
import { InputSize, InputType } from "@docspace/shared/components/text-input";
|
||||
|
||||
import { OAuthStoreProps } from "SRC_DIR/store/OAuthStore";
|
||||
import { UserStore } from "@docspace/shared/store/UserStore";
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
p {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
`;
|
||||
|
||||
type GenerateDeveloperTokenDialogProps = {
|
||||
client?: IClientProps;
|
||||
|
||||
setRevokeDeveloperTokenDialogVisible?: (value: boolean) => void;
|
||||
};
|
||||
|
||||
const GenerateDeveloperTokenDialog = ({
|
||||
client,
|
||||
|
||||
setRevokeDeveloperTokenDialogVisible,
|
||||
}: GenerateDeveloperTokenDialogProps) => {
|
||||
// const {} = useTranslation(["OAuth", "Common"]);
|
||||
|
||||
const [token, setToken] = React.useState("");
|
||||
|
||||
const [requestRunning, setRequestRunning] = React.useState(false);
|
||||
|
||||
const onRevoke = async () => {
|
||||
if (!token || !client || requestRunning) return;
|
||||
|
||||
try {
|
||||
const { clientId, clientSecret } = client;
|
||||
|
||||
setRequestRunning(true);
|
||||
|
||||
await api.oauth.revokeDeveloperToken(token, clientId, clientSecret);
|
||||
|
||||
setRequestRunning(false);
|
||||
|
||||
setToken("");
|
||||
setRevokeDeveloperTokenDialogVisible?.(false);
|
||||
|
||||
toastr.success("Revoked");
|
||||
} catch (e) {
|
||||
toastr.error(e as TData);
|
||||
}
|
||||
};
|
||||
|
||||
const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const value = e.target.value;
|
||||
|
||||
setToken(value);
|
||||
};
|
||||
|
||||
const onClose = () => {
|
||||
if (requestRunning) return;
|
||||
|
||||
setRevokeDeveloperTokenDialogVisible?.(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<ModalDialog
|
||||
visible
|
||||
onClose={onClose}
|
||||
displayType={ModalDialogType.modal}
|
||||
autoMaxHeight
|
||||
scale
|
||||
>
|
||||
<ModalDialog.Header>Revoke developer token</ModalDialog.Header>
|
||||
<ModalDialog.Body>
|
||||
<StyledContainer>
|
||||
<Text>Warning text</Text>
|
||||
<InputBlock
|
||||
value={token}
|
||||
scale
|
||||
placeholder="Enter developer token"
|
||||
type={InputType.text}
|
||||
size={InputSize.base}
|
||||
onChange={onChange}
|
||||
/>
|
||||
</StyledContainer>
|
||||
</ModalDialog.Body>
|
||||
<ModalDialog.Footer>
|
||||
<Button
|
||||
label="Revoke"
|
||||
primary
|
||||
scale
|
||||
onClick={onRevoke}
|
||||
isDisabled={!token}
|
||||
isLoading={requestRunning}
|
||||
size={ButtonSize.small}
|
||||
/>
|
||||
<Button
|
||||
label="Cancel"
|
||||
scale
|
||||
onClick={onClose}
|
||||
size={ButtonSize.small}
|
||||
isDisabled={requestRunning}
|
||||
/>
|
||||
</ModalDialog.Footer>
|
||||
</ModalDialog>
|
||||
);
|
||||
};
|
||||
|
||||
export default inject(
|
||||
({
|
||||
oauthStore,
|
||||
userStore,
|
||||
}: {
|
||||
oauthStore: OAuthStoreProps;
|
||||
userStore: UserStore;
|
||||
}) => {
|
||||
const { setRevokeDeveloperTokenDialogVisible, bufferSelection } =
|
||||
oauthStore;
|
||||
|
||||
const { user } = userStore;
|
||||
|
||||
return {
|
||||
setRevokeDeveloperTokenDialogVisible,
|
||||
client: bufferSelection,
|
||||
|
||||
email: user?.email,
|
||||
};
|
||||
},
|
||||
)(observer(GenerateDeveloperTokenDialog));
|
@ -61,6 +61,9 @@ export interface OAuthStoreProps {
|
||||
generateDeveloperTokenDialogVisible: boolean;
|
||||
setGenerateDeveloperTokenDialogVisible: (value: boolean) => void;
|
||||
|
||||
revokeDeveloperTokenDialogVisible: boolean;
|
||||
setRevokeDeveloperTokenDialogVisible: (value: boolean) => void;
|
||||
|
||||
deleteDialogVisible: boolean;
|
||||
setDeleteDialogVisible: (value: boolean) => void;
|
||||
|
||||
@ -162,6 +165,8 @@ class OAuthStore implements OAuthStoreProps {
|
||||
|
||||
generateDeveloperTokenDialogVisible: boolean = false;
|
||||
|
||||
revokeDeveloperTokenDialogVisible: boolean = false;
|
||||
|
||||
selection: string[] = [];
|
||||
|
||||
bufferSelection: IClientProps | null = null;
|
||||
@ -225,6 +230,10 @@ class OAuthStore implements OAuthStoreProps {
|
||||
this.generateDeveloperTokenDialogVisible = value;
|
||||
};
|
||||
|
||||
setRevokeDeveloperTokenDialogVisible = (value: boolean) => {
|
||||
this.revokeDeveloperTokenDialogVisible = value;
|
||||
};
|
||||
|
||||
setClientSecret = (value: string) => {
|
||||
this.clientSecret = value;
|
||||
};
|
||||
@ -536,6 +545,7 @@ class OAuthStore implements OAuthStoreProps {
|
||||
this.setDisableDialogVisible(false);
|
||||
this.setDeleteDialogVisible(false);
|
||||
this.setGenerateDeveloperTokenDialogVisible(false);
|
||||
this.setRevokeDeveloperTokenDialogVisible(false);
|
||||
};
|
||||
|
||||
const onRevoke = () => {
|
||||
@ -546,6 +556,7 @@ class OAuthStore implements OAuthStoreProps {
|
||||
this.setDisableDialogVisible(false);
|
||||
this.setDeleteDialogVisible(false);
|
||||
this.setGenerateDeveloperTokenDialogVisible(false);
|
||||
this.setRevokeDeveloperTokenDialogVisible(false);
|
||||
};
|
||||
|
||||
const onDisable = () => {
|
||||
@ -556,9 +567,10 @@ class OAuthStore implements OAuthStoreProps {
|
||||
this.setDisableDialogVisible(true);
|
||||
this.setDeleteDialogVisible(false);
|
||||
this.setGenerateDeveloperTokenDialogVisible(false);
|
||||
this.setRevokeDeveloperTokenDialogVisible(false);
|
||||
};
|
||||
|
||||
const onGenerateDevelopToken = () => {
|
||||
const onGenerateDeveloperToken = () => {
|
||||
this.setBufferSelection(clientId);
|
||||
this.setPreviewDialogVisible(false);
|
||||
this.setInfoDialogVisible(false);
|
||||
@ -566,6 +578,18 @@ class OAuthStore implements OAuthStoreProps {
|
||||
this.setDisableDialogVisible(false);
|
||||
this.setDeleteDialogVisible(false);
|
||||
this.setGenerateDeveloperTokenDialogVisible(true);
|
||||
this.setRevokeDeveloperTokenDialogVisible(false);
|
||||
};
|
||||
|
||||
const onRevokeDeveloperToken = () => {
|
||||
this.setBufferSelection(clientId);
|
||||
this.setPreviewDialogVisible(false);
|
||||
this.setInfoDialogVisible(false);
|
||||
this.setRevokeDialogVisible(false);
|
||||
this.setDisableDialogVisible(false);
|
||||
this.setDeleteDialogVisible(false);
|
||||
this.setGenerateDeveloperTokenDialogVisible(false);
|
||||
this.setRevokeDeveloperTokenDialogVisible(true);
|
||||
};
|
||||
|
||||
const openOption = {
|
||||
@ -621,6 +645,7 @@ class OAuthStore implements OAuthStoreProps {
|
||||
this.setDisableDialogVisible(false);
|
||||
this.setDeleteDialogVisible(true);
|
||||
this.setGenerateDeveloperTokenDialogVisible(false);
|
||||
this.setRevokeDeveloperTokenDialogVisible(false);
|
||||
};
|
||||
|
||||
const onShowPreview = () => {
|
||||
@ -631,6 +656,7 @@ class OAuthStore implements OAuthStoreProps {
|
||||
this.setDisableDialogVisible(false);
|
||||
this.setDeleteDialogVisible(false);
|
||||
this.setGenerateDeveloperTokenDialogVisible(false);
|
||||
this.setRevokeDeveloperTokenDialogVisible(false);
|
||||
};
|
||||
|
||||
const onEnable = async (status: boolean) => {
|
||||
@ -640,6 +666,7 @@ class OAuthStore implements OAuthStoreProps {
|
||||
this.setDisableDialogVisible(false);
|
||||
this.setDeleteDialogVisible(false);
|
||||
this.setGenerateDeveloperTokenDialogVisible(false);
|
||||
this.setRevokeDeveloperTokenDialogVisible(false);
|
||||
|
||||
if (isGroupContext) {
|
||||
try {
|
||||
@ -698,15 +725,21 @@ class OAuthStore implements OAuthStoreProps {
|
||||
onClick: onDisable,
|
||||
};
|
||||
|
||||
const generateDevelopTokenOption = {
|
||||
const generateDeveloperTokenOption = {
|
||||
key: "generate-token",
|
||||
icon: EnableReactSvgUrl,
|
||||
label: "Generate developer token",
|
||||
onClick: onGenerateDevelopToken,
|
||||
onClick: onGenerateDeveloperToken,
|
||||
};
|
||||
|
||||
const revokeDeveloperTokenOption = {
|
||||
key: "revoke-token",
|
||||
icon: EnableReactSvgUrl,
|
||||
label: "Revoke developer token",
|
||||
onClick: onRevokeDeveloperToken,
|
||||
};
|
||||
|
||||
const contextOptions = [
|
||||
{ ...generateDevelopTokenOption },
|
||||
{
|
||||
key: "Separator dropdownItem",
|
||||
isSeparator: true,
|
||||
@ -741,6 +774,9 @@ class OAuthStore implements OAuthStoreProps {
|
||||
contextOptions.unshift(enableOption);
|
||||
}
|
||||
|
||||
contextOptions.unshift(revokeDeveloperTokenOption);
|
||||
contextOptions.unshift(generateDeveloperTokenOption);
|
||||
|
||||
if (!isInfo) contextOptions.unshift(infoOption);
|
||||
contextOptions.unshift(authButtonOption);
|
||||
contextOptions.unshift(editOption);
|
||||
|
Loading…
Reference in New Issue
Block a user