Merge remote-tracking branch 'origin/main' into auto-capitalization-toggle

This commit is contained in:
Hasan Mansoor
2023-02-05 03:19:06 +03:00
129 changed files with 3586 additions and 1104 deletions
+11 -5
View File
@@ -10,7 +10,9 @@ import Layout from '@app/components/basic/Layout';
import NotificationProvider from '@app/components/context/Notifications/NotificationProvider';
import Telemetry from '@app/components/utilities/telemetry/Telemetry';
import { publicPaths } from '@app/const';
import { SubscriptionProvider } from '@app/context';
import { AuthProvider } from '@app/context/AuthContext';
import { WorkspaceProvider } from '@app/context/WorkspaceContext';
import { queryClient } from '@app/reactQuery';
import '@fortawesome/fontawesome-svg-core/styles.css';
@@ -68,11 +70,15 @@ const App = ({ Component, pageProps, ...appProps }: NextAppProp): JSX.Element =>
return (
<QueryClientProvider client={queryClient}>
<AuthProvider>
<NotificationProvider>
<Layout>
<Component {...pageProps} />
</Layout>
</NotificationProvider>
<WorkspaceProvider>
<SubscriptionProvider>
<NotificationProvider>
<Layout>
<Component {...pageProps} />
</Layout>
</NotificationProvider>
</SubscriptionProvider>
</WorkspaceProvider>
</AuthProvider>
</QueryClientProvider>
);
+1 -1
View File
@@ -124,7 +124,7 @@ export default function Activity() {
};
return (
<div className="mx-6 lg:mx-0 w-full overflow-y-scroll h-screen">
<div className="mx-6 lg:mx-0 w-full h-screen">
<NavHeader pageName="Project Activity" isProjectRelated />
{currentSidebarAction && (
<ActivitySideBar toggleSidebar={toggleSidebar} currentAction={currentSidebarAction} />
@@ -13,6 +13,7 @@ export interface IMembershipOrg {
organization: string;
role: 'owner' | 'admin' | 'member';
status: 'invited' | 'accepted';
deniedPermissions: any[];
}
/**
* This route lets us get all the users in an org.
@@ -0,0 +1,27 @@
import SecurityClient from '@app/components/utilities/SecurityClient';
/**
* This function change the access of a user in a certain organization
* @param {string} organizationId
* @param {string} membershipId
* @param {string} role
* @returns
*/
const changeUserRoleInOrganization = (organizationId: string, membershipId: string, role: string) =>
SecurityClient.fetchCall(`/api/v2/organizations/${organizationId}/memberships/${membershipId}`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
role
})
}).then(async (res) => {
if (res && res.status === 200) {
return res;
}
console.log('Failed to change the user role in an org');
return undefined;
});
export default changeUserRoleInOrganization;
@@ -0,0 +1,22 @@
import SecurityClient from '@app/components/utilities/SecurityClient';
/**
* This route lets us get the environments that a certain user has acess to in a certain project
* @param {string} workspaceId
* @returns
*/
const getWorkspaceEnvironments = ({ workspaceId }: { workspaceId: string }) =>
SecurityClient.fetchCall(`/api/v2/workspace/${workspaceId}/environments`, {
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
}).then(async (res) => {
if (res?.status === 200) {
return (await res.json()).accessibleEnvironments;
}
console.log('Failed to get accessible environments');
return undefined;
});
export default getWorkspaceEnvironments;
+28 -9
View File
@@ -41,11 +41,13 @@ import updateSecrets from '../api/files/UpdateSecrets';
import getUser from '../api/user/getUser';
import checkUserAction from '../api/userActions/checkUserAction';
import registerUserAction from '../api/userActions/registerUserAction';
import getWorkspaceEnvironments from '../api/workspace/getWorkspaceEnvironments';
import getWorkspaces from '../api/workspace/getWorkspaces';
type WorkspaceEnv = {
name: string;
slug: string;
isWriteDenied: boolean;
};
interface SecretDataProps {
@@ -134,7 +136,8 @@ export default function Dashboard() {
const [selectedSnapshotEnv, setSelectedSnapshotEnv] = useState<WorkspaceEnv>();
const [selectedEnv, setSelectedEnv] = useState<WorkspaceEnv>({
name: '',
slug: ''
slug: '',
isWriteDenied: false
});
const [atSecretAreaTop, setAtSecretsAreaTop] = useState(true);
const secretsTop = useRef<HTMLDivElement>(null);
@@ -216,9 +219,10 @@ export default function Dashboard() {
}
setAutoCapitalization(workspace?.autoCapitalization ?? true);
setWorkspaceEnvs(workspace?.environments || []);
const accessibleEnvironments = await getWorkspaceEnvironments({ workspaceId });
setWorkspaceEnvs(accessibleEnvironments || []);
// set env
const env = workspace?.environments?.[0] || {
const env = accessibleEnvironments?.[0] || {
name: 'unknown',
slug: 'unkown'
};
@@ -353,6 +357,7 @@ export default function Dashboard() {
findDuplicates(data!.map((item: SecretDataProps) => item.key)).length > 0;
if (nameErrors) {
setSaveLoading(false);
return createNotification({
text: 'Solve all name errors before saving secrets.',
type: 'error'
@@ -360,12 +365,21 @@ export default function Dashboard() {
}
if (duplicatesExist) {
setSaveLoading(false);
return createNotification({
text: 'Remove duplicated secret names before saving.',
type: 'error'
});
}
if (selectedEnv.isWriteDenied) {
setSaveLoading(false);
return createNotification({
text: 'You are not allowed to edit this environment',
type: 'error'
});
}
// Once "Save changes" is clicked, disable that button
setButtonReady(false);
@@ -506,7 +520,7 @@ export default function Dashboard() {
};
return data ? (
<div className="bg-bunker-800 max-h-screen flex flex-col justify-between text-white">
<div className="bg-bunker-800 max-h-screen h-full relative flex flex-col justify-between text-white">
<Head>
<title>{t('common:head-title', { title: t('dashboard:title') })}</title>
<link rel="icon" href="/infisical.ico" />
@@ -514,7 +528,7 @@ export default function Dashboard() {
<meta property="og:title" content={String(t('dashboard:og-title'))} />
<meta name="og:description" content={String(t('dashboard:og-description'))} />
</Head>
<div className="flex flex-row">
<div className="flex flex-row h-full">
{sidebarSecretId !== 'None' && (
<SideBar
toggleSidebar={toggleSidebar}
@@ -527,6 +541,9 @@ export default function Dashboard() {
modifyValueOverride={listenChangeValueOverride}
modifyComment={listenChangeComment}
buttonReady={buttonReady}
workspaceEnvs={workspaceEnvs}
selectedEnv={selectedEnv}
workspaceId={workspaceId}
savePush={savePush}
sharedToHide={sharedToHide}
setSharedToHide={setSharedToHide}
@@ -582,7 +599,8 @@ export default function Dashboard() {
setSelectedEnv(
workspaceEnvs.find(({ name }) => envName === name) || {
name: 'unknown',
slug: 'unknown'
slug: 'unknown',
isWriteDenied: false
}
)
}
@@ -662,7 +680,8 @@ export default function Dashboard() {
setSelectedEnv(
workspaceEnvs.find(({ name }) => envName === name) || {
name: 'unknown',
slug: 'unknown'
slug: 'unknown',
isWriteDenied: false
}
)
}
@@ -675,7 +694,8 @@ export default function Dashboard() {
setSelectedSnapshotEnv(
workspaceEnvs.find(({ name }) => envName === name) || {
name: 'unknown',
slug: 'unknown'
slug: 'unknown',
isWriteDenied: false
}
)
}
@@ -857,7 +877,6 @@ export default function Dashboard() {
</div>
) : (
<div className="relative z-10 w-10/12 mr-auto h-full ml-2 bg-bunker-800 flex flex-col items-center justify-center">
<div className="absolute top-0 bg-bunker h-14 border-b border-mineshaft-700 w-full" />
<Image src="/images/loading/loading.gif" height={70} width={120} alt="loading animation" />
</div>
);
+1 -1
View File
@@ -167,7 +167,7 @@ export default function Home() {
})}
{learningItem({
text: 'Inject secrets locally',
subText: 'Replace .env files with a more secure an efficient alternative.',
subText: 'Replace .env files with a more secure and efficient alternative.',
complete: false,
icon: faNetworkWired,
time: '8 min',
+6
View File
@@ -22,6 +22,7 @@ export default function Login() {
const [password, setPassword] = useState('');
const [errorLogin, setErrorLogin] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const [isAlreadyLoggedIn, setIsAlreadyLoggedIn] = useState(false);
const router = useRouter();
const { t } = useTranslation();
const lang = router.locale ?? 'en';
@@ -44,6 +45,7 @@ export default function Login() {
}
};
if (isLoggedIn()) {
setIsAlreadyLoggedIn(true);
redirectToDashboard();
}
}, []);
@@ -64,6 +66,10 @@ export default function Login() {
});
};
if (isAlreadyLoggedIn) {
return null
}
return (
<div className="bg-bunker-800 h-screen flex flex-col justify-start px-6">
<Head>
+13 -354
View File
@@ -1,370 +1,29 @@
import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import Head from 'next/head';
import { useRouter } from 'next/router';
import { useTranslation } from 'next-i18next';
import { faCheck, faCopy, faPlus } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import Button from '@app/components/basic/buttons/Button';
import AddServiceTokenDialog from '@app/components/basic/dialog/AddServiceTokenDialog';
import InputField from '@app/components/basic/InputField';
import EnvironmentTable from '@app/components/basic/table/EnvironmentsTable';
import ServiceTokenTable from '@app/components/basic/table/ServiceTokenTable';
import NavHeader from '@app/components/navigation/NavHeader';
import { getTranslatedServerSideProps } from '@app/components/utilities/withTranslateProps';
import { Checkbox } from '@app/components/v2';
import deleteEnvironment from '@app/pages/api/environments/deleteEnvironment';
import updateEnvironment from '@app/pages/api/environments/updateEnvironment';
import createEnvironment from '../../api/environments/createEnvironment';
import getServiceTokens from '../../api/serviceToken/getServiceTokens';
import deleteWorkspace from '../../api/workspace/deleteWorkspace';
import getWorkspaces from '../../api/workspace/getWorkspaces';
import renameWorkspace from '../../api/workspace/renameWorkspace';
import toggleAutoCapitalization from '../../api/workspace/toggleAutoCapitalization';
type EnvData = {
name: string;
slug: string;
};
export default function SettingsBasic() {
const [buttonReady, setButtonReady] = useState(false);
const [autoCapitalizationButtonReady, setAutoCapitalizationButtonReady] = useState(false);
const router = useRouter();
const [workspaceName, setWorkspaceName] = useState('');
const [autoCapitalization, setAutoCapitalization] = useState(false);
const [serviceTokens, setServiceTokens] = useState<any[]>([]);
const [environments, setEnvironments] = useState<Array<EnvData>>([]);
const [workspaceToBeDeletedName, setWorkspaceToBeDeletedName] = useState('');
// const [isAddOpen, setIsAddOpen] = useState(false);
const [isAddServiceTokenDialogOpen, setIsAddServiceTokenDialogOpen] = useState(false);
const [projectIdCopied, setProjectIdCopied] = useState(false);
const workspaceId = router.query.id as string;
import { getTranslatedStaticProps } from '@app/components/utilities/withTranslateProps';
import { ProjectSettingsPage } from '@app/views/Settings/ProjectSettingsPage';
const ProjectSettings = () => {
const { t } = useTranslation();
/**
* This function copies the project id to the clipboard
*/
function copyToClipboard() {
const copyText = document.getElementById('myInput') as HTMLInputElement;
if (copyText) {
copyText.select();
copyText.setSelectionRange(0, 99999); // For mobile devices
navigator.clipboard.writeText(copyText.value);
setProjectIdCopied(true);
setTimeout(() => setProjectIdCopied(false), 2000);
}
}
useEffect(() => {
const load = async () => {
const userWorkspaces = await getWorkspaces();
userWorkspaces.forEach((userWorkspace) => {
if (userWorkspace._id === workspaceId) {
setWorkspaceName(userWorkspace.name);
setAutoCapitalization(userWorkspace.autoCapitalization ?? true);
setEnvironments(userWorkspace.environments);
}
});
const tempServiceTokens = await getServiceTokens({
workspaceId
});
setServiceTokens(tempServiceTokens);
};
load();
}, []);
const modifyWorkspaceName = (newName: string) => {
setButtonReady(true);
setWorkspaceName(newName);
};
const toggleAutoCapitalizationCheckBox = (state: boolean) => {
setAutoCapitalizationButtonReady(true);
setAutoCapitalization(state);
};
const submitChanges = (newWorkspaceName: string) => {
renameWorkspace(workspaceId, newWorkspaceName);
setButtonReady(false);
};
const submitAutoCapitalizationChanges = () => {
toggleAutoCapitalization(workspaceId, autoCapitalization);
setAutoCapitalizationButtonReady(false);
};
const closeAddServiceTokenModal = () => {
setIsAddServiceTokenDialogOpen(false);
};
/**
* This function deleted a workspace.
* It first checks if there is more than one workspace aviable. Otherwise, it doesn't delete
* It then checks if the name of the workspace to be deleted is correct. Otherwise, it doesn't delete.
* It then deletes the workspace and forwards the user to another aviable workspace.
*/
const executeDeletingWorkspace = async () => {
const userWorkspaces = await getWorkspaces();
if (userWorkspaces.length > 1) {
if (
userWorkspaces.filter((workspace) => workspace._id === workspaceId)[0].name ===
workspaceToBeDeletedName
) {
await deleteWorkspace(workspaceId);
const ws = await getWorkspaces();
router.push(`/dashboard/${ws[0]._id}`);
}
}
};
const onCreateEnvironment = async ({ name, slug }: EnvData) => {
const res = await createEnvironment(workspaceId, {
environmentName: name,
environmentSlug: slug
});
if (res) {
// TODO: on react-query migration do an api call to resync
setEnvironments((env) => [...env, { name, slug }]);
}
};
const onUpdateEnvironment = async (oldSlug: string, { name, slug }: EnvData) => {
const res = await updateEnvironment(workspaceId, {
oldEnvironmentSlug: oldSlug,
environmentName: name,
environmentSlug: slug
});
// TODO: on react-query migration do an api call to resync
if (res) {
setEnvironments((env) => env.map((el) => (el.slug === oldSlug ? { name, slug } : el)));
}
};
const onDeleteEnvironment = async (slugToBeDelete: string) => {
const res = await deleteEnvironment(workspaceId, slugToBeDelete);
// TODO: on react-query migration do an api call to resync
if (res) {
setEnvironments((env) => env.filter(({ slug }) => slug !== slugToBeDelete));
}
};
return (
<div className="bg-bunker-800 max-h-screen flex flex-col justify-between text-white">
<>
<Head>
<title>{t('common:head-title', { title: t('settings-project:title') })}</title>
<link rel="icon" href="/infisical.ico" />
</Head>
<AddServiceTokenDialog
isOpen={isAddServiceTokenDialogOpen}
workspaceId={workspaceId}
environments={environments}
closeModal={closeAddServiceTokenModal}
workspaceName={workspaceName}
serviceTokens={serviceTokens}
setServiceTokens={setServiceTokens}
/>
<div className="flex flex-row mr-6 max-w-5xl">
<div className="w-full max-h-screen pb-2 overflow-y-auto">
<NavHeader pageName={t('settings-project:title')} isProjectRelated />
<div className="flex flex-row justify-between items-center ml-6 my-8 text-xl max-w-5xl">
<div className="flex flex-col justify-start items-start text-3xl">
<p className="font-semibold mr-4 text-gray-200">{t('settings-project:title')}</p>
<p className="font-normal mr-4 text-gray-400 text-base">
{t('settings-project:description')}
</p>
</div>
</div>
<div className="flex flex-col ml-6 text-mineshaft-50">
<div className="flex flex-col">
<div className="min-w-md mt-2 flex flex-col items-start">
<div className="bg-white/5 rounded-md px-6 pb-4 flex flex-col items-start w-full mb-6 pt-2">
<p className="text-xl font-semibold mb-4 mt-2">{t('common:display-name')}</p>
<div className="max-h-28 w-full max-w-md mr-auto">
<InputField
label=""
onChangeHandler={modifyWorkspaceName}
type="varName"
value={workspaceName}
placeholder=""
isRequired
/>
</div>
<div className="flex justify-start w-full">
<div className="flex justify-start max-w-sm mt-4 mb-2">
<Button
text={t('common:save-changes') as string}
onButtonPressed={() => submitChanges(workspaceName)}
color="mineshaft"
size="md"
active={buttonReady}
iconDisabled={faCheck}
textDisabled="Saved"
/>
</div>
</div>
</div>
<div className="bg-white/5 rounded-md px-6 pb-4 flex flex-col items-start w-full mb-6 pt-2">
<p className="text-xl font-semibold mb-4 mt-2">{t('settings-project:auto-capitalization')}</p>
<Checkbox
className='data-[state=checked]:bg-primary'
id='autoCapitalization'
isChecked={autoCapitalization}
onCheckedChange={(state) => toggleAutoCapitalizationCheckBox(state as boolean)}
> {t('settings-project:auto-capitalization-description')}</Checkbox>
<div className="flex justify-start w-full">
<div className="flex justify-start max-w-sm mt-4 mb-2">
<Button
text={t('common:save-changes') as string}
onButtonPressed={() => submitAutoCapitalizationChanges()}
color="mineshaft"
size="md"
active={autoCapitalizationButtonReady}
iconDisabled={faCheck}
textDisabled="Saved"
/>
</div>
</div>
</div>
<div className="bg-white/5 rounded-md px-6 pt-4 pb-2 flex flex-col items-start w-full mb-6 mt-4">
<p className="text-xl font-semibold self-start">{t('common:project-id')}</p>
<p className="text-base text-gray-400 font-normal self-start mt-4">
{t('settings-project:project-id-description')}
</p>
<p className="text-base text-gray-400 font-normal self-start">
{t('settings-project:project-id-description2')}
{/* eslint-disable-next-line react/jsx-no-target-blank */}
<a
href="https://infisical.com/docs/getting-started/introduction"
target="_blank"
rel="noopener"
className="text-primary hover:opacity-80 duration-200"
>
{t('settings-project:docs')}
</a>
</p>
<p className="mt-4 text-xs text-bunker-300">
{t('settings-project:auto-generated')}
</p>
<div className="flex justify-end items-center bg-white/[0.07] text-base mt-2 mb-3 mr-2 rounded-md text-gray-400">
<p className="mr-2 font-bold pl-4">{`${t('common:project-id')}:`}</p>
<input
type="text"
value={workspaceId}
id="myInput"
className="bg-white/0 text-gray-400 py-2 w-60 px-2 min-w-md outline-none"
disabled
/>
<div className="group font-normal group relative inline-block text-gray-400 underline hover:text-primary duration-200">
<button
type="button"
onClick={copyToClipboard}
className="pl-4 pr-4 border-l border-white/20 py-2 hover:bg-white/[0.12] duration-200"
>
{projectIdCopied ? (
<FontAwesomeIcon icon={faCheck} className="pr-0.5" />
) : (
<FontAwesomeIcon icon={faCopy} />
)}
</button>
<span className="absolute hidden group-hover:flex group-hover:animate-popup duration-300 w-28 -left-8 -top-20 translate-y-full pl-3 py-2 bg-bunker-800 rounded-md text-center text-gray-400 text-sm">
{t('common:click-to-copy')}
</span>
</div>
</div>
</div>
<div className="bg-white/5 rounded-md px-6 pt-6 flex flex-col items-start w-full mt-4 mb-4">
<EnvironmentTable
data={environments}
onCreateEnv={onCreateEnvironment}
onUpdateEnv={onUpdateEnvironment}
onDeleteEnv={onDeleteEnvironment}
/>
</div>
<div className="bg-white/5 rounded-md px-6 flex flex-col items-start w-full mt-4 mb-4 pt-2">
<div className="flex flex-row justify-between w-full">
<div className="flex flex-col w-full">
<p className="text-xl font-semibold mb-3">
{t('section-token:service-tokens')}
</p>
<p className="text-sm text-gray-400">
{t('section-token:service-tokens-description')}
</p>
<p className="text-sm text-gray-400 mb-4">
Please, make sure you are on the
<a
className="text-primary underline underline-offset-2 ml-1"
href="https://infisical.com/docs/cli/overview"
target="_blank"
rel="noreferrer"
>
latest version of CLI
</a>
.
</p>
</div>
<div className="w-48 mt-2">
<Button
text={t('section-token:add-new') as string}
onButtonPressed={() => {
setIsAddServiceTokenDialogOpen(true);
}}
color="mineshaft"
icon={faPlus}
size="md"
/>
</div>
</div>
<ServiceTokenTable
data={serviceTokens}
workspaceName={workspaceName}
setServiceTokens={setServiceTokens as any}
/>
</div>
</div>
</div>
<div className="bg-white/5 rounded-md px-6 border-l border-red pl-6 flex flex-col items-start w-full mb-6 mt-4 pb-4 pt-2">
<p className="text-xl font-bold text-red">{t('settings-project:danger-zone')}</p>
<p className="mt-2 text-md text-gray-400">{t('settings-project:danger-zone-note')}</p>
<div className="max-h-28 w-full max-w-md mr-auto mt-4">
<InputField
label={t('settings-project:project-to-delete') as string}
onChangeHandler={setWorkspaceToBeDeletedName}
type="varName"
value={workspaceToBeDeletedName}
placeholder=""
isRequired
/>
</div>
<button
type="button"
className="max-w-md mt-6 w-full inline-flex justify-center rounded-md border border-transparent bg-gray-800 px-4 py-2.5 text-sm font-medium text-gray-400 hover:bg-red hover:text-white hover:font-semibold hover:text-semibold duration-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2"
onClick={executeDeletingWorkspace}
>
{t('settings-project:delete-project')}
</button>
<p className="mt-0.5 ml-1 text-xs text-gray-500">
{t('settings-project:delete-project-note')}
</p>
</div>
</div>
</div>
</div>
</div>
<ProjectSettingsPage />
</>
);
}
};
SettingsBasic.requireAuth = true;
export default ProjectSettings;
export const getServerSideProps = getTranslatedServerSideProps([
ProjectSettings.requireAuth = true;
export const getServerSideProps = getTranslatedStaticProps([
'settings',
'settings-project',
'section-token'
+7 -8
View File
@@ -8,7 +8,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import Button from '@app/components/basic/buttons/Button';
import AddProjectMemberDialog from '@app/components/basic/dialog/AddProjectMemberDialog';
import UserTable from '@app/components/basic/table/UserTable';
import ProjectUsersTable from '@app/components/basic/table/ProjectUsersTable';
import NavHeader from '@app/components/navigation/NavHeader';
import guidGenerator from '@app/components/utilities/randomId';
import { getTranslatedServerSideProps } from '@app/components/utilities/withTranslateProps';
@@ -33,6 +33,7 @@ interface UserProps {
}
interface MembershipProps {
deniedPermissions: any[];
user: UserProps;
inviteEmail: string;
role: string;
@@ -76,6 +77,7 @@ export default function Users() {
status: membership?.status,
userId: membership.user?._id,
membershipId: membership._id,
deniedPermissions: membership.deniedPermissions,
publicKey: membership.user?.publicKey
}));
setUserList(tempUserList);
@@ -144,7 +146,7 @@ export default function Users() {
};
return userList ? (
<div className="bg-bunker-800 md:h-screen flex flex-col justify-start">
<div className="bg-bunker-800 md:h-screen flex flex-col justify-start max-w-[calc(100vw-240px)]">
<Head>
<title>{t('common:head-title', { title: t('settings-members:title') })}</title>
<link rel="icon" href="/infisical.ico" />
@@ -168,7 +170,7 @@ export default function Users() {
setEmail={setEmail}
/>
{/* <DeleteUserDialog isOpen={isDeleteOpen} closeModal={closeDeleteModal} submitModal={deleteMembership} userIdToBeDeleted={userIdToBeDeleted}/> */}
<div className="px-6 pb-1 w-full flex flex-row items-start min-w-6xl max-w-6xl">
<div className="px-6 pb-1 w-full flex flex-row items-start">
<div className="h-10 w-full bg-white/5 mt-2 rounded-md flex flex-row items-center">
<FontAwesomeIcon
className="bg-white/5 rounded-l-md py-3 pl-4 pr-2 text-gray-400"
@@ -191,14 +193,12 @@ export default function Users() {
/>
</div>
</div>
<div className="block overflow-y-auto min-w-6xl max-w-6xl px-6">
<UserTable
<div className="block overflow-x-scroll px-6 pb-6 no-scrollbar no-scrollbar::-webkit-scrollbar">
<ProjectUsersTable
userData={userList}
changeData={setUserList}
myUser={personalEmail}
filter={searchUsers}
resendInvite={submitAddModal}
isOrg={false}
// onClick={openDeleteModal}
// deleteUser={deleteMembership}
// setUserIdToBeDeleted={setUserIdToBeDeleted}
@@ -207,7 +207,6 @@ export default function Users() {
</div>
) : (
<div className="relative z-10 w-10/12 mr-auto h-full ml-2 bg-bunker-800 flex flex-col items-center justify-center">
<div className="absolute top-0 bg-bunker h-14 border-b border-mineshaft-700 w-full" />
<Image src="/images/loading/loading.gif" height={70} width={120} alt="loading animation" />
</div>
);
+1 -1
View File
@@ -29,7 +29,7 @@ export default function VerifyEmail() {
<title>Login</title>
<link rel="icon" href="/infisical.ico" />
<meta property="og:image" content="/images/message.png" />
<meta property="og:title" content="Log In to Infisical" />
<meta property="og:title" content="Verify your email in Infisical" />
<meta
name="og:description"
content="Infisical a simple end-to-end encrypted platform that enables teams to sync and manage their .env files."