From 310f2d5dc590a4c8275bb8f9331af231eee17ea7 Mon Sep 17 00:00:00 2001 From: Timofey Boyko Date: Tue, 26 Sep 2023 10:31:22 +0300 Subject: [PATCH] Web:Client:PortalSettings: add OAuth edit and create page --- .../src/pages/PortalSettings/Layout/index.js | 10 +- .../OAuth/OAuthCreatePage/index.tsx | 7 + .../OAuth/OAuthDetails/index.js | 126 ----- .../OAuth/OAuthEditPage/index.tsx | 11 + .../SectionHeader.styled.ts | 63 +++ .../OAuthSectionHeader/SectionHeader.types.ts | 3 + .../OAuth/OAuthSectionHeader/index.tsx | 49 ++ .../OAuth/{StyledOAuth.js => StyledOAuth.ts} | 2 +- .../developer-tools/OAuth/index.tsx | 13 +- .../ClientForm/ClientForm.styled.ts | 96 ++++ .../ClientForm/ClientForm.types.ts | 50 ++ .../ClientForm/components/Block.tsx | 10 + .../ClientForm/components/BlockHeader.tsx | 30 ++ .../ClientForm/components/Checkbox.tsx | 46 ++ .../ClientForm/components/Input.tsx | 66 +++ .../ClientForm/components/InputHeader.tsx | 22 + .../OAuth/sub-components/ClientForm/index.tsx | 436 ++++++++++++++++++ .../categories/developer-tools/index.js | 3 +- .../PortalSettings/utils/settingsTree.js | 2 +- packages/client/src/routes/portalSettings.js | 7 +- packages/client/src/store/OAuthStore.ts | 4 + packages/common/utils/oauth/dto.ts | 6 +- 22 files changed, 927 insertions(+), 135 deletions(-) create mode 100644 packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/OAuthCreatePage/index.tsx delete mode 100644 packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/OAuthDetails/index.js create mode 100644 packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/OAuthEditPage/index.tsx create mode 100644 packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/OAuthSectionHeader/SectionHeader.styled.ts create mode 100644 packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/OAuthSectionHeader/SectionHeader.types.ts create mode 100644 packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/OAuthSectionHeader/index.tsx rename packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/{StyledOAuth.js => StyledOAuth.ts} (91%) create mode 100644 packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/ClientForm/ClientForm.styled.ts create mode 100644 packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/ClientForm/ClientForm.types.ts create mode 100644 packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/ClientForm/components/Block.tsx create mode 100644 packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/ClientForm/components/BlockHeader.tsx create mode 100644 packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/ClientForm/components/Checkbox.tsx create mode 100644 packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/ClientForm/components/Input.tsx create mode 100644 packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/ClientForm/components/InputHeader.tsx create mode 100644 packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/ClientForm/index.tsx diff --git a/packages/client/src/pages/PortalSettings/Layout/index.js b/packages/client/src/pages/PortalSettings/Layout/index.js index 149450bd1a..1b3cca306a 100644 --- a/packages/client/src/pages/PortalSettings/Layout/index.js +++ b/packages/client/src/pages/PortalSettings/Layout/index.js @@ -10,6 +10,7 @@ import withLoading from "SRC_DIR/HOCs/withLoading"; import { useParams } from "react-router-dom"; import HistoryHeader from "../categories/developer-tools/Webhooks/WebhookHistory/sub-components/HistoryHeader"; import DetailsNavigationHeader from "../categories/developer-tools/Webhooks/WebhookEventDetails/sub-components/DetailsNavigationHeader"; +import OAuthSectionHeader from "../categories/developer-tools/OAuth/OAuthSectionHeader"; const ArticleSettings = React.memo(() => { return ( @@ -41,6 +42,10 @@ const Layout = ({ const webhookHistoryPath = `/portal-settings/developer-tools/webhooks/${id}`; const webhookDetailsPath = `/portal-settings/developer-tools/webhooks/${id}/${eventId}`; + + const oauthCreatePath = "/portal-settings/developer-tools/oauth/create"; + const oauthEditPath = `/portal-settings/developer-tools/oauth/${id}`; + const currentPath = window.location.pathname; return ( @@ -49,7 +54,10 @@ const Layout = ({ {!isGeneralPage && (
- {currentPath === webhookHistoryPath ? ( + {currentPath === oauthCreatePath || + currentPath === oauthEditPath ? ( + + ) : currentPath === webhookHistoryPath ? ( ) : currentPath === webhookDetailsPath ? ( diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/OAuthCreatePage/index.tsx b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/OAuthCreatePage/index.tsx new file mode 100644 index 0000000000..3414110c71 --- /dev/null +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/OAuthCreatePage/index.tsx @@ -0,0 +1,7 @@ +import ClientForm from "../sub-components/ClientForm"; + +const OAuthCreatePage = () => { + return ; +}; + +export default OAuthCreatePage; diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/OAuthDetails/index.js b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/OAuthDetails/index.js deleted file mode 100644 index 2d2e04d67e..0000000000 --- a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/OAuthDetails/index.js +++ /dev/null @@ -1,126 +0,0 @@ -import React, { useState, useEffect } from "react"; -import { withTranslation } from "react-i18next"; -import TextInput from "@docspace/components/text-input"; -import Label from "@docspace/components/label"; -import { inject, observer } from "mobx-react"; -import StyledSettingsSeparator from "SRC_DIR/pages/PortalSettings/StyledSettingsSeparator"; -import Category from "../sub-components/Category"; -import { Container, Property } from "../StyledOAuth"; - -const OAuthDetails = (props) => { - const { t, setDocumentTitle, currentClient, theme } = props; - - setDocumentTitle("OAuth"); - - return ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ); -}; - -export default inject(({ setup, auth, oauthStore }) => { - const { settingsStore, setDocumentTitle } = auth; - const { theme } = settingsStore; - const { currentClient } = oauthStore; - - return { - theme, - setDocumentTitle, - currentClient, - }; -})(withTranslation(["Common"])(observer(OAuthDetails))); diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/OAuthEditPage/index.tsx b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/OAuthEditPage/index.tsx new file mode 100644 index 0000000000..7321b79434 --- /dev/null +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/OAuthEditPage/index.tsx @@ -0,0 +1,11 @@ +import { useParams } from "react-router-dom"; + +import ClientForm from "../sub-components/ClientForm"; + +const OAuthEditPage = () => { + const { id } = useParams(); + + return ; +}; + +export default OAuthEditPage; diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/OAuthSectionHeader/SectionHeader.styled.ts b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/OAuthSectionHeader/SectionHeader.styled.ts new file mode 100644 index 0000000000..43acb1c982 --- /dev/null +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/OAuthSectionHeader/SectionHeader.styled.ts @@ -0,0 +1,63 @@ +import styled, { css } from "styled-components"; +import { isMobile, isMobileOnly } from "react-device-detect"; + +import { Base } from "@docspace/components/themes"; +import { tablet } from "@docspace/components/utils/device"; + +const HeaderContainer = styled.div` + position: sticky; + top: 0; + background-color: ${(props) => props.theme.backgroundColor}; + z-index: 201; + display: flex; + align-items: center; + width: 100%; + min-height: 70px; + flex-wrap: wrap; + + ${() => + isMobile && + css` + margin-bottom: 11px; + `} + + ${() => + isMobileOnly && + css` + margin-top: 7px; + margin-left: -14px; + padding-left: 14px; + margin-right: -14px; + padding-right: 14px; + `} + + .arrow-button { + margin-inline-end: 18.5px; + + @media ${tablet} { + padding-block: 8px; + padding-inline: 8px 0; + margin-inline-start: -8px; + } + + ${() => + isMobileOnly && + css` + margin-inline-end: 13px; + `} + + svg { + ${({ theme }) => + theme.interfaceDirection === "rtl" && "transform: scaleX(-1);"} + } + } + + .headline { + font-size: 18px; + margin-inline-end: 16px; + } +`; + +HeaderContainer.defaultProps = { theme: Base }; + +export { HeaderContainer }; diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/OAuthSectionHeader/SectionHeader.types.ts b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/OAuthSectionHeader/SectionHeader.types.ts new file mode 100644 index 0000000000..8b47470674 --- /dev/null +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/OAuthSectionHeader/SectionHeader.types.ts @@ -0,0 +1,3 @@ +export interface OAuthSectionHeaderProps { + isEdit: boolean; +} diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/OAuthSectionHeader/index.tsx b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/OAuthSectionHeader/index.tsx new file mode 100644 index 0000000000..ceda731b0f --- /dev/null +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/OAuthSectionHeader/index.tsx @@ -0,0 +1,49 @@ +import React from "react"; +import { useNavigate } from "react-router-dom"; +import { inject, observer } from "mobx-react"; +import { useTranslation } from "react-i18next"; + +// @ts-ignore +import Headline from "@docspace/common/components/Headline"; +// @ts-ignore +import IconButton from "@docspace/components/icon-button"; + +import ArrowPathReactSvgUrl from "PUBLIC_DIR/images/arrow.path.react.svg?url"; + +import { HeaderContainer } from "./SectionHeader.styled"; +import { OAuthSectionHeaderProps } from "./SectionHeader.types"; + +const OAuthSectionHeader = ({ isEdit }: OAuthSectionHeaderProps) => { + const { t } = useTranslation(["OAuth"]); + + const navigate = useNavigate(); + + const onBack = () => { + navigate("/portal-settings/developer-tools/oauth"); + }; + + const NavigationHeader = () => ( + <> + + + {isEdit ? t("EditApp") : t("NewApp")} + + + ); + + return ( + + + + ); +}; + +export default inject(({}) => { + return {}; +})(observer(OAuthSectionHeader)); diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/StyledOAuth.js b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/StyledOAuth.ts similarity index 91% rename from packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/StyledOAuth.js rename to packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/StyledOAuth.ts index 0668400969..ba191dc238 100644 --- a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/StyledOAuth.js +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/StyledOAuth.ts @@ -1,6 +1,6 @@ import styled from "styled-components"; -export const Container = styled.div` +export const OAuthContainer = styled.div` width: 100%; margin-top: 5px; `; diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/index.tsx b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/index.tsx index fed19365f2..1e710f1dc6 100644 --- a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/index.tsx +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/index.tsx @@ -1,8 +1,19 @@ import React from "react"; import { inject, observer } from "mobx-react"; +import { useTranslation } from "react-i18next"; + +import OAuthEmptyScreen from "./sub-components/EmptyScreen"; + +import { OAuthContainer } from "./StyledOAuth"; const OAuth = ({}) => { - return
; + const { t } = useTranslation(["OAuth"]); + + return ( + + + + ); }; export default inject(({}) => { diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/ClientForm/ClientForm.styled.ts b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/ClientForm/ClientForm.styled.ts new file mode 100644 index 0000000000..eecfc858fa --- /dev/null +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/ClientForm/ClientForm.styled.ts @@ -0,0 +1,96 @@ +import styled from "styled-components"; + +const Container = styled.div` + max-width: 350px; + + display: flex; + flex-direction: column; + gap: 20px; + + .button-container { + width: 100; + display: flex; + + flex-direction: raw; + gap: 8px; + } +`; + +const BlockContainer = styled.div` + width: 100%; + height: auto; + + display: flex; + flex-direction: column; + gap: 12px; +`; + +const HeaderRaw = styled.div` + width: 100%; + + display: flex; + flex-direction: raw; + gap: 4px; + + align-items: center; + + div { + height: 12px; + } +`; + +const InputGroup = styled.div` + width: 100%; + height: auto; + + display: flex; + flex-direction: column; + gap: 4px; +`; + +const InputRaw = styled.div` + width: 100%; + + display: flex; + flex-direction: raw; + justify-content: space-between; + + gap: 8px; + + input { + user-select: none; + } +`; + +const CheckboxGroup = styled.div` + width: 100%; + height: auto; + + display: flex; + flex-direction: column; + gap: 8px; +`; + +const CheckboxRaw = styled.div` + width: 100%; + height: auto; + + display: flex; + flex-direction: raw; + align-items: center; + gap: 8px; + + .checkbox { + margin-right: 0px; + } +`; + +export { + Container, + BlockContainer, + HeaderRaw, + InputGroup, + InputRaw, + CheckboxGroup, + CheckboxRaw, +}; diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/ClientForm/ClientForm.types.ts b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/ClientForm/ClientForm.types.ts new file mode 100644 index 0000000000..258a745cf1 --- /dev/null +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/ClientForm/ClientForm.types.ts @@ -0,0 +1,50 @@ +import { ClientProps, ScopeDTO } from "@docspace/common/utils/oauth/dto"; + +export interface InputProps { + value: string; + name: string; + placeholder: string; + onChange: (e: React.ChangeEvent) => void; + + isReadOnly?: boolean; + isSecret?: boolean; + withCopy?: boolean; + + withButton?: boolean; + buttonLabel?: string; + onClickButton?: () => void; + + multiplyInput?: boolean; +} + +export interface CheckboxProps { + isChecked: boolean; + onChange: () => void; + + label: string; + description: string; +} + +export interface BlockHeaderProps { + header: string; + helpButtonText: string; +} + +export interface BlockProps { + children: React.ReactNode; +} + +export interface ClientFormProps { + id?: string; + client?: ClientProps; + + scopeList?: ScopeDTO[]; + + fetchClient?: (clientId: string) => Promise; + fetchScopes?: () => Promise; + + saveClient: (client: ClientProps) => Promise; + updateClient: (clientId: string, client: ClientProps) => Promise; + + regenerateSecret?: (clientId: string) => Promise; +} diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/ClientForm/components/Block.tsx b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/ClientForm/components/Block.tsx new file mode 100644 index 0000000000..99357a3501 --- /dev/null +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/ClientForm/components/Block.tsx @@ -0,0 +1,10 @@ +import React from "react"; + +import { BlockContainer } from "../ClientForm.styled"; +import { BlockProps } from "../ClientForm.types"; + +const Block = ({ children }: BlockProps) => { + return {children}; +}; + +export default Block; diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/ClientForm/components/BlockHeader.tsx b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/ClientForm/components/BlockHeader.tsx new file mode 100644 index 0000000000..ba445548f3 --- /dev/null +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/ClientForm/components/BlockHeader.tsx @@ -0,0 +1,30 @@ +import React from "react"; + +import Text from "@docspace/components/text"; +//@ts-ignore +import HelpButton from "@docspace/components/help-button"; + +import { HeaderRaw } from "../ClientForm.styled"; +import { BlockHeaderProps } from "../ClientForm.types"; + +const BlockHeader = ({ header, helpButtonText }: BlockHeaderProps) => { + return ( + + + {header} + + + + ); +}; + +export default BlockHeader; diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/ClientForm/components/Checkbox.tsx b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/ClientForm/components/Checkbox.tsx new file mode 100644 index 0000000000..1a94820367 --- /dev/null +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/ClientForm/components/Checkbox.tsx @@ -0,0 +1,46 @@ +import React from "react"; + +import Checkbox from "@docspace/components/checkbox"; +import Text from "@docspace/components/text"; + +import { CheckboxRaw } from "../ClientForm.styled"; +import { CheckboxProps } from "../ClientForm.types"; + +const CheckboxComponent = ({ + isChecked, + onChange, + label, + description, +}: CheckboxProps) => { + return ( + + + + {label} + + + {description} + + + ); +}; + +export default CheckboxComponent; diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/ClientForm/components/Input.tsx b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/ClientForm/components/Input.tsx new file mode 100644 index 0000000000..22b91f9fba --- /dev/null +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/ClientForm/components/Input.tsx @@ -0,0 +1,66 @@ +import React from "react"; +import copy from "copy-to-clipboard"; + +import InputBlock from "@docspace/components/input-block"; +import Button from "@docspace/components/button"; +// @ts-ignore +import toastr from "@docspace/components/toast/toastr"; + +import CopyReactSvgUrl from "PUBLIC_DIR/images/copy.react.svg?url"; + +import { InputProps } from "../ClientForm.types"; +import { InputRaw } from "../ClientForm.styled"; + +const Input = ({ + value, + placeholder, + name, + onChange, + isReadOnly, + isSecret, + withCopy, + withButton, + buttonLabel, + onClickButton, + multiplyInput, +}: InputProps) => { + const onCopy = () => { + if (value) { + toastr.success( + isSecret + ? "Secret has been copied to the clipboard" + : "ID has been copied to the clipboard" + ); + copy(value); + } + }; + + return ( + + + + {withButton && ( +