From 7c5aab7bf35c4fac4b06e3620e91ef4f049e0141 Mon Sep 17 00:00:00 2001 From: "akash.dutta" Date: Sat, 7 May 2022 22:10:29 +0530 Subject: [PATCH] all components updated, uncontrolled input error handled --- dashboard/src/App.tsx | 3 + .../components/EnvComponents/AccessToken.tsx | 65 + .../EnvComponents/DatabaseCredentials.tsx | 88 ++ .../EnvComponents/DomainWhitelisting.tsx | 35 + .../EnvComponents/EmailConfiguration.tsx | 114 ++ .../EnvComponents/JWTConfiguration.tsx | 154 +++ .../components/EnvComponents/OAuthConfig.tsx | 191 +++ .../EnvComponents/OrganizationInfo.tsx | 60 + .../src/components/EnvComponents/Roles.tsx | 67 + .../EnvComponents/SecurityAdminSecret.tsx | 138 ++ .../EnvComponents/SessionStorage.tsx | 36 + .../EnvComponents/SocialMediaLogin.tsx | 80 ++ .../EnvComponents/UICustomization.tsx | 80 ++ dashboard/src/components/InputField.tsx | 19 +- dashboard/src/components/Menu.tsx | 539 +++++--- dashboard/src/pages/Environment.tsx | 1139 +++++------------ dashboard/src/routes/index.tsx | 2 + 17 files changed, 1765 insertions(+), 1045 deletions(-) create mode 100644 dashboard/src/components/EnvComponents/AccessToken.tsx create mode 100644 dashboard/src/components/EnvComponents/DatabaseCredentials.tsx create mode 100644 dashboard/src/components/EnvComponents/DomainWhitelisting.tsx create mode 100644 dashboard/src/components/EnvComponents/EmailConfiguration.tsx create mode 100644 dashboard/src/components/EnvComponents/JWTConfiguration.tsx create mode 100644 dashboard/src/components/EnvComponents/OAuthConfig.tsx create mode 100644 dashboard/src/components/EnvComponents/OrganizationInfo.tsx create mode 100644 dashboard/src/components/EnvComponents/Roles.tsx create mode 100644 dashboard/src/components/EnvComponents/SecurityAdminSecret.tsx create mode 100644 dashboard/src/components/EnvComponents/SessionStorage.tsx create mode 100644 dashboard/src/components/EnvComponents/SocialMediaLogin.tsx create mode 100644 dashboard/src/components/EnvComponents/UICustomization.tsx diff --git a/dashboard/src/App.tsx b/dashboard/src/App.tsx index 001e7a9..c8ac2cf 100644 --- a/dashboard/src/App.tsx +++ b/dashboard/src/App.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import { Fragment } from "react" import { ChakraProvider, extendTheme } from '@chakra-ui/react'; import { BrowserRouter } from 'react-router-dom'; import { createClient, Provider } from 'urql'; @@ -36,6 +37,7 @@ const theme = extendTheme({ export default function App() { return ( + @@ -45,5 +47,6 @@ export default function App() { + ); } diff --git a/dashboard/src/components/EnvComponents/AccessToken.tsx b/dashboard/src/components/EnvComponents/AccessToken.tsx new file mode 100644 index 0000000..9fba521 --- /dev/null +++ b/dashboard/src/components/EnvComponents/AccessToken.tsx @@ -0,0 +1,65 @@ +import React from "react"; +import { Flex, Stack, Text, useMediaQuery } from "@chakra-ui/react"; +import InputField from "../../components/InputField"; +import { TextInputType, TextAreaInputType } from "../../constants"; + +const AccessToken = ({ variables, setVariables }: any) => { + const [isNotSmallerScreen] = useMediaQuery("(min-width:600px)"); + return ( +
+ {" "} + + Access Token + + + + + Access Token Expiry Time: + + + + + + + + Custom Scripts: + + (Used to add custom fields in ID token) + + + + + + + +
+ ); +}; + +export default AccessToken; \ No newline at end of file diff --git a/dashboard/src/components/EnvComponents/DatabaseCredentials.tsx b/dashboard/src/components/EnvComponents/DatabaseCredentials.tsx new file mode 100644 index 0000000..12c85e1 --- /dev/null +++ b/dashboard/src/components/EnvComponents/DatabaseCredentials.tsx @@ -0,0 +1,88 @@ +import React from "react"; +import { Flex, Stack, Center, Text, useMediaQuery } from "@chakra-ui/react"; + +import InputField from "../../components/InputField"; +import { TextInputType } from "../../constants"; + +const DatabaseCredentials = ({ variables, setVariables }: any) => { + const [isNotSmallerScreen] = useMediaQuery("(min-width:600px)"); + return ( +
+ {" "} + + Database Credentials + + + + Note: Database related environment variables cannot be updated from + dashboard :( + + + + DataBase Name: + +
+ +
+
+ + + DataBase Type: + +
+ +
+
+ + + DataBase URL: + +
+ +
+
+
+
+ ); +}; + +export default DatabaseCredentials; \ No newline at end of file diff --git a/dashboard/src/components/EnvComponents/DomainWhitelisting.tsx b/dashboard/src/components/EnvComponents/DomainWhitelisting.tsx new file mode 100644 index 0000000..d7ed13f --- /dev/null +++ b/dashboard/src/components/EnvComponents/DomainWhitelisting.tsx @@ -0,0 +1,35 @@ +import React from "react"; +import { Flex, Stack, Center, Text, useMediaQuery } from "@chakra-ui/react"; +import InputField from "../../components/InputField"; +import { ArrayInputType} from "../../constants"; + +const DomainWhiteListing = ({ variables, setVariables }: any) => { + const [isNotSmallerScreen] = useMediaQuery("(min-width:600px)"); + return ( +
+ {" "} + + Domain White Listing + + + + + Allowed Origins: + +
+ +
+
+
+
+ ); +}; + +export default DomainWhiteListing; \ No newline at end of file diff --git a/dashboard/src/components/EnvComponents/EmailConfiguration.tsx b/dashboard/src/components/EnvComponents/EmailConfiguration.tsx new file mode 100644 index 0000000..17a1eed --- /dev/null +++ b/dashboard/src/components/EnvComponents/EmailConfiguration.tsx @@ -0,0 +1,114 @@ +import React from "react"; +import { Flex, Stack, Center, Text, useMediaQuery } from "@chakra-ui/react"; +import InputField from "../../components/InputField"; +import { TextInputType, HiddenInputType} from "../../constants"; +const EmailConfigurations = ({ + variables, + setVariables, + fieldVisibility, + setFieldVisibility, +}: any) => { + const [isNotSmallerScreen] = useMediaQuery("(min-width:600px)"); + return ( +
+ {" "} + + Email Configurations + + + + + SMTP Host: + +
+ +
+
+ + + SMTP Port: + +
+ +
+
+ + + SMTP Username: + +
+ +
+
+ + + SMTP Password: + +
+ +
+
+ + + From Email: + +
+ +
+
+
+
+ ); +}; + +export default EmailConfigurations; \ No newline at end of file diff --git a/dashboard/src/components/EnvComponents/JWTConfiguration.tsx b/dashboard/src/components/EnvComponents/JWTConfiguration.tsx new file mode 100644 index 0000000..4424725 --- /dev/null +++ b/dashboard/src/components/EnvComponents/JWTConfiguration.tsx @@ -0,0 +1,154 @@ +import React from "react"; +import { Flex, Stack, Center, Text, useMediaQuery } from "@chakra-ui/react"; +import { + HiddenInputType, + TextInputType, + TextAreaInputType, +} from "../../constants"; +import GenerateKeysModal from "../GenerateKeysModal"; +import InputField from "../InputField"; + +const JSTConfigurations = ({ + variables, + setVariables, + fieldVisibility, + setFieldVisibility, + SelectInputType, + getData, + HMACEncryptionType, + RSAEncryptionType, + ECDSAEncryptionType, +}: any) => { + const [isNotSmallerScreen] = useMediaQuery("(min-width:600px)"); + + return ( +
+ {" "} + + + JWT (JSON Web Tokens) Configurations + + + + + + + + + JWT Type: + + + + + + {Object.values(HMACEncryptionType).includes(variables.JWT_TYPE) ? ( + + + JWT Secret + +
+ +
+
+ ) : ( + <> + + + Public Key + +
+ +
+
+ + + Private Key + +
+ +
+
+ + )} + + + + JWT Role Claim: + + +
+ +
+
+
+
+ ); +}; + +export default JSTConfigurations; \ No newline at end of file diff --git a/dashboard/src/components/EnvComponents/OAuthConfig.tsx b/dashboard/src/components/EnvComponents/OAuthConfig.tsx new file mode 100644 index 0000000..b06d595 --- /dev/null +++ b/dashboard/src/components/EnvComponents/OAuthConfig.tsx @@ -0,0 +1,191 @@ +import React from "react"; +import InputField from "../InputField"; +import { + Flex, + Stack, + Center, + Text, + Box, + Divider, + useMediaQuery, +} from "@chakra-ui/react"; +import { FaGoogle, FaGithub, FaFacebookF } from "react-icons/fa"; +import { TextInputType, HiddenInputType } from "../../constants"; + +const OAuthConfig = ({ + envVariables, + setVariables, + fieldVisibility, + setFieldVisibility, +}: any) => { + const [isNotSmallerScreen] = useMediaQuery("(min-width:667px)"); + return ( +
+ + + Your instance information + + + + + Client ID + +
+ {}} + inputType={TextInputType.CLIENT_ID} + placeholder="Client ID" + readOnly={true} + /> +
+
+ + + Client Secret + +
+ +
+
+
+ + {/* ################ SOCIAL MEDIA LOGIN ################ */} + + Social Media Logins + + + +
+ +
+
+ +
+
+ +
+
+ +
+ +
+
+ +
+
+ +
+
+ +
+ +
+
+ +
+
+ +
+
+
+
+
+ ); +}; + +export default OAuthConfig; \ No newline at end of file diff --git a/dashboard/src/components/EnvComponents/OrganizationInfo.tsx b/dashboard/src/components/EnvComponents/OrganizationInfo.tsx new file mode 100644 index 0000000..c5f7e36 --- /dev/null +++ b/dashboard/src/components/EnvComponents/OrganizationInfo.tsx @@ -0,0 +1,60 @@ +import React from "react"; +import { Flex, Stack, Center, Text, useMediaQuery } from "@chakra-ui/react"; +import InputField from "../InputField"; +import { TextInputType } from "../../constants"; + +const OrganizationInfo = ({ variables, setVariables }: any) => { + const [isNotSmallerScreen] = useMediaQuery("(min-width:600px)"); + return ( +
+ {" "} + + Organization Information + + + + + Organization Name: + +
+ +
+
+ + + Organization Logo: + +
+ +
+
+
+
+ ); +}; + +export default OrganizationInfo; \ No newline at end of file diff --git a/dashboard/src/components/EnvComponents/Roles.tsx b/dashboard/src/components/EnvComponents/Roles.tsx new file mode 100644 index 0000000..ac610ab --- /dev/null +++ b/dashboard/src/components/EnvComponents/Roles.tsx @@ -0,0 +1,67 @@ +import React from "react"; +import { Flex, Stack, Center, Text, useMediaQuery } from "@chakra-ui/react"; +import { ArrayInputType } from "../../constants"; +import InputField from "../InputField"; + +const Roles = ({ variables, setVariables }: any) => { + const [isNotSmallerScreen] = useMediaQuery("(min-width:600px)"); + return ( +
+ {" "} + + Roles + + + + + Roles: + +
+ +
+
+ + + Default Roles: + +
+ +
+
+ + + Protected Roles: + +
+ +
+
+
+
+ ); +}; + +export default Roles; \ No newline at end of file diff --git a/dashboard/src/components/EnvComponents/SecurityAdminSecret.tsx b/dashboard/src/components/EnvComponents/SecurityAdminSecret.tsx new file mode 100644 index 0000000..b3e27d8 --- /dev/null +++ b/dashboard/src/components/EnvComponents/SecurityAdminSecret.tsx @@ -0,0 +1,138 @@ +import React from "react"; +import { + Flex, + Stack, + Center, + Text, + Input, + InputGroup, + InputRightElement, + useMediaQuery, +} from "@chakra-ui/react"; +import { FaRegEyeSlash, FaRegEye } from "react-icons/fa"; +import InputField from "../InputField"; +import { TextInputType, HiddenInputType } from "../../constants"; +const SecurityAdminSecret = ({ + variables, + setVariables, + fieldVisibility, + setFieldVisibility, + validateAdminSecretHandler, + adminSecret, +}: any) => { + const [isNotSmallerScreen] = useMediaQuery("(min-width:600px)"); + return ( +
+ {" "} + + Security (Admin Secret) + + + + + Old Admin Secret: + +
+ + validateAdminSecretHandler(event)} + type={ + !fieldVisibility[HiddenInputType.OLD_ADMIN_SECRET] + ? "password" + : "text" + } + /> + + {fieldVisibility[HiddenInputType.OLD_ADMIN_SECRET] ? ( +
+ setFieldVisibility({ + ...fieldVisibility, + [HiddenInputType.OLD_ADMIN_SECRET]: false, + }) + } + > + +
+ ) : ( +
+ setFieldVisibility({ + ...fieldVisibility, + [HiddenInputType.OLD_ADMIN_SECRET]: true, + }) + } + > + +
+ )} + + } + /> +
+
+
+ + + New Admin Secret: + +
+ +
+
+
+
+ ); +}; + +export default SecurityAdminSecret; \ No newline at end of file diff --git a/dashboard/src/components/EnvComponents/SessionStorage.tsx b/dashboard/src/components/EnvComponents/SessionStorage.tsx new file mode 100644 index 0000000..8570f47 --- /dev/null +++ b/dashboard/src/components/EnvComponents/SessionStorage.tsx @@ -0,0 +1,36 @@ +import React from "react"; +import { Flex, Stack, Center, Text, useMediaQuery } from "@chakra-ui/react"; +import InputField from "../InputField"; + +const SessionStorage = ({ variables, setVariables, RedisURL }: any) => { + const [isNotSmallerScreen] = useMediaQuery("(min-width:600px)"); + return ( +
+ {" "} + + Session Storage + + + + + Redis URL: + +
+ +
+
+
+
+ ); +}; + +export default SessionStorage; \ No newline at end of file diff --git a/dashboard/src/components/EnvComponents/SocialMediaLogin.tsx b/dashboard/src/components/EnvComponents/SocialMediaLogin.tsx new file mode 100644 index 0000000..38df534 --- /dev/null +++ b/dashboard/src/components/EnvComponents/SocialMediaLogin.tsx @@ -0,0 +1,80 @@ +import React from "react"; +import { Flex, Stack, Text, useMediaQuery } from "@chakra-ui/react"; +import InputField from "../InputField"; +import { SwitchInputType } from "../../constants"; + +const UICustomization = ({ variables, setVariables }: any) => { + const [isNotSmallerScreen] = useMediaQuery("(min-width:600px)"); + return ( +
+ {" "} + + Disable Features + + + + + Disable Login Page: + + + + + + + + Disable Email Verification: + + + + + + + + Disable Magic Login Link: + + + + + + + + Disable Basic Authentication: + + + + + + + + Disable Sign Up: + + + + + + +
+ ); +}; + +export default UICustomization; \ No newline at end of file diff --git a/dashboard/src/components/EnvComponents/UICustomization.tsx b/dashboard/src/components/EnvComponents/UICustomization.tsx new file mode 100644 index 0000000..38df534 --- /dev/null +++ b/dashboard/src/components/EnvComponents/UICustomization.tsx @@ -0,0 +1,80 @@ +import React from "react"; +import { Flex, Stack, Text, useMediaQuery } from "@chakra-ui/react"; +import InputField from "../InputField"; +import { SwitchInputType } from "../../constants"; + +const UICustomization = ({ variables, setVariables }: any) => { + const [isNotSmallerScreen] = useMediaQuery("(min-width:600px)"); + return ( +
+ {" "} + + Disable Features + + + + + Disable Login Page: + + + + + + + + Disable Email Verification: + + + + + + + + Disable Magic Login Link: + + + + + + + + Disable Basic Authentication: + + + + + + + + Disable Sign Up: + + + + + + +
+ ); +}; + +export default UICustomization; \ No newline at end of file diff --git a/dashboard/src/components/InputField.tsx b/dashboard/src/components/InputField.tsx index ede074d..8e58189 100644 --- a/dashboard/src/components/InputField.tsx +++ b/dashboard/src/components/InputField.tsx @@ -116,7 +116,7 @@ const InputField = ({ 3 ? "scroll" : "hidden"} + overflowY="hidden" + justifyContent="start" + alignItems="center" > {variables[inputType].map((role: string, index: number) => ( @@ -220,7 +221,7 @@ const InputField = ({ size="xs" minW="150px" placeholder="add a new value" - value={inputData[inputType]} + value={inputData[inputType] ?? ''} onChange={(e: any) => { setInputData({ ...inputData, [inputType]: e.target.value }); }} diff --git a/dashboard/src/components/Menu.tsx b/dashboard/src/components/Menu.tsx index a8e2fdd..8c1883b 100644 --- a/dashboard/src/components/Menu.tsx +++ b/dashboard/src/components/Menu.tsx @@ -1,233 +1,362 @@ -import React, { ReactNode } from 'react'; +import React, { ReactNode } from "react"; import { - IconButton, - Box, - CloseButton, - Flex, - Image, - HStack, - VStack, - Icon, - useColorModeValue, - Link, - Text, - BoxProps, - FlexProps, - Menu, - MenuButton, - MenuItem, - MenuList, -} from '@chakra-ui/react'; + IconButton, + Box, + CloseButton, + Flex, + Image, + HStack, + VStack, + Icon, + useColorModeValue, + Link, + Text, + BoxProps, + FlexProps, + Menu, + MenuButton, + MenuItem, + MenuList, + Accordion, + AccordionButton, + AccordionPanel, + AccordionItem, + AccordionIcon, + useMediaQuery, +} from "@chakra-ui/react"; import { - FiHome, - FiCode, - FiSettings, - FiMenu, - FiUser, - FiUsers, - FiChevronDown, -} from 'react-icons/fi'; -import { IconType } from 'react-icons'; -import { ReactText } from 'react'; -import { useMutation, useQuery } from 'urql'; -import { NavLink, useNavigate, useLocation } from 'react-router-dom'; -import { useAuthContext } from '../contexts/AuthContext'; -import { AdminLogout } from '../graphql/mutation'; -import { MetaQuery } from '../graphql/queries'; + FiHome, + FiUser, + FiGlobe, + FiCode, + FiSettings, + FiMenu, + FiUsers, + FiChevronDown, + FiShieldOff, +} from "react-icons/fi"; +import { BiCustomize } from "react-icons/bi"; +import { FcDatabase } from "react-icons/fc"; +import { AiOutlineKey } from "react-icons/ai"; +import { SiOpenaccess, SiJsonwebtokens } from "react-icons/si"; +import { MdSecurity } from "react-icons/md"; +import { RiSkullLine } from "react-icons/ri"; +import { RiDatabase2Line } from "react-icons/ri"; +import { BsCheck2Circle } from "react-icons/bs"; +import { HiOutlineMail, HiOutlineOfficeBuilding } from "react-icons/hi"; +import { IconType } from "react-icons"; +import { ReactText } from "react"; +import { useMutation, useQuery } from "urql"; +import { NavLink, useNavigate, useLocation } from "react-router-dom"; +import { useAuthContext } from "../contexts/AuthContext"; +import { AdminLogout } from "../graphql/mutation"; +import { MetaQuery } from "../graphql/queries"; + +interface SubRoutes { + name: string; + icon: IconType; + route: string; +} interface LinkItemProps { - name: string; - icon: IconType; - route: string; + name: string; + icon: IconType; + route: string; + subRoutes?: SubRoutes[]; } const LinkItems: Array = [ - // { name: 'Home', icon: FiHome, route: '/' }, - { name: 'Environment Variables', icon: FiSettings, route: '/' }, - { name: 'Users', icon: FiUsers, route: '/users' }, + { + name: "Environment ", + icon: FiSettings, + route: "/", + subRoutes: [ + { + name: "OAuth Config", + icon: AiOutlineKey, + route: "/oauth-setting", + }, + + { name: "Roles", icon: FiUser, route: "/roles" }, + { + name: "JWT Secrets", + icon: SiJsonwebtokens, + route: "/jwt-config", + }, + { + name: "Session Storage", + icon: RiDatabase2Line, + route: "/session-storage", + }, + { + name: "Email Configurations", + icon: HiOutlineMail, + route: "/email-config", + }, + { + name: "Domain White Listing", + icon: BsCheck2Circle, + route: "/whitelist-variables", + }, + { + name: "Organization Info", + icon: HiOutlineOfficeBuilding, + route: "/organization-info", + }, + { name: "Access Token", icon: SiOpenaccess, route: "/access-token" }, + { + name: "UI Customization", + icon: BiCustomize, + route: "/ui-customization", + }, + { name: "Database", icon: RiDatabase2Line, route: "/db-cred" }, + { + name: " Security", + icon: MdSecurity, + route: "/admin-secret", + }, + ], + }, + { name: "Users", icon: FiUsers, route: "/users" }, + // { name: "AUsers", icon: FiUsers, route: "/usersa" }, ]; interface SidebarProps extends BoxProps { - onClose: () => void; + onClose: () => void; } export const Sidebar = ({ onClose, ...rest }: SidebarProps) => { - const { pathname } = useLocation(); - const [{ fetching, data }] = useQuery({ query: MetaQuery }); - return ( - - - - - logo - - AUTHORIZER - - - - - - {LinkItems.map((link) => ( - - - {link.name} - - - ))} + const { pathname } = useLocation(); + const [{ fetching, data }] = useQuery({ query: MetaQuery }); + const [isNotSmallerScreen] = useMediaQuery("(min-width:600px)"); + return ( + + + + + logo + + AUTHORIZER + + + + + - - API Playground - + + + {LinkItems.map((link) => + link?.subRoutes ? ( + + + + + {link.name} + + + + + + + + {link.subRoutes?.map((sublink) => ( + + {" "} + + + {sublink.name} + {" "} + + + ))} + + + ) : ( + + {" "} + + + {link.name} + {" "} + + + ) + )} + + API Playground + + + - {data?.meta?.version && ( - - Current Version: {data.meta.version} - - )} - - ); + {data?.meta?.version && ( + + {" "} + + Current Version: {data.meta.version} + + + )} + + ); }; interface NavItemProps extends FlexProps { - icon: IconType; - children: ReactText; + icon: IconType; + children: ReactText; } export const NavItem = ({ icon, children, ...rest }: NavItemProps) => { - return ( - - {icon && ( - - )} - {children} - - ); + return ( + + {icon && ( + + )} + {children} + + ); }; interface MobileProps extends FlexProps { - onOpen: () => void; + onOpen: () => void; } export const MobileNav = ({ onOpen, ...rest }: MobileProps) => { - const [_, logout] = useMutation(AdminLogout); - const { setIsLoggedIn } = useAuthContext(); - const navigate = useNavigate(); + const [_, logout] = useMutation(AdminLogout); + const { setIsLoggedIn } = useAuthContext(); + const navigate = useNavigate(); - const handleLogout = async () => { - await logout(); - setIsLoggedIn(false); - navigate('/', { replace: true }); - }; + const handleLogout = async () => { + await logout(); + setIsLoggedIn(false); + navigate("/", { replace: true }); + }; - return ( - - } - /> + return ( + + } + /> - logo + logo - - - - - - - - Admin - - - - - - - - Sign out - - - - - - ); -}; + + + + + + + + Admin + + + + + + + + Sign out + + + + + + ); +}; \ No newline at end of file diff --git a/dashboard/src/pages/Environment.tsx b/dashboard/src/pages/Environment.tsx index a6ef5a5..db09298 100644 --- a/dashboard/src/pages/Environment.tsx +++ b/dashboard/src/pages/Environment.tsx @@ -1,847 +1,324 @@ -import React, { useEffect } from 'react'; +import React, { useEffect } from "react"; +import { useParams } from "react-router-dom"; +import { Box, Flex, Stack, Button, useToast } from "@chakra-ui/react"; +import { useClient } from "urql"; +import { FaSave } from "react-icons/fa"; +import _ from "lodash"; +import { EnvVariablesQuery } from "../graphql/queries"; import { - Box, - Divider, - Flex, - Stack, - Center, - Text, - Button, - Input, - InputGroup, - InputRightElement, - useToast, -} from '@chakra-ui/react'; -import { useClient } from 'urql'; -import { - FaGoogle, - FaGithub, - FaFacebookF, - FaSave, - FaRegEyeSlash, - FaRegEye, -} from 'react-icons/fa'; -import _ from 'lodash'; -import InputField from '../components/InputField'; -import { EnvVariablesQuery } from '../graphql/queries'; -import { - ArrayInputType, - SelectInputType, - HiddenInputType, - TextInputType, - TextAreaInputType, - SwitchInputType, - HMACEncryptionType, - RSAEncryptionType, - ECDSAEncryptionType, - envVarTypes, -} from '../constants'; -import { UpdateEnvVariables } from '../graphql/mutation'; -import { getObjectDiff, capitalizeFirstLetter } from '../utils'; -import GenerateKeysModal from '../components/GenerateKeysModal'; + SelectInputType, + HiddenInputType, + TextInputType, + HMACEncryptionType, + RSAEncryptionType, + ECDSAEncryptionType, + envVarTypes, +} from "../constants"; +import { UpdateEnvVariables } from "../graphql/mutation"; +import { getObjectDiff, capitalizeFirstLetter } from "../utils"; +// Component inputs +import OAuthConfig from "../components/EnvComponents/OAuthConfig"; +import Roles from "../components/EnvComponents/Roles"; +import JWTConfigurations from "../components/EnvComponents/JWTConfiguration"; +import SessionStorage from "../components/EnvComponents/SessionStorage"; +import EmailConfigurations from "../components/EnvComponents/EmailConfiguration"; +import DomainWhiteListing from "../components/EnvComponents/DomainWhitelisting"; +import OrganizationInfo from "../components/EnvComponents/OrganizationInfo"; +import AccessToken from "../components/EnvComponents/AccessToken"; +import UICustomization from "../components/EnvComponents/UICustomization" +import SecurityAdminSecret from "../components/EnvComponents/SecurityAdminSecret"; +import DatabaseCredentials from "../components/EnvComponents/DatabaseCredentials"; -export default function Environment() { - const client = useClient(); - const toast = useToast(); - const [adminSecret, setAdminSecret] = React.useState< - Record - >({ - value: '', - disableInputField: true, - }); - const [loading, setLoading] = React.useState(true); - const [envVariables, setEnvVariables] = React.useState({ - GOOGLE_CLIENT_ID: '', - GOOGLE_CLIENT_SECRET: '', - GITHUB_CLIENT_ID: '', - GITHUB_CLIENT_SECRET: '', - FACEBOOK_CLIENT_ID: '', - FACEBOOK_CLIENT_SECRET: '', - ROLES: [], - DEFAULT_ROLES: [], - PROTECTED_ROLES: [], - JWT_TYPE: '', - JWT_SECRET: '', - JWT_ROLE_CLAIM: '', - JWT_PRIVATE_KEY: '', - JWT_PUBLIC_KEY: '', - REDIS_URL: '', - SMTP_HOST: '', - SMTP_PORT: '', - SMTP_USERNAME: '', - SMTP_PASSWORD: '', - SENDER_EMAIL: '', - ALLOWED_ORIGINS: [], - ORGANIZATION_NAME: '', - ORGANIZATION_LOGO: '', - CUSTOM_ACCESS_TOKEN_SCRIPT: '', - ADMIN_SECRET: '', - DISABLE_LOGIN_PAGE: false, - DISABLE_MAGIC_LINK_LOGIN: false, - DISABLE_EMAIL_VERIFICATION: false, - DISABLE_BASIC_AUTHENTICATION: false, - DISABLE_SIGN_UP: false, - OLD_ADMIN_SECRET: '', - DATABASE_NAME: '', - DATABASE_TYPE: '', - DATABASE_URL: '', - ACCESS_TOKEN_EXPIRY_TIME: '', - }); +const Environment = () => { + const client = useClient(); + const toast = useToast(); + const [adminSecret, setAdminSecret] = React.useState< + Record + >({ + value: "", + disableInputField: true, + }); + const [loading, setLoading] = React.useState(true); + const [envVariables, setEnvVariables] = React.useState({ + GOOGLE_CLIENT_ID: "", + GOOGLE_CLIENT_SECRET: "", + GITHUB_CLIENT_ID: "", + GITHUB_CLIENT_SECRET: "", + FACEBOOK_CLIENT_ID: "", + FACEBOOK_CLIENT_SECRET: "", + ROLES: [], + DEFAULT_ROLES: [], + PROTECTED_ROLES: [], + JWT_TYPE: "", + JWT_SECRET: "", + JWT_ROLE_CLAIM: "", + JWT_PRIVATE_KEY: "", + JWT_PUBLIC_KEY: "", + REDIS_URL: "", + SMTP_HOST: "", + SMTP_PORT: "", + SMTP_USERNAME: "", + SMTP_PASSWORD: "", + SENDER_EMAIL: "", + ALLOWED_ORIGINS: [], + ORGANIZATION_NAME: "", + ORGANIZATION_LOGO: "", + CUSTOM_ACCESS_TOKEN_SCRIPT: "", + ADMIN_SECRET: "", + DISABLE_LOGIN_PAGE: false, + DISABLE_MAGIC_LINK_LOGIN: false, + DISABLE_EMAIL_VERIFICATION: false, + DISABLE_BASIC_AUTHENTICATION: false, + DISABLE_SIGN_UP: false, + OLD_ADMIN_SECRET: "", + DATABASE_NAME: "", + DATABASE_TYPE: "", + DATABASE_URL: "", + ACCESS_TOKEN_EXPIRY_TIME: "", + }); - const [fieldVisibility, setFieldVisibility] = React.useState< - Record - >({ - GOOGLE_CLIENT_SECRET: false, - GITHUB_CLIENT_SECRET: false, - FACEBOOK_CLIENT_SECRET: false, - JWT_SECRET: false, - SMTP_PASSWORD: false, - ADMIN_SECRET: false, - OLD_ADMIN_SECRET: false, - }); + const [fieldVisibility, setFieldVisibility] = React.useState< + Record + >({ + GOOGLE_CLIENT_SECRET: false, + GITHUB_CLIENT_SECRET: false, + FACEBOOK_CLIENT_SECRET: false, + JWT_SECRET: false, + SMTP_PASSWORD: false, + ADMIN_SECRET: false, + OLD_ADMIN_SECRET: false, + }); - async function getData() { - const { - data: { _env: envData }, - } = await client.query(EnvVariablesQuery).toPromise(); - setLoading(false); - setEnvVariables({ - ...envData, - OLD_ADMIN_SECRET: envData.ADMIN_SECRET, - ADMIN_SECRET: '', - }); - setAdminSecret({ - value: '', - disableInputField: true, - }); - } + const { sec } = useParams(); - useEffect(() => { - getData(); - }, []); + async function getData() { + const { + data: { _env: envData }, + } = await client.query(EnvVariablesQuery).toPromise(); + setLoading(false); - const validateAdminSecretHandler = (event: any) => { - if (envVariables.OLD_ADMIN_SECRET === event.target.value) { - setAdminSecret({ - ...adminSecret, - value: event.target.value, - disableInputField: false, - }); - } else { - setAdminSecret({ - ...adminSecret, - value: event.target.value, - disableInputField: true, - }); - } - if (envVariables.ADMIN_SECRET !== '') { - setEnvVariables({ ...envVariables, ADMIN_SECRET: '' }); - } - }; + setEnvVariables({ + ...envData, + OLD_ADMIN_SECRET: envData.ADMIN_SECRET, + ADMIN_SECRET: "", + }); + setAdminSecret({ + value: "", + disableInputField: true, + }); + } - const saveHandler = async () => { - setLoading(true); - const { - data: { _env: envData }, - } = await client.query(EnvVariablesQuery).toPromise(); - const diff = getObjectDiff(envVariables, envData); - const updatedEnvVariables = diff.reduce( - (acc: any, property: string) => ({ - ...acc, - // @ts-ignore - [property]: envVariables[property], - }), - {} - ); - if ( - updatedEnvVariables[HiddenInputType.ADMIN_SECRET] === '' || - updatedEnvVariables[HiddenInputType.OLD_ADMIN_SECRET] !== - envData.ADMIN_SECRET - ) { - delete updatedEnvVariables.OLD_ADMIN_SECRET; - delete updatedEnvVariables.ADMIN_SECRET; - } + useEffect(() => { + getData(); + }, [sec]); - delete updatedEnvVariables.DATABASE_URL; - delete updatedEnvVariables.DATABASE_TYPE; - delete updatedEnvVariables.DATABASE_NAME; + const validateAdminSecretHandler = (event: any) => { + if (envVariables.OLD_ADMIN_SECRET === event.target.value) { + setAdminSecret({ + ...adminSecret, + value: event.target.value, + disableInputField: false, + }); + } else { + setAdminSecret({ + ...adminSecret, + value: event.target.value, + disableInputField: true, + }); + } + if (envVariables.ADMIN_SECRET !== "") { + setEnvVariables({ ...envVariables, ADMIN_SECRET: "" }); + } + }; - const res = await client - .mutation(UpdateEnvVariables, { params: updatedEnvVariables }) - .toPromise(); + const saveHandler = async () => { + setLoading(true); + const { + data: { _env: envData }, + } = await client.query(EnvVariablesQuery).toPromise(); + const diff = getObjectDiff(envVariables, envData); + const updatedEnvVariables = diff.reduce( + (acc: any, property: string) => ({ + ...acc, + // @ts-ignore + [property]: envVariables[property], + }), + {} + ); + if ( + updatedEnvVariables[HiddenInputType.ADMIN_SECRET] === "" || + updatedEnvVariables[HiddenInputType.OLD_ADMIN_SECRET] !== + envData.ADMIN_SECRET + ) { + delete updatedEnvVariables.OLD_ADMIN_SECRET; + delete updatedEnvVariables.ADMIN_SECRET; + } - setLoading(false); + delete updatedEnvVariables.DATABASE_URL; + delete updatedEnvVariables.DATABASE_TYPE; + delete updatedEnvVariables.DATABASE_NAME; - if (res.error) { - toast({ - title: capitalizeFirstLetter(res.error.message), - isClosable: true, - status: 'error', - position: 'bottom-right', - }); + const res = await client + .mutation(UpdateEnvVariables, { params: updatedEnvVariables }) + .toPromise(); - return; - } + setLoading(false); - setAdminSecret({ - value: '', - disableInputField: true, - }); + if (res.error) { + toast({ + title: capitalizeFirstLetter(res.error.message), + isClosable: true, + status: "error", + position: "bottom-right", + }); - getData(); + return; + } - toast({ - title: `Successfully updated ${ - Object.keys(updatedEnvVariables).length - } variables`, - isClosable: true, - status: 'success', - position: 'bottom-right', - }); - }; + setAdminSecret({ + value: "", + disableInputField: true, + }); - return ( - - - Your instance information - - - - - Client ID - -
- {}} - inputType={TextInputType.CLIENT_ID} - placeholder="Client ID" - readOnly={true} - /> -
-
- - - Client Secret - -
- -
-
-
- - - Social Media Logins - - - -
- -
-
- -
-
- -
-
- -
- -
-
- -
-
- -
-
- -
- -
-
- -
-
- -
-
-
- - - Roles - - - - - Roles: - -
- -
-
- - - Default Roles: - -
- -
-
- - - Protected Roles: - -
- -
-
-
- - - - JWT (JSON Web Tokens) Configurations - - - - - - - - - JWT Type: - - - - - - {Object.values(HMACEncryptionType).includes(envVariables.JWT_TYPE) ? ( - - - JWT Secret - -
- -
-
- ) : ( - <> - - - Public Key - -
- -
-
- - - Private Key - -
- -
-
- - )} - - - JWT Role Claim: - -
- -
-
-
- - - Session Storage - - - - - Redis URL: - -
- -
-
-
- - - Email Configurations - - - - - SMTP Host: - -
- -
-
- - - SMTP Port: - -
- -
-
- - - SMTP Username: - -
- -
-
- - - SMTP Password: - -
- -
-
- - - From Email: - -
- -
-
-
- - - White Listing - - - - - Allowed Origins: - -
- -
-
-
- - - Organization Information - - - - - Organization Name: - -
- -
-
- - - Organization Logo: - -
- -
-
-
- - - Access Token - - - - - Access Token Expiry Time: - - - - - - - - Custom Scripts: - Used to add custom fields in ID token - - - - - - - - - Disable Features - - - - - Disable Login Page: - - - - - - - - Disable Email Verification: - - - - - - - - Disable Magic Login Link: - - - - - - - - Disable Basic Authentication: - - - - - - - - Disable Sign Up: - - - - - - - - - Danger - - - - - Note: Database related environment variables cannot be updated from - dashboard :( - - - - DataBase Name: - -
- -
-
- - - DataBase Type: - -
- -
-
- - - DataBase URL: - -
- -
-
-
- - - Old Admin Secret: - -
- - validateAdminSecretHandler(event)} - type={ - !fieldVisibility[HiddenInputType.OLD_ADMIN_SECRET] - ? 'password' - : 'text' - } - /> - - {fieldVisibility[HiddenInputType.OLD_ADMIN_SECRET] ? ( -
- setFieldVisibility({ - ...fieldVisibility, - [HiddenInputType.OLD_ADMIN_SECRET]: false, - }) - } - > - -
- ) : ( -
- setFieldVisibility({ - ...fieldVisibility, - [HiddenInputType.OLD_ADMIN_SECRET]: true, - }) - } - > - -
- )} - - } - /> -
-
-
- - - New Admin Secret: - -
- -
-
-
- - - - - - -
- ); -} + getData(); + + toast({ + title: `Successfully updated ${ + Object.keys(updatedEnvVariables).length + } variables`, + isClosable: true, + status: "success", + position: "bottom-right", + }); + }; + + const getCorrectScreen = (tab: any) => { + switch (tab) { + case "instance-info": + return ( + + ); + + case "roles": + return ( + + ); + case "jwt-config": + return ( + + ); + case "session-storage": + return ( + + ); + case "email-config": + return ( + + ); + case "whitelist-variables": + return ( + + ); + case "organization-info": + return ( + + ); + case "access-token": + return ( + + ); + case "ui-customization": + return ( + + ); + case "admin-secret": + return ( + + ); + case "db-cred": + return ( + + ); + default: + return ( + + ); + } + }; + return ( + + {getCorrectScreen(sec)} + + + + + + + ); +}; + +export default Environment; \ No newline at end of file diff --git a/dashboard/src/routes/index.tsx b/dashboard/src/routes/index.tsx index 8443372..f611e92 100644 --- a/dashboard/src/routes/index.tsx +++ b/dashboard/src/routes/index.tsx @@ -14,6 +14,7 @@ export const AppRoutes = () => { if (isLoggedIn) { return ( +
}> { +
); } return (