diff --git a/dashboard/package-lock.json b/dashboard/package-lock.json index 7917cfa..41d31f9 100644 --- a/dashboard/package-lock.json +++ b/dashboard/package-lock.json @@ -10,6 +10,7 @@ "license": "ISC", "dependencies": { "@chakra-ui/react": "^1.7.3", + "@emotion/core": "^11.0.0", "@emotion/react": "^11.7.1", "@emotion/styled": "^11.6.0", "@types/react": "^17.0.38", @@ -17,6 +18,7 @@ "@types/react-router-dom": "^5.3.2", "dayjs": "^1.10.7", "esbuild": "^0.14.9", + "focus-visible": "^5.2.0", "framer-motion": "^5.5.5", "graphql": "^16.2.0", "lodash": "^4.17.21", @@ -978,6 +980,11 @@ "stylis": "4.0.13" } }, + "node_modules/@emotion/core": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@emotion/core/-/core-11.0.0.tgz", + "integrity": "sha512-w4sE3AmHmyG6RDKf6mIbtHpgJUSJ2uGvPQb8VXFL7hFjMPibE8IiehG8cMX3Ztm4svfCQV6KqusQbeIOkurBcA==" + }, "node_modules/@emotion/hash": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", @@ -1667,6 +1674,11 @@ "node": ">=10" } }, + "node_modules/focus-visible": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/focus-visible/-/focus-visible-5.2.0.tgz", + "integrity": "sha512-Rwix9pBtC1Nuy5wysTmKy+UjbDJpIfg8eHjw0rjZ1mX4GNLz1Bmd16uDpI3Gk1i70Fgcs8Csg2lPm8HULFg9DQ==" + }, "node_modules/framer-motion": { "version": "5.5.5", "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-5.5.5.tgz", @@ -2517,8 +2529,7 @@ "@chakra-ui/css-reset": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@chakra-ui/css-reset/-/css-reset-1.1.1.tgz", - "integrity": "sha512-+KNNHL4OWqeKia5SL858K3Qbd8WxMij9mWIilBzLD4j2KFrl/+aWFw8syMKth3NmgIibrjsljo+PU3fy2o50dg==", - "requires": {} + "integrity": "sha512-+KNNHL4OWqeKia5SL858K3Qbd8WxMij9mWIilBzLD4j2KFrl/+aWFw8syMKth3NmgIibrjsljo+PU3fy2o50dg==" }, "@chakra-ui/descendant": { "version": "2.1.1", @@ -3038,6 +3049,11 @@ "stylis": "4.0.13" } }, + "@emotion/core": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@emotion/core/-/core-11.0.0.tgz", + "integrity": "sha512-w4sE3AmHmyG6RDKf6mIbtHpgJUSJ2uGvPQb8VXFL7hFjMPibE8IiehG8cMX3Ztm4svfCQV6KqusQbeIOkurBcA==" + }, "@emotion/hash": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", @@ -3117,8 +3133,7 @@ "@graphql-typed-document-node/core": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.1.1.tgz", - "integrity": "sha512-NQ17ii0rK1b34VZonlmT2QMJFI70m0TRwbknO/ihlbatXyaktDhN/98vBiUU6kNBPljqGqyIrl2T4nY2RpFANg==", - "requires": {} + "integrity": "sha512-NQ17ii0rK1b34VZonlmT2QMJFI70m0TRwbknO/ihlbatXyaktDhN/98vBiUU6kNBPljqGqyIrl2T4nY2RpFANg==" }, "@popperjs/core": { "version": "2.11.0", @@ -3540,6 +3555,11 @@ "tslib": "^2.0.3" } }, + "focus-visible": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/focus-visible/-/focus-visible-5.2.0.tgz", + "integrity": "sha512-Rwix9pBtC1Nuy5wysTmKy+UjbDJpIfg8eHjw0rjZ1mX4GNLz1Bmd16uDpI3Gk1i70Fgcs8Csg2lPm8HULFg9DQ==" + }, "framer-motion": { "version": "5.5.5", "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-5.5.5.tgz", @@ -3823,8 +3843,7 @@ "react-icons": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.3.1.tgz", - "integrity": "sha512-cB10MXLTs3gVuXimblAdI71jrJx8njrJZmNMEMC+sQu5B/BIOmlsAjskdqpn81y8UBVEGuHODd7/ci5DvoSzTQ==", - "requires": {} + "integrity": "sha512-cB10MXLTs3gVuXimblAdI71jrJx8njrJZmNMEMC+sQu5B/BIOmlsAjskdqpn81y8UBVEGuHODd7/ci5DvoSzTQ==" }, "react-is": { "version": "16.13.1", @@ -4010,8 +4029,7 @@ "use-callback-ref": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.2.5.tgz", - "integrity": "sha512-gN3vgMISAgacF7sqsLPByqoePooY3n2emTH59Ur5d/M8eg4WTWu1xp8i8DHjohftIyEx0S08RiYxbffr4j8Peg==", - "requires": {} + "integrity": "sha512-gN3vgMISAgacF7sqsLPByqoePooY3n2emTH59Ur5d/M8eg4WTWu1xp8i8DHjohftIyEx0S08RiYxbffr4j8Peg==" }, "use-sidecar": { "version": "1.0.5", diff --git a/dashboard/package.json b/dashboard/package.json index 9f854ba..0762191 100644 --- a/dashboard/package.json +++ b/dashboard/package.json @@ -12,6 +12,7 @@ "license": "ISC", "dependencies": { "@chakra-ui/react": "^1.7.3", + "@emotion/core": "^11.0.0", "@emotion/react": "^11.7.1", "@emotion/styled": "^11.6.0", "@types/react": "^17.0.38", @@ -19,6 +20,7 @@ "@types/react-router-dom": "^5.3.2", "dayjs": "^1.10.7", "esbuild": "^0.14.9", + "focus-visible": "^5.2.0", "framer-motion": "^5.5.5", "graphql": "^16.2.0", "lodash": "^4.17.21", diff --git a/dashboard/src/App.tsx b/dashboard/src/App.tsx index 001e7a9..1f62166 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'; @@ -24,6 +25,7 @@ const theme = extendTheme({ 'html, body, #root': { fontFamily: 'Avenir, Helvetica, Arial, sans-serif', height: '100%', + outline: 'none', }, }, }, @@ -36,14 +38,16 @@ const theme = extendTheme({ export default function App() { return ( - - - - - - - - - + + + + + + + + + + + ); } 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..a235e09 --- /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 Logins + + + +
+ +
+
+ +
+
+ +
+
+ +
+ +
+
+ +
+
+ +
+
+ +
+ +
+
+ +
+
+ +
+
+
+
+
+ ); +}; + +export default OAuthConfig; 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..cf39f6c --- /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 { 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/UICustomization.tsx b/dashboard/src/components/EnvComponents/UICustomization.tsx new file mode 100644 index 0000000..756c739 --- /dev/null +++ b/dashboard/src/components/EnvComponents/UICustomization.tsx @@ -0,0 +1,79 @@ +import React from 'react'; +import { Flex, Stack, Text } from '@chakra-ui/react'; +import InputField from '../InputField'; +import { SwitchInputType } from '../../constants'; + +const UICustomization = ({ variables, setVariables }: any) => { + return ( +
+ {' '} + + Disable Features + + + + + Disable Login Page: + + + + + + + + Disable Email Verification: + + + + + + + + Disable Magic Login Link: + + + + + + + + Disable Basic Authentication: + + + + + + + + Disable Sign Up: + + + + + + +
+ ); +}; + +export default UICustomization; 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/InviteMembersModal.tsx b/dashboard/src/components/InviteMembersModal.tsx index 8107669..2878722 100644 --- a/dashboard/src/components/InviteMembersModal.tsx +++ b/dashboard/src/components/InviteMembersModal.tsx @@ -22,6 +22,7 @@ import { InputRightElement, Text, Link, + Tooltip } from '@chakra-ui/react'; import { useClient } from 'urql'; import { FaUserPlus, FaMinusCircle, FaPlus, FaUpload } from 'react-icons/fa'; @@ -186,7 +187,22 @@ const InviteMembersModal = ({ isDisabled={disabled} size="sm" > -
Invite Members
+
+ {disabled ? ( + + Invite Members + + ) : ( + "Invite Members" + )} +
{" "} diff --git a/dashboard/src/components/Menu.tsx b/dashboard/src/components/Menu.tsx index a8e2fdd..819c665 100644 --- a/dashboard/src/components/Menu.tsx +++ b/dashboard/src/components/Menu.tsx @@ -1,4 +1,4 @@ -import React, { ReactNode } from 'react'; +import React, { Fragment, ReactNode } from 'react'; import { IconButton, Box, @@ -17,16 +17,27 @@ import { MenuButton, MenuItem, MenuList, + Accordion, + AccordionButton, + AccordionPanel, + AccordionItem, + useMediaQuery, } from '@chakra-ui/react'; import { - FiHome, + FiUser, FiCode, FiSettings, FiMenu, - FiUser, FiUsers, FiChevronDown, } from 'react-icons/fi'; +import { BiCustomize } from 'react-icons/bi'; +import { AiOutlineKey } from 'react-icons/ai'; +import { SiOpenaccess, SiJsonwebtokens } from 'react-icons/si'; +import { MdSecurity } from 'react-icons/md'; +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'; @@ -35,14 +46,70 @@ import { useAuthContext } from '../contexts/AuthContext'; import { AdminLogout } from '../graphql/mutation'; import { MetaQuery } from '../graphql/queries'; -interface LinkItemProps { +interface SubRoutes { name: string; icon: IconType; route: string; } + +interface LinkItemProps { + name: string; + icon: IconType; + route: string; + subRoutes?: SubRoutes[]; +} const LinkItems: Array = [ - // { name: 'Home', icon: FiHome, route: '/' }, - { name: 'Environment Variables', icon: FiSettings, route: '/' }, + { + 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' }, ]; @@ -53,6 +120,7 @@ interface SidebarProps extends BoxProps { export const Sidebar = ({ onClose, ...rest }: SidebarProps) => { const { pathname } = useLocation(); const [{ fetching, data }] = useQuery({ query: MetaQuery }); + const [isNotSmallerScreen] = useMediaQuery('(min-width:600px)'); return ( { h="full" {...rest} > - + - + logo { - {LinkItems.map((link) => ( - - - {link.name} - - - ))} - - 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} - + + {' '} + + Current Version: {data.meta.version} + + )}
); @@ -119,7 +250,7 @@ export const Sidebar = ({ onClose, ...rest }: SidebarProps) => { interface NavItemProps extends FlexProps { icon: IconType; - children: ReactText; + children: ReactText | JSX.Element | JSX.Element[]; } export const NavItem = ({ icon, children, ...rest }: NavItemProps) => { return ( @@ -204,7 +335,7 @@ export const MobileNav = ({ onOpen, ...rest }: MobileProps) => { transition="all 0.3s" _focus={{ boxShadow: 'none' }} > - + , document.getElementById('root')); +ReactDOM.render( +
+ +
, + document.getElementById('root') +); diff --git a/dashboard/src/layouts/AuthLayout.tsx b/dashboard/src/layouts/AuthLayout.tsx index dbe51ff..4c1c01f 100644 --- a/dashboard/src/layouts/AuthLayout.tsx +++ b/dashboard/src/layouts/AuthLayout.tsx @@ -1,20 +1,27 @@ -import { Box, Flex, Image, Text, Spinner } from '@chakra-ui/react'; +import { + Box, + Flex, + Image, + Text, + Spinner, + useMediaQuery, +} from '@chakra-ui/react'; import React from 'react'; import { useQuery } from 'urql'; import { MetaQuery } from '../graphql/queries'; export function AuthLayout({ children }: { children: React.ReactNode }) { const [{ fetching, data }] = useQuery({ query: MetaQuery }); + const [isNotSmallerScreen] = useMediaQuery('(min-width:600px)'); return ( - + logo ) : ( <> - + {children} diff --git a/dashboard/src/pages/Environment.tsx b/dashboard/src/pages/Environment.tsx index a6ef5a5..78f79c4 100644 --- a/dashboard/src/pages/Environment.tsx +++ b/dashboard/src/pages/Environment.tsx @@ -1,46 +1,35 @@ import React, { useEffect } from 'react'; -import { - Box, - Divider, - Flex, - Stack, - Center, - Text, - Button, - Input, - InputGroup, - InputRightElement, - useToast, -} from '@chakra-ui/react'; +import { useParams } from 'react-router-dom'; +import { Box, Flex, Stack, Button, useToast } from '@chakra-ui/react'; import { useClient } from 'urql'; -import { - FaGoogle, - FaGithub, - FaFacebookF, - FaSave, - FaRegEyeSlash, - FaRegEye, -} from 'react-icons/fa'; +import { FaSave } 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, + envSubViews, } from '../constants'; import { UpdateEnvVariables } from '../graphql/mutation'; import { getObjectDiff, capitalizeFirstLetter } from '../utils'; -import GenerateKeysModal from '../components/GenerateKeysModal'; +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 Environment = () => { const client = useClient(); const toast = useToast(); const [adminSecret, setAdminSecret] = React.useState< @@ -100,11 +89,14 @@ export default function Environment() { OLD_ADMIN_SECRET: false, }); + const { sec } = useParams(); + async function getData() { const { data: { _env: envData }, } = await client.query(EnvVariablesQuery).toPromise(); setLoading(false); + setEnvVariables({ ...envData, OLD_ADMIN_SECRET: envData.ADMIN_SECRET, @@ -118,7 +110,7 @@ export default function Environment() { useEffect(() => { getData(); - }, []); + }, [sec]); const validateAdminSecretHandler = (event: any) => { if (envVariables.OLD_ADMIN_SECRET === event.target.value) { @@ -200,636 +192,113 @@ export default function Environment() { }); }; - 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 - - - { + switch (tab) { + case envSubViews.INSTANCE_INFO: + return ( + + ); + case envSubViews.ROLES: + return ( + + ); + case envSubViews.JWT_CONFIG: + return ( + - - - - - - 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: - -
- -
-
-
- - + ); + case envSubViews.SESSION_STORAGE: + return ( + + ); + case envSubViews.EMAIL_CONFIG: + return ( + + ); + case envSubViews.WHITELIST_VARIABLES: + return ( + + ); + case envSubViews.ORGANIZATION_INFO: + return ( + + ); + case envSubViews.ACCESS_TOKEN: + return ( + + ); + case envSubViews.UI_CUSTOMIZATION: + return ( + + ); + case envSubViews.ADMIN_SECRET: + return ( + + ); + case envSubViews.DB_CRED: + return ( + + ); + default: + return ( + + ); + } + }; + return ( + + {renderComponent(sec)} +