Feat/manage env vars (#107)

* ui to manage env variables added

* ui to manage env variables updated

* ui to manage env variables updated

* ui to manage env variables updated

* ui to manage env variables updated

* ui updates

* ui updates

* ui updates

* ui updates

* env vars input field updated

* env vars input field updated

Co-authored-by: Anik Ghosh <tech.anikghosh@gmail.com>
This commit is contained in:
Lakhan Samani
2022-01-25 09:34:35 +05:30
committed by GitHub
parent 8df8010b22
commit 82bc38923c
68 changed files with 40201 additions and 35 deletions

View File

@@ -0,0 +1,300 @@
import React from 'react';
import {
Box,
Flex,
Input,
Center,
InputGroup,
InputRightElement,
Tag,
TagLabel,
TagRightIcon,
Select,
Textarea,
Switch,
Code,
} from '@chakra-ui/react';
import {
FaRegClone,
FaRegEye,
FaRegEyeSlash,
FaPlus,
FaTimes,
} from 'react-icons/fa';
import {
ArrayInputOperations,
ArrayInputType,
SelectInputType,
HiddenInputType,
TextInputType,
TextAreaInputType,
SwitchInputType,
} from '../constants';
import { copyTextToClipboard } from '../utils';
const InputField = ({
inputType,
envVariables,
setEnvVariables,
fieldVisibility,
setFieldVisibility,
...downshiftProps
}: any) => {
const props = {
size: 'sm',
...downshiftProps,
};
const [inputFieldVisibility, setInputFieldVisibility] = React.useState<
Record<string, boolean>
>({
ROLES: false,
DEFAULT_ROLES: false,
PROTECTED_ROLES: false,
ALLOWED_ORIGINS: false,
});
const [inputData, setInputData] = React.useState<Record<string, string>>({
ROLES: '',
DEFAULT_ROLES: '',
PROTECTED_ROLES: '',
ALLOWED_ORIGINS: '',
});
const updateInputHandler = (
type: string,
operation: any,
role: string = ''
) => {
if (operation === ArrayInputOperations.APPEND) {
if (inputData[type] !== '') {
setEnvVariables({
...envVariables,
[type]: [...envVariables[type], inputData[type]],
});
setInputData({ ...inputData, [type]: '' });
}
setInputFieldVisibility({ ...inputFieldVisibility, [type]: false });
}
if (operation === ArrayInputOperations.REMOVE) {
let updatedEnvVars = envVariables[type].filter(
(item: string) => item !== role
);
setEnvVariables({
...envVariables,
[type]: updatedEnvVars,
});
}
};
if (Object.values(TextInputType).includes(inputType)) {
return (
<InputGroup size="sm">
<Input
{...props}
value={envVariables[inputType]}
onChange={(
event: Event & {
target: HTMLInputElement;
}
) =>
setEnvVariables({
...envVariables,
[inputType]: event.target.value,
})
}
/>
<InputRightElement
children={<FaRegClone color="#bfbfbf" />}
cursor="pointer"
onClick={() => copyTextToClipboard(envVariables[inputType])}
/>
</InputGroup>
);
}
if (Object.values(HiddenInputType).includes(inputType)) {
return (
<InputGroup size="sm">
<Input
{...props}
value={envVariables[inputType]}
onChange={(
event: Event & {
target: HTMLInputElement;
}
) =>
setEnvVariables({
...envVariables,
[inputType]: event.target.value,
})
}
type={!fieldVisibility[inputType] ? 'password' : 'text'}
/>
<InputRightElement
right="15px"
children={
<Flex>
{fieldVisibility[inputType] ? (
<Center
w="25px"
margin="0 1.5%"
cursor="pointer"
onClick={() =>
setFieldVisibility({
...fieldVisibility,
[inputType]: false,
})
}
>
<FaRegEyeSlash color="#bfbfbf" />
</Center>
) : (
<Center
w="25px"
margin="0 1.5%"
cursor="pointer"
onClick={() =>
setFieldVisibility({
...fieldVisibility,
[inputType]: true,
})
}
>
<FaRegEye color="#bfbfbf" />
</Center>
)}
<Center
w="25px"
margin="0 1.5%"
cursor="pointer"
onClick={() => copyTextToClipboard(envVariables[inputType])}
>
<FaRegClone color="#bfbfbf" />
</Center>
</Flex>
}
/>
</InputGroup>
);
}
if (Object.values(ArrayInputType).includes(inputType)) {
return (
<Flex
border="1px solid #e2e8f0"
w="100%"
h="45px"
wrap="wrap"
overflow="scroll"
padding="1%"
>
{envVariables[inputType].map((role: string, index: number) => (
<Box key={index} margin="1" role="group">
<Tag
size="sm"
variant="outline"
colorScheme="gray"
minW="fit-content"
>
<TagLabel cursor="default">{role}</TagLabel>
<TagRightIcon
boxSize="12px"
as={FaTimes}
display="none"
cursor="pointer"
_groupHover={{ display: 'block' }}
onClick={() =>
updateInputHandler(
inputType,
ArrayInputOperations.REMOVE,
role
)
}
/>
</Tag>
</Box>
))}
{inputFieldVisibility[inputType] ? (
<Box ml="1.15%">
<Input
type="text"
size="xs"
placeholder="add a new value"
value={inputData[inputType]}
onChange={(e: any) => {
setInputData({ ...inputData, [inputType]: e.target.value });
}}
onBlur={() =>
updateInputHandler(inputType, ArrayInputOperations.APPEND)
}
onKeyPress={(event) => {
if (event.key === 'Enter') {
updateInputHandler(inputType, ArrayInputOperations.APPEND);
}
}}
/>
</Box>
) : (
<Box
margin="1"
cursor="pointer"
onClick={() =>
setInputFieldVisibility({
...inputFieldVisibility,
[inputType]: true,
})
}
>
<Tag
size="sm"
variant="outline"
colorScheme="gray"
minW="fit-content"
>
<FaPlus />
</Tag>
</Box>
)}
</Flex>
);
}
if (Object.values(SelectInputType).includes(inputType)) {
return (
<Select size="sm" {...props}>
{[envVariables[inputType]].map((value: string) => (
<option value="value" key={value}>
{value}
</option>
))}
</Select>
);
}
if (Object.values(TextAreaInputType).includes(inputType)) {
return (
<Textarea
{...props}
size="lg"
value={inputData[inputType]}
onChange={(e: any) => {
setInputData({ ...inputData, [inputType]: e.target.value });
}}
/>
);
}
if (Object.values(SwitchInputType).includes(inputType)) {
return (
<Flex w="25%" justifyContent="space-between">
<Code h="75%">Off</Code>
<Switch
size="md"
isChecked={!envVariables[inputType]}
onChange={() => {
setEnvVariables({
...envVariables,
[inputType]: !envVariables[inputType],
});
}}
/>
<Code h="75%">On</Code>
</Flex>
);
}
return null;
};
export default InputField;

View File

@@ -161,6 +161,7 @@ export const MobileNav = ({ onOpen, ...rest }: MobileProps) => {
borderBottomWidth="1px"
borderBottomColor={useColorModeValue('gray.200', 'gray.700')}
justifyContent={{ base: 'space-between', md: 'flex-end' }}
zIndex={99}
{...rest}
>
<IconButton

View File

@@ -1 +1,56 @@
export const LOGO_URL = "https://user-images.githubusercontent.com/6964334/147834043-fc384cab-e7ca-40f8-9663-38fc25fd5f3a.png"
export const LOGO_URL =
'https://user-images.githubusercontent.com/6964334/147834043-fc384cab-e7ca-40f8-9663-38fc25fd5f3a.png';
export const TextInputType = {
GOOGLE_CLIENT_ID: 'GOOGLE_CLIENT_ID',
GITHUB_CLIENT_ID: 'GITHUB_CLIENT_ID',
FACEBOOK_CLIENT_ID: 'FACEBOOK_CLIENT_ID',
JWT_ROLE_CLAIM: 'JWT_ROLE_CLAIM',
REDIS_URL: 'REDIS_URL',
SMTP_HOST: 'SMTP_HOST',
SMTP_PORT: 'SMTP_PORT',
SMTP_USERNAME: 'SMTP_USERNAME',
SENDER_EMAIL: 'SENDER_EMAIL',
ORGANIZATION_NAME: 'ORGANIZATION_NAME',
ORGANIZATION_LOGO: 'ORGANIZATION_LOGO',
DATABASE_NAME: 'DATABASE_NAME',
DATABASE_TYPE: 'DATABASE_TYPE',
DATABASE_URL: 'DATABASE_URL',
};
export const HiddenInputType = {
GOOGLE_CLIENT_SECRET: 'GOOGLE_CLIENT_SECRET',
GITHUB_CLIENT_SECRET: 'GITHUB_CLIENT_SECRET',
FACEBOOK_CLIENT_SECRET: 'FACEBOOK_CLIENT_SECRET',
JWT_SECRET: 'JWT_SECRET',
SMTP_PASSWORD: 'SMTP_PASSWORD',
ADMIN_SECRET: 'ADMIN_SECRET',
OLD_ADMIN_SECRET: 'OLD_ADMIN_SECRET',
};
export const ArrayInputType = {
ROLES: 'ROLES',
DEFAULT_ROLES: 'DEFAULT_ROLES',
PROTECTED_ROLES: 'PROTECTED_ROLES',
ALLOWED_ORIGINS: 'ALLOWED_ORIGINS',
};
export const SelectInputType = {
JWT_TYPE: 'JWT_TYPE',
};
export const TextAreaInputType = {
CUSTOM_ACCESS_TOKEN_SCRIPT: 'CUSTOM_ACCESS_TOKEN_SCRIPT',
};
export const SwitchInputType = {
DISABLE_LOGIN_PAGE: 'DISABLE_LOGIN_PAGE',
DISABLE_MAGIC_LINK_LOGIN: 'DISABLE_MAGIC_LINK_LOGIN',
DISABLE_EMAIL_VERIFICATION: 'DISABLE_EMAIL_VERIFICATION',
DISABLE_BASIC_AUTHENTICATION: 'DISABLE_BASIC_AUTHENTICATION',
};
export const ArrayInputOperations = {
APPEND: 'APPEND',
REMOVE: 'REMOVE',
};

View File

@@ -32,7 +32,7 @@ export const AuthContextProvider = ({ children }: { children: any }) => {
if (fetching) {
return (
<Center>
<Center h="100%">
<Spinner />
</Center>
);

View File

@@ -21,3 +21,13 @@ export const AdminLogout = `
}
}
`;
export const UpdateEnvVariables = `
mutation updateEnvVariables(
$params: UpdateEnvInput!
) {
_update_env(params: $params) {
message
}
}
`;

View File

@@ -5,3 +5,40 @@ export const AdminSessionQuery = `
}
}
`;
export const EnvVariablesQuery = `
query {
_env{
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,
REDIS_URL,
SMTP_HOST,
SMTP_PORT,
SMTP_USERNAME,
SMTP_PASSWORD,
SENDER_EMAIL,
ALLOWED_ORIGINS,
ORGANIZATION_NAME,
ORGANIZATION_LOGO,
ADMIN_SECRET,
DISABLE_LOGIN_PAGE,
DISABLE_MAGIC_LINK_LOGIN,
DISABLE_EMAIL_VERIFICATION,
DISABLE_BASIC_AUTHENTICATION,
CUSTOM_ACCESS_TOKEN_SCRIPT,
DATABASE_NAME,
DATABASE_TYPE,
DATABASE_URL,
}
}
`;

View File

@@ -1,35 +1,765 @@
import { Box, Divider, Flex } from '@chakra-ui/react';
import React from 'react';
import {
Box,
Divider,
Flex,
Stack,
Center,
Text,
Button,
Input,
InputGroup,
InputRightElement,
} from '@chakra-ui/react';
import { useClient } from 'urql';
import {
FaGoogle,
FaGithub,
FaFacebookF,
FaUndo,
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,
} from '../constants';
import { UpdateEnvVariables } from '../graphql/mutation';
import { getObjectDiff } from '../utils';
interface envVarTypes {
GOOGLE_CLIENT_ID: string;
GOOGLE_CLIENT_SECRET: string;
GITHUB_CLIENT_ID: string;
GITHUB_CLIENT_SECRET: string;
FACEBOOK_CLIENT_ID: string;
FACEBOOK_CLIENT_SECRET: string;
ROLES: [string] | [];
DEFAULT_ROLES: [string] | [];
PROTECTED_ROLES: [string] | [];
JWT_TYPE: string;
JWT_SECRET: string;
JWT_ROLE_CLAIM: string;
REDIS_URL: string;
SMTP_HOST: string;
SMTP_PORT: string;
SMTP_USERNAME: string;
SMTP_PASSWORD: string;
SENDER_EMAIL: string;
ALLOWED_ORIGINS: [string] | [];
ORGANIZATION_NAME: string;
ORGANIZATION_LOGO: string;
CUSTOM_ACCESS_TOKEN_SCRIPT: string;
ADMIN_SECRET: string;
DISABLE_LOGIN_PAGE: boolean;
DISABLE_MAGIC_LINK_LOGIN: boolean;
DISABLE_EMAIL_VERIFICATION: boolean;
DISABLE_BASIC_AUTHENTICATION: boolean;
OLD_ADMIN_SECRET: string;
DATABASE_NAME: string;
DATABASE_TYPE: string;
DATABASE_URL: string;
}
// Don't allow changing database from here as it can cause persistence issues
export default function Environment() {
const client = useClient();
const [adminSecret, setAdminSecret] = React.useState<
Record<string, string | boolean>
>({
value: '',
disableInputField: true,
});
const [loading, setLoading] = React.useState<boolean>(false);
const [envVariables, setEnvVariables] = React.useState<envVarTypes>({
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: '',
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,
OLD_ADMIN_SECRET: '',
DATABASE_NAME: '',
DATABASE_TYPE: '',
DATABASE_URL: '',
});
const [oldEnvVariables, setOldEnvVariables] = React.useState<envVarTypes>({
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: '',
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,
OLD_ADMIN_SECRET: '',
DATABASE_NAME: '',
DATABASE_TYPE: '',
DATABASE_URL: '',
});
const [fieldVisibility, setFieldVisibility] = React.useState<
Record<string, boolean>
>({
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 updateHandler = async () => {
setLoading(true);
const {
data: { _env: envData },
} = await client.query(EnvVariablesQuery).toPromise();
if (envData) {
setEnvVariables({
...envVariables,
...envData,
ADMIN_SECRET: '',
OLD_ADMIN_SECRET: envData.ADMIN_SECRET,
});
setOldEnvVariables({
...envVariables,
...envData,
ADMIN_SECRET: '',
OLD_ADMIN_SECRET: envData.ADMIN_SECRET,
});
}
setAdminSecret({
value: '',
disableInputField: true,
});
setLoading(false);
};
React.useEffect(() => {
updateHandler();
}, []);
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 saveHandler = async () => {
setLoading(true);
const diff = getObjectDiff(envVariables, oldEnvVariables);
const updatedEnvVariables = diff.reduce(
(acc: any, property: string) => ({
...acc,
// @ts-ignore
[property]: envVariables[property],
}),
{}
);
if (diff.includes(HiddenInputType.ADMIN_SECRET)) {
updatedEnvVariables[HiddenInputType.OLD_ADMIN_SECRET] =
// @ts-ignore
envVariables[HiddenInputType.OLD_ADMIN_SECRET];
}
const res = await client
.mutation(UpdateEnvVariables, { params: envVariables })
.toPromise();
console.log('res ==>> ', res);
updateHandler();
};
return (
<Box m="5" p="5" bg="white" rounded="md">
<h1>Social Media Logins</h1>
<Divider />- Add horizontal input for clientID and secret for - Google -
Github - Facebook
<h1>Roles</h1>
<Divider />- Add tagged input for roles, default roles, and protected
roles
<h1>JWT Configurations</h1>
<Divider />- Add input for JWT Type (keep this disabled for now with
notice saying, "More JWT types will be enabled in upcoming releases"),JWT
secret, JWT role claim
<h1>Session Storage</h1>
<Divider />- Add input for redis url
<h1>Email Configurations</h1>
<Divider />- Add input for SMTP Host, PORT, Username, Password, From
Email,
<h1>White Listing</h1>
<Divider />- Add input for allowed origins
<h1>Organization Information</h1>
<Divider />- Add input for organization name, and logo
<h1>Custom Scripts</h1>
<Divider />- For now add text area input for CUSTOM_ACCESS_TOKEN_SCRIPT
<h1>Disable Features</h1>
<Divider />
<h1>Danger</h1>
<Divider />- Include changing admin secret
<Text fontSize="md" paddingTop="2%">
Social Media Logins
</Text>
<Stack spacing={6} padding="3%">
<Flex>
<Center
w="50px"
marginRight="1.5%"
border="1px solid #e2e8f0"
borderRadius="5px"
>
<FaGoogle style={{ color: '#8c8c8c' }} />
</Center>
<Center w="45%" marginRight="1.5%">
<InputField
envVariables={envVariables}
setEnvVariables={setEnvVariables}
inputType={TextInputType.GOOGLE_CLIENT_ID}
placeholder="Google Client ID"
/>
</Center>
<Center w="45%">
<InputField
envVariables={envVariables}
setEnvVariables={setEnvVariables}
fieldVisibility={fieldVisibility}
setFieldVisibility={setFieldVisibility}
inputType={HiddenInputType.GOOGLE_CLIENT_SECRET}
placeholder="Google Secret"
/>
</Center>
</Flex>
<Flex>
<Center
w="50px"
marginRight="1.5%"
border="1px solid #e2e8f0"
borderRadius="5px"
>
<FaGithub style={{ color: '#8c8c8c' }} />
</Center>
<Center w="45%" marginRight="1.5%">
<InputField
envVariables={envVariables}
setEnvVariables={setEnvVariables}
inputType={TextInputType.GITHUB_CLIENT_ID}
placeholder="Github Client ID"
/>
</Center>
<Center w="45%">
<InputField
envVariables={envVariables}
setEnvVariables={setEnvVariables}
fieldVisibility={fieldVisibility}
setFieldVisibility={setFieldVisibility}
inputType={HiddenInputType.GITHUB_CLIENT_SECRET}
placeholder="Github Secret"
/>
</Center>
</Flex>
<Flex>
<Center
w="50px"
marginRight="1.5%"
border="1px solid #e2e8f0"
borderRadius="5px"
>
<FaFacebookF style={{ color: '#8c8c8c' }} />
</Center>
<Center w="45%" marginRight="1.5%">
<InputField
envVariables={envVariables}
setEnvVariables={setEnvVariables}
inputType={TextInputType.FACEBOOK_CLIENT_ID}
placeholder="Facebook Client ID"
/>
</Center>
<Center w="45%">
<InputField
envVariables={envVariables}
setEnvVariables={setEnvVariables}
fieldVisibility={fieldVisibility}
setFieldVisibility={setFieldVisibility}
inputType={HiddenInputType.FACEBOOK_CLIENT_SECRET}
placeholder="Facebook Secret"
/>
</Center>
</Flex>
</Stack>
<Divider marginTop="2%" marginBottom="2%" />
<Text fontSize="md" paddingTop="2%">
Roles
</Text>
<Stack spacing={6} padding="3% 5%">
<Flex>
<Flex w="30%" justifyContent="start" alignItems="center">
<Text fontSize="sm">Roles:</Text>
</Flex>
<Center w="70%">
<InputField
envVariables={envVariables}
setEnvVariables={setEnvVariables}
inputType={ArrayInputType.ROLES}
/>
</Center>
</Flex>
<Flex>
<Flex w="30%" justifyContent="start" alignItems="center">
<Text fontSize="sm">Default Roles:</Text>
</Flex>
<Center w="70%">
<InputField
envVariables={envVariables}
setEnvVariables={setEnvVariables}
inputType={ArrayInputType.DEFAULT_ROLES}
/>
</Center>
</Flex>
<Flex>
<Flex w="30%" justifyContent="start" alignItems="center">
<Text fontSize="sm">Protected Roles:</Text>
</Flex>
<Center w="70%">
<InputField
envVariables={envVariables}
setEnvVariables={setEnvVariables}
inputType={ArrayInputType.PROTECTED_ROLES}
/>
</Center>
</Flex>
</Stack>
<Divider marginTop="2%" marginBottom="2%" />
<Text fontSize="md" paddingTop="2%">
JWT Configurations
</Text>
<Stack spacing={6} padding="3% 5%">
<Flex>
<Flex w="30%" justifyContent="start" alignItems="center">
<Text fontSize="sm">JWT Type:</Text>
</Flex>
<Center w="70%">
<Flex w="100%" justifyContent="space-between">
<Flex flex="2">
<InputField
envVariables={envVariables}
setEnvVariables={setEnvVariables}
inputType={SelectInputType.JWT_TYPE}
isDisabled={true}
defaultValue={SelectInputType.JWT_TYPE}
/>
</Flex>
<Flex flex="3" justifyContent="center" alignItems="center">
<Text fontSize="sm">
More JWT types will be enabled in upcoming releases.
</Text>
</Flex>
</Flex>
</Center>
</Flex>
<Flex>
<Flex w="30%" justifyContent="start" alignItems="center">
<Text fontSize="sm">JWT Secret</Text>
</Flex>
<Center w="70%">
<InputField
envVariables={envVariables}
setEnvVariables={setEnvVariables}
fieldVisibility={fieldVisibility}
setFieldVisibility={setFieldVisibility}
inputType={HiddenInputType.JWT_SECRET}
/>
</Center>
</Flex>
<Flex>
<Flex w="30%" justifyContent="start" alignItems="center">
<Text fontSize="sm">JWT Role Claim:</Text>
</Flex>
<Center w="70%">
<InputField
envVariables={envVariables}
setEnvVariables={setEnvVariables}
inputType={TextInputType.JWT_ROLE_CLAIM}
/>
</Center>
</Flex>
</Stack>
<Divider marginTop="2%" marginBottom="2%" />
<Text fontSize="md" paddingTop="2%">
Session Storage
</Text>
<Stack spacing={6} padding="3% 5%">
<Flex>
<Flex w="30%" justifyContent="start" alignItems="center">
<Text fontSize="sm">Redis URL:</Text>
</Flex>
<Center w="70%">
<InputField
envVariables={envVariables}
setEnvVariables={setEnvVariables}
inputType={TextInputType.REDIS_URL}
/>
</Center>
</Flex>
</Stack>
<Divider marginTop="2%" marginBottom="2%" />
<Text fontSize="md" paddingTop="2%">
Email Configurations
</Text>
<Stack spacing={6} padding="3% 5%">
<Flex>
<Flex w="30%" justifyContent="start" alignItems="center">
<Text fontSize="sm">SMTP Host:</Text>
</Flex>
<Center w="70%">
<InputField
envVariables={envVariables}
setEnvVariables={setEnvVariables}
inputType={TextInputType.SMTP_HOST}
/>
</Center>
</Flex>
<Flex>
<Flex w="30%" justifyContent="start" alignItems="center">
<Text fontSize="sm">Port:</Text>
</Flex>
<Center w="70%">
<InputField
envVariables={envVariables}
setEnvVariables={setEnvVariables}
inputType={TextInputType.SMTP_PORT}
/>
</Center>
</Flex>
<Flex>
<Flex w="30%" justifyContent="start" alignItems="center">
<Text fontSize="sm">Username:</Text>
</Flex>
<Center w="70%">
<InputField
envVariables={envVariables}
setEnvVariables={setEnvVariables}
inputType={TextInputType.SMTP_USERNAME}
/>
</Center>
</Flex>
<Flex>
<Flex w="30%" justifyContent="start" alignItems="center">
<Text fontSize="sm">Password:</Text>
</Flex>
<Center w="70%">
<InputField
envVariables={envVariables}
setEnvVariables={setEnvVariables}
fieldVisibility={fieldVisibility}
setFieldVisibility={setFieldVisibility}
inputType={HiddenInputType.SMTP_PASSWORD}
/>
</Center>
</Flex>
<Flex>
<Flex w="30%" justifyContent="start" alignItems="center">
<Text fontSize="sm">From Email:</Text>
</Flex>
<Center w="70%">
<InputField
envVariables={envVariables}
setEnvVariables={setEnvVariables}
inputType={TextInputType.SENDER_EMAIL}
/>
</Center>
</Flex>
</Stack>
<Divider marginTop="2%" marginBottom="2%" />
<Text fontSize="md" paddingTop="2%">
White Listing
</Text>
<Stack spacing={6} padding="3% 5%">
<Flex>
<Flex w="30%" justifyContent="start" alignItems="center">
<Text fontSize="sm">Allowed Origins:</Text>
</Flex>
<Center w="70%">
<InputField
envVariables={envVariables}
setEnvVariables={setEnvVariables}
inputType={ArrayInputType.ALLOWED_ORIGINS}
/>
</Center>
</Flex>
</Stack>
<Divider marginTop="2%" marginBottom="2%" />
<Text fontSize="md" paddingTop="2%">
Organization Information
</Text>
<Stack spacing={6} padding="3% 5%">
<Flex>
<Flex w="30%" justifyContent="start" alignItems="center">
<Text fontSize="sm">Organization Name:</Text>
</Flex>
<Center w="70%">
<InputField
envVariables={envVariables}
setEnvVariables={setEnvVariables}
inputType={TextInputType.ORGANIZATION_NAME}
/>
</Center>
</Flex>
<Flex>
<Flex w="30%" justifyContent="start" alignItems="center">
<Text fontSize="sm">Organization Logo:</Text>
</Flex>
<Center w="70%">
<InputField
envVariables={envVariables}
setEnvVariables={setEnvVariables}
inputType={TextInputType.ORGANIZATION_LOGO}
/>
</Center>
</Flex>
</Stack>
<Divider marginTop="2%" marginBottom="2%" />
<Text fontSize="md" paddingTop="2%">
Custom Scripts
</Text>
<Stack spacing={6} padding="3% 5%">
<Flex>
<Center w="100%">
<InputField
envVariables={envVariables}
setEnvVariables={setEnvVariables}
inputType={TextAreaInputType.CUSTOM_ACCESS_TOKEN_SCRIPT}
placeholder="Add script here"
minH="25vh"
/>
</Center>
</Flex>
</Stack>
<Divider marginTop="2%" marginBottom="2%" />
<Text fontSize="md" paddingTop="2%">
Disable Features
</Text>
<Stack spacing={6} padding="3% 5%">
<Flex>
<Flex w="30%" justifyContent="start" alignItems="center">
<Text fontSize="sm">Login Page:</Text>
</Flex>
<Flex justifyContent="start" w="70%">
<InputField
envVariables={envVariables}
setEnvVariables={setEnvVariables}
inputType={SwitchInputType.DISABLE_LOGIN_PAGE}
/>
</Flex>
</Flex>
<Flex>
<Flex w="30%" justifyContent="start" alignItems="center">
<Text fontSize="sm">Magic Login Link:</Text>
</Flex>
<Flex justifyContent="start" w="70%">
<InputField
envVariables={envVariables}
setEnvVariables={setEnvVariables}
inputType={SwitchInputType.DISABLE_MAGIC_LINK_LOGIN}
/>
</Flex>
</Flex>
<Flex>
<Flex w="30%" justifyContent="start" alignItems="center">
<Text fontSize="sm">Email Verification:</Text>
</Flex>
<Flex justifyContent="start" w="70%">
<InputField
envVariables={envVariables}
setEnvVariables={setEnvVariables}
inputType={SwitchInputType.DISABLE_EMAIL_VERIFICATION}
/>
</Flex>
</Flex>
<Flex>
<Flex w="30%" justifyContent="start" alignItems="center">
<Text fontSize="sm">Basic Authentication:</Text>
</Flex>
<Flex justifyContent="start" w="70%">
<InputField
envVariables={envVariables}
setEnvVariables={setEnvVariables}
inputType={SwitchInputType.DISABLE_BASIC_AUTHENTICATION}
/>
</Flex>
</Flex>
</Stack>
<Divider marginTop="2%" marginBottom="2%" />
<Text fontSize="md" paddingTop="2%">
Danger
</Text>
<Stack
spacing={6}
padding="0 5%"
marginTop="3%"
border="1px solid #ff7875"
borderRadius="5px"
>
<Stack spacing={6} padding="3% 0">
<Flex>
<Flex w="30%" justifyContent="start" alignItems="center">
<Text fontSize="sm">DataBase Name:</Text>
</Flex>
<Center w="70%">
<InputField
envVariables={envVariables}
setEnvVariables={setEnvVariables}
inputType={TextInputType.DATABASE_NAME}
isDisabled={true}
/>
</Center>
</Flex>
<Flex>
<Flex w="30%" justifyContent="start" alignItems="center">
<Text fontSize="sm">DataBase Type:</Text>
</Flex>
<Center w="70%">
<InputField
envVariables={envVariables}
setEnvVariables={setEnvVariables}
inputType={TextInputType.DATABASE_TYPE}
isDisabled={true}
/>
</Center>
</Flex>
<Flex>
<Flex w="30%" justifyContent="start" alignItems="center">
<Text fontSize="sm">DataBase URL:</Text>
</Flex>
<Center w="70%">
<InputField
envVariables={envVariables}
setEnvVariables={setEnvVariables}
inputType={TextInputType.DATABASE_URL}
isDisabled={true}
/>
</Center>
</Flex>
</Stack>
<Flex marginTop="3%">
<Flex w="30%" justifyContent="start" alignItems="center">
<Text fontSize="sm">Old Admin Secret:</Text>
</Flex>
<Center w="70%">
<InputGroup size="sm">
<Input
size="sm"
placeholder="Enter Old Admin Secret"
value={adminSecret.value as string}
onChange={(event: any) => validateAdminSecretHandler(event)}
type={
!fieldVisibility[HiddenInputType.OLD_ADMIN_SECRET]
? 'password'
: 'text'
}
/>
<InputRightElement
right="5px"
children={
<Flex>
{fieldVisibility[HiddenInputType.OLD_ADMIN_SECRET] ? (
<Center
w="25px"
margin="0 1.5%"
cursor="pointer"
onClick={() =>
setFieldVisibility({
...fieldVisibility,
[HiddenInputType.OLD_ADMIN_SECRET]: false,
})
}
>
<FaRegEyeSlash color="#bfbfbf" />
</Center>
) : (
<Center
w="25px"
margin="0 1.5%"
cursor="pointer"
onClick={() =>
setFieldVisibility({
...fieldVisibility,
[HiddenInputType.OLD_ADMIN_SECRET]: true,
})
}
>
<FaRegEye color="#bfbfbf" />
</Center>
)}
</Flex>
}
/>
</InputGroup>
</Center>
</Flex>
<Flex paddingBottom="3%">
<Flex w="30%" justifyContent="start" alignItems="center">
<Text fontSize="sm">New Admin Secret:</Text>
</Flex>
<Center w="70%">
<InputField
envVariables={envVariables}
setEnvVariables={setEnvVariables}
inputType={HiddenInputType.ADMIN_SECRET}
fieldVisibility={fieldVisibility}
setFieldVisibility={setFieldVisibility}
isDisabled={adminSecret.disableInputField}
placeholder="Enter New Admin Secret"
/>
</Center>
</Flex>
</Stack>
<Divider marginTop="5%" marginBottom="2%" />
<Stack spacing={6} padding="1% 0">
<Flex justifyContent="end" alignItems="center">
<Button
leftIcon={<FaSave />}
colorScheme="blue"
variant="solid"
onClick={saveHandler}
isDisabled={loading}
>
Save
</Button>
</Flex>
</Stack>
</Box>
);
}

View File

@@ -1,6 +1,65 @@
import {
Alert,
AlertIcon,
AlertTitle,
AlertDescription,
} from '@chakra-ui/react';
import _ from 'lodash';
export const hasAdminSecret = () => {
return (<any>window)['__authorizer__'].isOnboardingCompleted === true;
};
export const capitalizeFirstLetter = (data: string): string =>
data.charAt(0).toUpperCase() + data.slice(1);
const fallbackCopyTextToClipboard = (text: string) => {
const textArea = document.createElement('textarea');
textArea.value = text;
textArea.style.top = '0';
textArea.style.left = '0';
textArea.style.position = 'fixed';
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
try {
const successful = document.execCommand('copy');
const msg = successful ? 'successful' : 'unsuccessful';
console.log('Fallback: Copying text command was ' + msg);
} catch (err) {
console.error('Fallback: Oops, unable to copy', err);
}
document.body.removeChild(textArea);
};
export const copyTextToClipboard = (text: string) => {
if (!navigator.clipboard) {
fallbackCopyTextToClipboard(text);
return;
}
navigator.clipboard.writeText(text).then(
() => {
console.log('Async: Copying to clipboard was successful!');
},
(err) => {
console.error('Async: Could not copy text: ', err);
}
);
};
export const getObjectDiff = (obj1: any, obj2: any) => {
const diff = Object.keys(obj1).reduce((result, key) => {
if (!obj2.hasOwnProperty(key)) {
result.push(key);
} else if (_.isEqual(obj1[key], obj2[key])) {
const resultKeyIndex = result.indexOf(key);
result.splice(resultKeyIndex, 1);
}
return result;
}, Object.keys(obj2));
return diff;
};