mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-15 10:35:17 +00:00
chore(frontend): fixed all eslint errors
This commit is contained in:
@@ -1,11 +1,10 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import Head from 'next/head';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
|
||||
import Plan from '~/components/billing/Plan';
|
||||
import NavHeader from '~/components/navigation/NavHeader';
|
||||
import { STRIPE_PRODUCT_PRO, STRIPE_PRODUCT_STARTER } from '~/utilities/config';
|
||||
import { getTranslatedServerSideProps } from '~/utilities/withTranslateProps';
|
||||
import Plan from '@app/components/billing/Plan';
|
||||
import NavHeader from '@app/components/navigation/NavHeader';
|
||||
import { STRIPE_PRODUCT_PRO, STRIPE_PRODUCT_STARTER } from '@app/components/utilities/config';
|
||||
import { getTranslatedServerSideProps } from '@app/components/utilities/withTranslateProps';
|
||||
|
||||
import getOrganizationSubscriptions from '../../api/organization/GetOrgSubscription';
|
||||
import getOrganizationUsers from '../../api/organization/GetOrgUsers';
|
||||
@@ -26,7 +25,7 @@ export default function SettingsBilling() {
|
||||
subtext: t('billing:starter.subtext')!,
|
||||
buttonTextMain: t('billing:downgrade')!,
|
||||
buttonTextSecondary: t('billing:learn-more')!,
|
||||
current: currentPlan == STRIPE_PRODUCT_STARTER,
|
||||
current: currentPlan === STRIPE_PRODUCT_STARTER
|
||||
},
|
||||
{
|
||||
key: 2,
|
||||
@@ -37,7 +36,7 @@ export default function SettingsBilling() {
|
||||
text: t('billing:professional.text')!,
|
||||
buttonTextMain: t('billing:upgrade')!,
|
||||
buttonTextSecondary: t('billing:learn-more')!,
|
||||
current: currentPlan == STRIPE_PRODUCT_PRO,
|
||||
current: currentPlan === STRIPE_PRODUCT_PRO
|
||||
},
|
||||
{
|
||||
key: 3,
|
||||
@@ -46,61 +45,53 @@ export default function SettingsBilling() {
|
||||
text: t('billing:enterprise.text')!,
|
||||
buttonTextMain: t('billing:schedule-demo')!,
|
||||
buttonTextSecondary: t('billing:learn-more')!,
|
||||
current: false,
|
||||
},
|
||||
current: false
|
||||
}
|
||||
];
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
const orgId = localStorage.getItem('orgData.id') as string;
|
||||
const subscriptions = await getOrganizationSubscriptions({
|
||||
orgId,
|
||||
orgId
|
||||
});
|
||||
|
||||
setCurrentPlan(subscriptions.data[0].plan.id);
|
||||
const orgUsers = await getOrganizationUsers({
|
||||
orgId,
|
||||
orgId
|
||||
});
|
||||
setNumUsers(orgUsers.length);
|
||||
})();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className='bg-bunker-800 max-h-screen flex flex-col justify-between text-white'>
|
||||
<div className="bg-bunker-800 max-h-screen flex flex-col justify-between text-white">
|
||||
<Head>
|
||||
<title>{t('common:head-title', { title: t('billing:title') })}</title>
|
||||
<link rel='icon' href='/infisical.ico' />
|
||||
<link rel="icon" href="/infisical.ico" />
|
||||
</Head>
|
||||
<div className='flex flex-row'>
|
||||
<div className='w-full max-h-screen pb-2 overflow-y-auto'>
|
||||
<div className="flex flex-row">
|
||||
<div className="w-full max-h-screen pb-2 overflow-y-auto">
|
||||
<NavHeader pageName={t('billing:title')} />
|
||||
<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('billing:title')}
|
||||
</p>
|
||||
<p className='font-normal mr-4 text-gray-400 text-base'>
|
||||
{t('billing:description')}
|
||||
</p>
|
||||
<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('billing:title')}</p>
|
||||
<p className="font-normal mr-4 text-gray-400 text-base">{t('billing:description')}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex flex-col ml-6 text-mineshaft-50'>
|
||||
<p className='text-xl font-semibold'>{t('billing:subscription')}</p>
|
||||
<div className='flex flex-row mt-4 overflow-x-auto'>
|
||||
<div className="flex flex-col ml-6 text-mineshaft-50">
|
||||
<p className="text-xl font-semibold">{t('billing:subscription')}</p>
|
||||
<div className="flex flex-row mt-4 overflow-x-auto">
|
||||
{plans.map((plan) => (
|
||||
<Plan key={plan.name} plan={plan} />
|
||||
))}
|
||||
</div>
|
||||
<p className='text-xl font-bold mt-12'>
|
||||
{t('billing:current-usage')}
|
||||
</p>
|
||||
<div className='flex flex-row'>
|
||||
<div className='mr-4 mt-8 text-gray-300 w-60 pt-6 pb-10 rounded-md bg-white/5 flex justify-center items-center flex flex-col'>
|
||||
<p className='text-6xl font-bold'>{numUsers}</p>
|
||||
<p className='text-gray-300'>
|
||||
{numUsers > 1
|
||||
? 'Organization members'
|
||||
: 'Organization member'}
|
||||
<p className="text-xl font-bold mt-12">{t('billing:current-usage')}</p>
|
||||
<div className="flex flex-row">
|
||||
<div className="mr-4 mt-8 text-gray-300 w-60 pt-6 pb-10 rounded-md bg-white/5 justify-center items-center flex flex-col">
|
||||
<p className="text-6xl font-bold">{numUsers}</p>
|
||||
<p className="text-gray-300">
|
||||
{numUsers > 1 ? 'Organization members' : 'Organization member'}
|
||||
</p>
|
||||
</div>
|
||||
{/* <div className="mr-4 mt-8 text-gray-300 w-60 pt-6 pb-10 rounded-md bg-white/5 flex justify-center items-center flex flex-col">
|
||||
@@ -117,7 +108,4 @@ export default function SettingsBilling() {
|
||||
|
||||
SettingsBilling.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps([
|
||||
'settings',
|
||||
'billing',
|
||||
]);
|
||||
export const getServerSideProps = getTranslatedServerSideProps(['settings', 'billing']);
|
||||
|
||||
@@ -1,24 +1,19 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
import { useEffect, useState } from 'react';
|
||||
import Head from 'next/head';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import {
|
||||
faMagnifyingGlass,
|
||||
faPlus,
|
||||
faX,
|
||||
} from '@fortawesome/free-solid-svg-icons';
|
||||
import { faCheck } from '@fortawesome/free-solid-svg-icons';
|
||||
import Button from '@app/components/basic/buttons/Button';
|
||||
import AddIncidentContactDialog from '@app/components/basic/dialog/AddIncidentContactDialog';
|
||||
import AddUserDialog from '@app/components/basic/dialog/AddUserDialog';
|
||||
import InputField from '@app/components/basic/InputField';
|
||||
import UserTable from '@app/components/basic/table/UserTable';
|
||||
import NavHeader from '@app/components/navigation/NavHeader';
|
||||
import guidGenerator from '@app/components/utilities/randomId';
|
||||
import { getTranslatedServerSideProps } from '@app/components/utilities/withTranslateProps';
|
||||
import { faCheck, faMagnifyingGlass, faPlus, faX } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
|
||||
import Button from '~/components/basic/buttons/Button';
|
||||
import AddIncidentContactDialog from '~/components/basic/dialog/AddIncidentContactDialog';
|
||||
import AddUserDialog from '~/components/basic/dialog/AddUserDialog';
|
||||
import InputField from '~/components/basic/InputField';
|
||||
import UserTable from '~/components/basic/table/UserTable';
|
||||
import NavHeader from '~/components/navigation/NavHeader';
|
||||
import guidGenerator from '~/utilities/randomId';
|
||||
import { getTranslatedServerSideProps } from '~/utilities/withTranslateProps';
|
||||
|
||||
import addUserToOrg from '../../api/organization/addUserToOrg';
|
||||
import deleteIncidentContact from '../../api/organization/deleteIncidentContact';
|
||||
import getIncidentContacts from '../../api/organization/getIncidentContacts';
|
||||
@@ -37,11 +32,8 @@ export default function SettingsOrg() {
|
||||
const [emailUser, setEmailUser] = useState('');
|
||||
const [workspaceToBeDeletedName, setWorkspaceToBeDeletedName] = useState('');
|
||||
const [searchUsers, setSearchUsers] = useState('');
|
||||
const [isAddIncidentContactOpen, setIsAddIncidentContactOpen] =
|
||||
useState(false);
|
||||
const [isAddUserOpen, setIsAddUserOpen] = useState(
|
||||
router.asPath.split('?')[1] == 'invite'
|
||||
);
|
||||
const [isAddIncidentContactOpen, setIsAddIncidentContactOpen] = useState(false);
|
||||
const [isAddUserOpen, setIsAddUserOpen] = useState(router.asPath.split('?')[1] === 'invite');
|
||||
const [incidentContacts, setIncidentContacts] = useState<string[]>([]);
|
||||
const [searchIncidentContact, setSearchIncidentContact] = useState('');
|
||||
const [userList, setUserList] = useState<any[]>([]);
|
||||
@@ -57,7 +49,7 @@ export default function SettingsOrg() {
|
||||
(async () => {
|
||||
const orgId = localStorage.getItem('orgData.id') as string;
|
||||
const org = await getOrganization({
|
||||
orgId,
|
||||
orgId
|
||||
});
|
||||
|
||||
setOrgName(org.name);
|
||||
@@ -65,33 +57,31 @@ export default function SettingsOrg() {
|
||||
localStorage.getItem('orgData.id') as string
|
||||
);
|
||||
|
||||
setIncidentContacts(
|
||||
incidentContactsData?.map((contact) => contact.email)
|
||||
);
|
||||
setIncidentContacts(incidentContactsData?.map((contact) => contact.email));
|
||||
|
||||
const user = await getUser();
|
||||
setPersonalEmail(user.email);
|
||||
|
||||
const orgUsers = await getOrganizationUsers({
|
||||
orgId,
|
||||
orgId
|
||||
});
|
||||
|
||||
setUserList(
|
||||
orgUsers.map((user) => ({
|
||||
orgUsers.map((orgUser) => ({
|
||||
key: guidGenerator(),
|
||||
firstName: user.user?.firstName,
|
||||
lastName: user.user?.lastName,
|
||||
email: user.user?.email == null ? user.inviteEmail : user.user?.email,
|
||||
role: user?.role,
|
||||
status: user?.status,
|
||||
userId: user.user?._id,
|
||||
membershipId: user._id,
|
||||
publicKey: user.user?.publicKey,
|
||||
firstName: orgUser.user?.firstName,
|
||||
lastName: orgUser.user?.lastName,
|
||||
email: orgUser.user?.email === null ? orgUser.inviteEmail : orgUser.user?.email,
|
||||
role: orgUser?.role,
|
||||
status: orgUser?.status,
|
||||
userId: orgUser.user?._id,
|
||||
membershipId: orgUser._id,
|
||||
publicKey: orgUser.user?.publicKey
|
||||
}))
|
||||
);
|
||||
|
||||
const subscriptions = await getOrganizationSubscriptions({
|
||||
orgId,
|
||||
orgId
|
||||
});
|
||||
setCurrentPlan(subscriptions.data[0].plan.product);
|
||||
})();
|
||||
@@ -107,37 +97,32 @@ export default function SettingsOrg() {
|
||||
setButtonReady(false);
|
||||
};
|
||||
|
||||
function closeAddUserModal() {
|
||||
const closeAddUserModal = () => {
|
||||
setIsAddUserOpen(false);
|
||||
}
|
||||
};
|
||||
|
||||
function closeAddIncidentContactModal() {
|
||||
const closeAddIncidentContactModal = () => {
|
||||
setIsAddIncidentContactOpen(false);
|
||||
}
|
||||
};
|
||||
|
||||
function openAddUserModal() {
|
||||
const openAddUserModal = () => {
|
||||
setIsAddUserOpen(true);
|
||||
}
|
||||
};
|
||||
|
||||
function openAddIncidentContactModal() {
|
||||
const openAddIncidentContactModal = () => {
|
||||
setIsAddIncidentContactOpen(true);
|
||||
}
|
||||
};
|
||||
|
||||
async function submitAddUserModal(email: string) {
|
||||
const submitAddUserModal = async (newUserEmail: string) => {
|
||||
await addUserToOrg(email, localStorage.getItem('orgData.id') as string);
|
||||
setEmail('');
|
||||
setIsAddUserOpen(false);
|
||||
router.reload();
|
||||
}
|
||||
};
|
||||
|
||||
const deleteIncidentContactFully = (incidentContact: string) => {
|
||||
setIncidentContacts(
|
||||
incidentContacts.filter((contact) => contact != incidentContact)
|
||||
);
|
||||
deleteIncidentContact(
|
||||
localStorage.getItem('orgData.id') as string,
|
||||
incidentContact
|
||||
);
|
||||
setIncidentContacts(incidentContacts.filter((contact) => contact !== incidentContact));
|
||||
deleteIncidentContact(localStorage.getItem('orgData.id') as string, incidentContact);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -151,69 +136,64 @@ export default function SettingsOrg() {
|
||||
|
||||
if (userWorkspaces.length > 1) {
|
||||
if (
|
||||
userWorkspaces.filter((workspace) => workspace._id == workspaceId)[0]
|
||||
.name == workspaceToBeDeletedName
|
||||
userWorkspaces.filter((workspace) => workspace._id === workspaceId)[0].name ===
|
||||
workspaceToBeDeletedName
|
||||
) {
|
||||
await deleteWorkspace(workspaceId);
|
||||
const userWorkspaces = await getWorkspaces();
|
||||
router.push('/dashboard/' + userWorkspaces[0]._id);
|
||||
const ws = await getWorkspaces();
|
||||
router.push(`/dashboard/${ws[0]._id}`);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className='bg-bunker-800 max-h-screen flex flex-col justify-between text-white'>
|
||||
<div className="bg-bunker-800 max-h-screen flex flex-col justify-between text-white">
|
||||
<Head>
|
||||
<title>
|
||||
{t('common:head-title', { title: t('settings-org:title') })}
|
||||
</title>
|
||||
<link rel='icon' href='/infisical.ico' />
|
||||
<title>{t('common:head-title', { title: t('settings-org:title') })}</title>
|
||||
<link rel="icon" href="/infisical.ico" />
|
||||
</Head>
|
||||
<div className='flex flex-row'>
|
||||
<div className='w-full max-h-screen pb-2 overflow-y-auto'>
|
||||
<div className="flex flex-row">
|
||||
<div className="w-full max-h-screen pb-2 overflow-y-auto">
|
||||
<NavHeader pageName={t('settings-org:title')} />
|
||||
<AddIncidentContactDialog
|
||||
isOpen={isAddIncidentContactOpen}
|
||||
closeModal={closeAddIncidentContactModal}
|
||||
workspaceId={workspaceId}
|
||||
incidentContacts={incidentContacts}
|
||||
setIncidentContacts={setIncidentContacts}
|
||||
/>
|
||||
<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-org:title')}
|
||||
</p>
|
||||
<p className='font-normal mr-4 text-gray-400 text-base'>
|
||||
<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-org:title')}</p>
|
||||
<p className="font-normal mr-4 text-gray-400 text-base">
|
||||
{t('settings-org:description')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex flex-col ml-6 text-mineshaft-50 mr-6 max-w-5xl'>
|
||||
<div className='flex flex-col'>
|
||||
<div className='min-w-md mt-2 flex flex-col items-end pb-4'>
|
||||
<div className='bg-white/5 rounded-md px-6 py-4 flex flex-col items-start w-full mb-6'>
|
||||
<div className='max-h-28 w-full max-w-md mr-auto'>
|
||||
<p className='font-semibold mr-4 text-gray-200 text-xl mb-2'>
|
||||
<div className="flex flex-col ml-6 text-mineshaft-50 mr-6 max-w-5xl">
|
||||
<div className="flex flex-col">
|
||||
<div className="min-w-md mt-2 flex flex-col items-end pb-4">
|
||||
<div className="bg-white/5 rounded-md px-6 py-4 flex flex-col items-start w-full mb-6">
|
||||
<div className="max-h-28 w-full max-w-md mr-auto">
|
||||
<p className="font-semibold mr-4 text-gray-200 text-xl mb-2">
|
||||
{t('common:display-name')}
|
||||
</p>
|
||||
<InputField
|
||||
label=''
|
||||
label=""
|
||||
// label="Organization Name"
|
||||
onChangeHandler={modifyOrgName}
|
||||
type='varName'
|
||||
type="varName"
|
||||
value={orgName}
|
||||
placeholder=''
|
||||
placeholder=""
|
||||
isRequired
|
||||
/>
|
||||
</div>
|
||||
<div className='flex justify-start w-full'>
|
||||
<div className={`flex justify-start max-w-sm mt-4 mb-2`}>
|
||||
<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(orgName)}
|
||||
color='mineshaft'
|
||||
size='md'
|
||||
color="mineshaft"
|
||||
size="md"
|
||||
active={buttonReady}
|
||||
iconDisabled={faCheck}
|
||||
textDisabled={t('common:saved') as string}
|
||||
@@ -223,11 +203,11 @@ export default function SettingsOrg() {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='bg-white/5 rounded-md px-6 pt-6 pb-2 flex flex-col items-start w-full mb-6'>
|
||||
<p className='font-semibold mr-4 text-white text-xl'>
|
||||
<div className="bg-white/5 rounded-md px-6 pt-6 pb-2 flex flex-col items-start w-full mb-6">
|
||||
<p className="font-semibold mr-4 text-white text-xl">
|
||||
{t('section-members:org-members')}
|
||||
</p>
|
||||
<p className='mr-4 text-gray-400 mt-2 mb-2'>
|
||||
<p className="mr-4 text-gray-400 mt-2 mb-2">
|
||||
{t('section-members:org-members-description')}
|
||||
</p>
|
||||
<AddUserDialog
|
||||
@@ -235,113 +215,107 @@ export default function SettingsOrg() {
|
||||
closeModal={closeAddUserModal}
|
||||
submitModal={submitAddUserModal}
|
||||
email={emailUser}
|
||||
workspaceId={workspaceId}
|
||||
setEmail={setEmailUser}
|
||||
currentPlan={currentPlan}
|
||||
orgName={orgName}
|
||||
/>
|
||||
{/* <DeleteUserDialog isOpen={isDeleteOpen} closeModal={closeDeleteModal} submitModal={deleteMembership} userIdToBeDeleted={userIdToBeDeleted}/> */}
|
||||
<div className='pb-1 w-full flex flex-row items-start max-w-6xl'>
|
||||
<div className='h-10 w-full bg-white/5 mt-2 flex items-center rounded-md flex-row '>
|
||||
<div className="pb-1 w-full flex flex-row items-start max-w-6xl">
|
||||
<div className="h-10 w-full bg-white/5 mt-2 flex items-center rounded-md flex-row ">
|
||||
<FontAwesomeIcon
|
||||
className='bg-white/5 rounded-l-md py-3 pl-4 pr-2 text-gray-400'
|
||||
className="bg-white/5 rounded-l-md py-3 pl-4 pr-2 text-gray-400"
|
||||
icon={faMagnifyingGlass}
|
||||
/>
|
||||
<input
|
||||
className='pl-2 text-gray-400 rounded-r-md bg-white/5 w-full h-full outline-none'
|
||||
className="pl-2 text-gray-400 rounded-r-md bg-white/5 w-full h-full outline-none"
|
||||
value={searchUsers}
|
||||
onChange={(e) => setSearchUsers(e.target.value)}
|
||||
placeholder={t('section-members:search-members') as string}
|
||||
/>
|
||||
</div>
|
||||
<div className='mt-2 ml-2 min-w-max flex flex-row items-start justify-start'>
|
||||
<div className="mt-2 ml-2 min-w-max flex flex-row items-start justify-start">
|
||||
<Button
|
||||
text={t('section-members:add-member') as string}
|
||||
onButtonPressed={openAddUserModal}
|
||||
color='mineshaft'
|
||||
size='md'
|
||||
color="mineshaft"
|
||||
size="md"
|
||||
icon={faPlus}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{userList && (
|
||||
<div className='overflow-y-auto max-w-6xl w-full'>
|
||||
<div className="overflow-y-auto max-w-6xl w-full">
|
||||
<UserTable
|
||||
userData={userList}
|
||||
changeData={setUserList}
|
||||
myUser={personalEmail}
|
||||
filter={searchUsers.toLowerCase()}
|
||||
resendInvite={submitAddUserModal}
|
||||
isOrg={true}
|
||||
isOrg
|
||||
// onClick={openDeleteModal}
|
||||
// deleteUser={deleteMembership}
|
||||
// setUserIdToBeDeleted={setUserIdToBeDeleted}
|
||||
className='w-full'
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className='bg-white/5 rounded-md px-6 pt-6 pb-6 flex flex-col items-start w-full mb-6 mt-4'>
|
||||
<div className='flex flex-row max-w-5xl justify-between items-center w-full'>
|
||||
<div className='flex flex-col justify-between w-full max-w-3xl'>
|
||||
<p className='text-xl font-semibold mb-3 min-w-max'>
|
||||
<div className="bg-white/5 rounded-md px-6 pt-6 pb-6 flex flex-col items-start w-full mb-6 mt-4">
|
||||
<div className="flex flex-row max-w-5xl justify-between items-center w-full">
|
||||
<div className="flex flex-col justify-between w-full max-w-3xl">
|
||||
<p className="text-xl font-semibold mb-3 min-w-max">
|
||||
{t('section-incident:incident-contacts')}
|
||||
</p>
|
||||
<p className='text-xs text-gray-500 mb-2 min-w-max'>
|
||||
<p className="text-xs text-gray-500 mb-2 min-w-max">
|
||||
{t('section-incident:incident-contacts-description')}
|
||||
</p>
|
||||
</div>
|
||||
<div className='mt-4 mb-2 min-w-max flex flex-row items-end justify-center'>
|
||||
<div className="mt-4 mb-2 min-w-max flex flex-row items-end justify-center">
|
||||
<Button
|
||||
text={t('section-incident:add-contact') as string}
|
||||
onButtonPressed={openAddIncidentContactModal}
|
||||
color='mineshaft'
|
||||
size='md'
|
||||
color="mineshaft"
|
||||
size="md"
|
||||
icon={faPlus}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className='h-12 w-full max-w-5xl bg-white/5 mt-2 flex items-center rounded-t-md flwex-row'>
|
||||
<div className="h-12 w-full max-w-5xl bg-white/5 mt-2 flex items-center rounded-t-md flwex-row">
|
||||
<FontAwesomeIcon
|
||||
className='bg-white/5 rounded-tl-md py-4 pl-4 pr-2 text-gray-400'
|
||||
className="bg-white/5 rounded-tl-md py-4 pl-4 pr-2 text-gray-400"
|
||||
icon={faMagnifyingGlass}
|
||||
/>
|
||||
<input
|
||||
className='pl-2 text-gray-400 rounded-tr-md bg-white/5 w-full h-full outline-none'
|
||||
className="pl-2 text-gray-400 rounded-tr-md bg-white/5 w-full h-full outline-none"
|
||||
value={searchIncidentContact}
|
||||
onChange={(e) => setSearchIncidentContact(e.target.value)}
|
||||
placeholder={t('common:search') as string}
|
||||
/>
|
||||
</div>
|
||||
{incidentContacts?.filter((email) =>
|
||||
email.includes(searchIncidentContact)
|
||||
{incidentContacts?.filter((incidentEmail) =>
|
||||
incidentEmail.includes(searchIncidentContact)
|
||||
).length > 0 ? (
|
||||
incidentContacts
|
||||
.filter((email) => email.includes(searchIncidentContact))
|
||||
.filter((incidentEmail) => incidentEmail.includes(searchIncidentContact))
|
||||
.map((contact) => (
|
||||
<div
|
||||
key={guidGenerator()}
|
||||
className='flex flex-row items-center justify-between max-w-5xl px-4 py-3 hover:bg-white/5 border-t border-gray-600 w-full'
|
||||
className="flex flex-row items-center justify-between max-w-5xl px-4 py-3 hover:bg-white/5 border-t border-gray-600 w-full"
|
||||
>
|
||||
<p className='text-gray-300'>{contact}</p>
|
||||
<div className='opacity-50 hover:opacity-100 duration-200'>
|
||||
<p className="text-gray-300">{contact}</p>
|
||||
<div className="opacity-50 hover:opacity-100 duration-200">
|
||||
<Button
|
||||
onButtonPressed={() =>
|
||||
deleteIncidentContactFully(contact)
|
||||
}
|
||||
color='red'
|
||||
size='icon-sm'
|
||||
onButtonPressed={() => deleteIncidentContactFully(contact)}
|
||||
color="red"
|
||||
size="icon-sm"
|
||||
icon={faX}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<div className='w-full flex flex-row justify-center mt-6 max-w-4xl ml-6'>
|
||||
<p className='text-gray-400'>
|
||||
{t('section-incident:no-incident-contacts')}
|
||||
</p>
|
||||
<div className="w-full flex flex-row justify-center mt-6 max-w-4xl ml-6">
|
||||
<p className="text-gray-400">{t('section-incident:no-incident-contacts')}</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -394,5 +368,5 @@ export const getServerSideProps = getTranslatedServerSideProps([
|
||||
'settings',
|
||||
'settings-org',
|
||||
'section-incident',
|
||||
'section-members',
|
||||
'section-members'
|
||||
]);
|
||||
|
||||
@@ -1,23 +1,22 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import Head from "next/head";
|
||||
import { useRouter } from "next/router";
|
||||
import { useTranslation } from "next-i18next";
|
||||
import { faCheck, faPlus, faX } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { useEffect, useState } from 'react';
|
||||
import Head from 'next/head';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import Button from '@app/components/basic/buttons/Button';
|
||||
import InputField from '@app/components/basic/InputField';
|
||||
import ListBox from '@app/components/basic/Listbox';
|
||||
import ApiKeyTable from '@app/components/basic/table/ApiKeyTable';
|
||||
import NavHeader from '@app/components/navigation/NavHeader';
|
||||
import passwordCheck from '@app/components/utilities/checks/PasswordCheck';
|
||||
import changePassword from '@app/components/utilities/cryptography/changePassword';
|
||||
import issueBackupKey from '@app/components/utilities/cryptography/issueBackupKey';
|
||||
import { getTranslatedServerSideProps } from '@app/components/utilities/withTranslateProps';
|
||||
import { faCheck, faPlus, faX } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
|
||||
import Button from "~/components/basic/buttons/Button";
|
||||
import InputField from "~/components/basic/InputField";
|
||||
import ListBox from "~/components/basic/Listbox";
|
||||
import ApiKeyTable from "~/components/basic/table/ApiKeyTable";
|
||||
import NavHeader from "~/components/navigation/NavHeader";
|
||||
import changePassword from "~/components/utilities/cryptography/changePassword";
|
||||
import issueBackupKey from "~/components/utilities/cryptography/issueBackupKey";
|
||||
import passwordCheck from "~/utilities/checks/PasswordCheck";
|
||||
import { getTranslatedServerSideProps } from "~/utilities/withTranslateProps";
|
||||
|
||||
import AddApiKeyDialog from "../../../components/basic/dialog/AddApiKeyDialog";
|
||||
import getAPIKeys from "../../api/apiKey/getAPIKeys";
|
||||
import getUser from "../../api/user/getUser";
|
||||
import AddApiKeyDialog from '../../../components/basic/dialog/AddApiKeyDialog';
|
||||
import getAPIKeys from '../../api/apiKey/getAPIKeys';
|
||||
import getUser from '../../api/user/getUser';
|
||||
|
||||
export default function PersonalSettings() {
|
||||
const [personalEmail, setPersonalEmail] = useState('');
|
||||
@@ -32,7 +31,7 @@ export default function PersonalSettings() {
|
||||
const [passwordChanged, setPasswordChanged] = useState(false);
|
||||
const [backupKeyIssued, setBackupKeyIssued] = useState(false);
|
||||
const [backupKeyError, setBackupKeyError] = useState(false);
|
||||
const [isAddApiKeyDialogOpen, setIsAddApiKeyDialogOpen] = useState(false)
|
||||
const [isAddApiKeyDialogOpen, setIsAddApiKeyDialogOpen] = useState(false);
|
||||
const [apiKeys, setApiKeys] = useState<any[]>([]);
|
||||
|
||||
const { t } = useTranslation();
|
||||
@@ -48,16 +47,14 @@ export default function PersonalSettings() {
|
||||
const load = async () => {
|
||||
try {
|
||||
const user = await getUser();
|
||||
setApiKeys(
|
||||
await getAPIKeys()
|
||||
);
|
||||
setApiKeys(await getAPIKeys());
|
||||
setPersonalEmail(user.email);
|
||||
setPersonalName(user.firstName + " " + user.lastName);
|
||||
setPersonalName(`${user.firstName} ${user.lastName}`);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
load();
|
||||
}, []);
|
||||
|
||||
@@ -66,12 +63,10 @@ export default function PersonalSettings() {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className='bg-bunker-800 max-h-screen flex flex-col justify-between text-white'>
|
||||
<div className="bg-bunker-800 max-h-screen flex flex-col justify-between text-white">
|
||||
<Head>
|
||||
<title>
|
||||
{t('common:head-title', { title: t('settings-personal:title') })}
|
||||
</title>
|
||||
<link rel='icon' href='/infisical.ico' />
|
||||
<title>{t('common:head-title', { title: t('settings-personal:title') })}</title>
|
||||
<link rel="icon" href="/infisical.ico" />
|
||||
</Head>
|
||||
<AddApiKeyDialog
|
||||
isOpen={isAddApiKeyDialogOpen}
|
||||
@@ -81,16 +76,11 @@ export default function PersonalSettings() {
|
||||
/>
|
||||
<div className="flex flex-row">
|
||||
<div className="w-full max-h-screen pb-2 overflow-y-auto">
|
||||
<NavHeader
|
||||
pageName={t('settings-personal:title')}
|
||||
isProjectRelated={false}
|
||||
/>
|
||||
<div className='flex flex-row justify-between items-center ml-6 mt-8 mb-6 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-personal:title')}
|
||||
</p>
|
||||
<p className='font-normal mr-4 text-gray-400 text-base'>
|
||||
<NavHeader pageName={t('settings-personal:title')} isProjectRelated={false} />
|
||||
<div className="flex flex-row justify-between items-center ml-6 mt-8 mb-6 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-personal:title')}</p>
|
||||
<p className="font-normal mr-4 text-gray-400 text-base">
|
||||
{t('settings-personal:description')}
|
||||
</p>
|
||||
</div>
|
||||
@@ -98,9 +88,9 @@ export default function PersonalSettings() {
|
||||
<div className="flex flex-col ml-6 text-mineshaft-50 mr-6 max-w-5xl">
|
||||
<div className="bg-white/5 rounded-md px-6 pt-6 pb-6 flex flex-col items-start w-full mb-6 mt-4">
|
||||
<p className="text-xl font-semibold self-start">
|
||||
{t("settings-personal:change-language")}
|
||||
{t('settings-personal:change-language')}
|
||||
</p>
|
||||
<div className='max-h-28 w-ful mt-4'>
|
||||
<div className="max-h-28 w-ful mt-4">
|
||||
<ListBox
|
||||
selected={lang}
|
||||
onChange={setLanguage}
|
||||
@@ -113,15 +103,15 @@ export default function PersonalSettings() {
|
||||
<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("settings-personal:api-keys.title")}
|
||||
{t('settings-personal:api-keys.title')}
|
||||
</p>
|
||||
<p className="text-sm text-gray-400">
|
||||
{t("settings-personal:api-keys.description")}
|
||||
{t('settings-personal:api-keys.description')}
|
||||
</p>
|
||||
</div>
|
||||
<div className="w-48 mt-2">
|
||||
<Button
|
||||
text={String(t("settings-personal:api-keys.add-new"))}
|
||||
text={String(t('settings-personal:api-keys.add-new'))}
|
||||
onButtonPressed={() => {
|
||||
setIsAddApiKeyDialogOpen(true);
|
||||
}}
|
||||
@@ -131,35 +121,32 @@ export default function PersonalSettings() {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<ApiKeyTable
|
||||
data={apiKeys}
|
||||
setApiKeys={setApiKeys as any}
|
||||
/>
|
||||
<ApiKeyTable data={apiKeys} setApiKeys={setApiKeys as any} />
|
||||
</div>
|
||||
|
||||
<div className='bg-white/5 rounded-md px-6 pt-5 pb-6 flex flex-col items-start w-full mb-6'>
|
||||
<div className='flex flex-row max-w-5xl justify-between items-center w-full'>
|
||||
<div className='flex flex-col justify-between w-full max-w-3xl'>
|
||||
<p className='text-xl font-semibold mb-3 min-w-max'>
|
||||
<div className="bg-white/5 rounded-md px-6 pt-5 pb-6 flex flex-col items-start w-full mb-6">
|
||||
<div className="flex flex-row max-w-5xl justify-between items-center w-full">
|
||||
<div className="flex flex-col justify-between w-full max-w-3xl">
|
||||
<p className="text-xl font-semibold mb-3 min-w-max">
|
||||
{t('section-password:change')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className='max-w-xl w-full'>
|
||||
<div className="max-w-xl w-full">
|
||||
<InputField
|
||||
label={t('section-password:current') as string}
|
||||
onChangeHandler={(password) => {
|
||||
setCurrentPassword(password);
|
||||
}}
|
||||
type='password'
|
||||
type="password"
|
||||
value={currentPassword}
|
||||
isRequired
|
||||
error={currentPasswordError}
|
||||
errorText={t('section-password:current-wrong') as string}
|
||||
autoComplete='current-password'
|
||||
id='current-password'
|
||||
autoComplete="current-password"
|
||||
id="current-password"
|
||||
/>
|
||||
<div className='py-2'></div>
|
||||
<div className="py-2" />
|
||||
<InputField
|
||||
label={t('section-password:new') as string}
|
||||
onChangeHandler={(password) => {
|
||||
@@ -169,39 +156,27 @@ export default function PersonalSettings() {
|
||||
setPasswordErrorLength,
|
||||
setPasswordErrorNumber,
|
||||
setPasswordErrorLowerCase,
|
||||
errorCheck: false,
|
||||
errorCheck: false
|
||||
});
|
||||
}}
|
||||
type='password'
|
||||
type="password"
|
||||
value={newPassword}
|
||||
isRequired
|
||||
error={
|
||||
passwordErrorLength &&
|
||||
passwordErrorLowerCase &&
|
||||
passwordErrorNumber
|
||||
}
|
||||
autoComplete='new-password'
|
||||
id='new-password'
|
||||
error={passwordErrorLength && passwordErrorLowerCase && passwordErrorNumber}
|
||||
autoComplete="new-password"
|
||||
id="new-password"
|
||||
/>
|
||||
</div>
|
||||
{passwordErrorLength ||
|
||||
passwordErrorLowerCase ||
|
||||
passwordErrorNumber ? (
|
||||
<div className='w-full mt-3 bg-white/5 px-2 flex flex-col items-start py-2 rounded-md max-w-xl mb-2'>
|
||||
<div className={`text-gray-400 text-sm mb-1`}>
|
||||
{passwordErrorLength || passwordErrorLowerCase || passwordErrorNumber ? (
|
||||
<div className="w-full mt-3 bg-white/5 px-2 flex flex-col items-start py-2 rounded-md max-w-xl mb-2">
|
||||
<div className="text-gray-400 text-sm mb-1">
|
||||
{t('section-password:validate-base')}
|
||||
</div>
|
||||
<div className='flex flex-row justify-start items-center ml-1'>
|
||||
<div className="flex flex-row justify-start items-center ml-1">
|
||||
{passwordErrorLength ? (
|
||||
<FontAwesomeIcon
|
||||
icon={faX}
|
||||
className='text-md text-red mr-2.5'
|
||||
/>
|
||||
<FontAwesomeIcon icon={faX} className="text-md text-red mr-2.5" />
|
||||
) : (
|
||||
<FontAwesomeIcon
|
||||
icon={faCheck}
|
||||
className='text-md text-primary mr-2'
|
||||
/>
|
||||
<FontAwesomeIcon icon={faCheck} className="text-md text-primary mr-2" />
|
||||
)}
|
||||
<div
|
||||
className={`${
|
||||
@@ -211,39 +186,25 @@ export default function PersonalSettings() {
|
||||
{t('section-password:validate-length')}
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex flex-row justify-start items-center ml-1'>
|
||||
<div className="flex flex-row justify-start items-center ml-1">
|
||||
{passwordErrorLowerCase ? (
|
||||
<FontAwesomeIcon
|
||||
icon={faX}
|
||||
className='text-md text-red mr-2.5'
|
||||
/>
|
||||
<FontAwesomeIcon icon={faX} className="text-md text-red mr-2.5" />
|
||||
) : (
|
||||
<FontAwesomeIcon
|
||||
icon={faCheck}
|
||||
className='text-md text-primary mr-2'
|
||||
/>
|
||||
<FontAwesomeIcon icon={faCheck} className="text-md text-primary mr-2" />
|
||||
)}
|
||||
<div
|
||||
className={`${
|
||||
passwordErrorLowerCase
|
||||
? 'text-gray-400'
|
||||
: 'text-gray-600'
|
||||
passwordErrorLowerCase ? 'text-gray-400' : 'text-gray-600'
|
||||
} text-sm`}
|
||||
>
|
||||
{t('section-password:validate-case')}
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex flex-row justify-start items-center ml-1'>
|
||||
<div className="flex flex-row justify-start items-center ml-1">
|
||||
{passwordErrorNumber ? (
|
||||
<FontAwesomeIcon
|
||||
icon={faX}
|
||||
className='text-md text-red mr-2.5'
|
||||
/>
|
||||
<FontAwesomeIcon icon={faX} className="text-md text-red mr-2.5" />
|
||||
) : (
|
||||
<FontAwesomeIcon
|
||||
icon={faCheck}
|
||||
className='text-md text-primary mr-2'
|
||||
/>
|
||||
<FontAwesomeIcon icon={faCheck} className="text-md text-primary mr-2" />
|
||||
)}
|
||||
<div
|
||||
className={`${
|
||||
@@ -255,17 +216,13 @@ export default function PersonalSettings() {
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className='py-2'></div>
|
||||
<div className="py-2" />
|
||||
)}
|
||||
<div className='flex flex-row items-center mt-3 w-52 pr-3'>
|
||||
<div className="flex flex-row items-center mt-3 w-52 pr-3">
|
||||
<Button
|
||||
text={t('section-password:change') as string}
|
||||
onButtonPressed={() => {
|
||||
if (
|
||||
!passwordErrorLength &&
|
||||
!passwordErrorLowerCase &&
|
||||
!passwordErrorNumber
|
||||
) {
|
||||
if (!passwordErrorLength && !passwordErrorLowerCase && !passwordErrorNumber) {
|
||||
changePassword(
|
||||
personalEmail,
|
||||
currentPassword,
|
||||
@@ -277,16 +234,12 @@ export default function PersonalSettings() {
|
||||
);
|
||||
}
|
||||
}}
|
||||
color='mineshaft'
|
||||
size='md'
|
||||
color="mineshaft"
|
||||
size="md"
|
||||
active={
|
||||
newPassword != '' &&
|
||||
currentPassword != '' &&
|
||||
!(
|
||||
passwordErrorLength ||
|
||||
passwordErrorLowerCase ||
|
||||
passwordErrorNumber
|
||||
)
|
||||
newPassword !== '' &&
|
||||
currentPassword !== '' &&
|
||||
!(passwordErrorLength || passwordErrorLowerCase || passwordErrorNumber)
|
||||
}
|
||||
textDisabled={t('section-password:change') as string}
|
||||
/>
|
||||
@@ -299,34 +252,34 @@ export default function PersonalSettings() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="bg-white/5 rounded-md px-6 pt-5 pb-6 mt-2 flex flex-col items-start flex flex-col items-start w-full mb-6">
|
||||
<div className="bg-white/5 rounded-md px-6 pt-5 pb-6 mt-2 flex flex-col items-start w-full mb-6">
|
||||
<div className="flex flex-row max-w-5xl justify-between items-center w-full">
|
||||
<div className="flex flex-col justify-between w-full max-w-3xl">
|
||||
<p className="text-xl font-semibold mb-3 min-w-max">
|
||||
{t("settings-personal:emergency.name")}
|
||||
{t('settings-personal:emergency.name')}
|
||||
</p>
|
||||
<p className='text-sm text-mineshaft-300 min-w-max'>
|
||||
<p className="text-sm text-mineshaft-300 min-w-max">
|
||||
{t('settings-personal:emergency.text1')}
|
||||
</p>
|
||||
<p className='text-sm text-mineshaft-300 mb-5 min-w-max'>
|
||||
<p className="text-sm text-mineshaft-300 mb-5 min-w-max">
|
||||
{t('settings-personal:emergency.text2')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className='w-full max-w-xl mb-4'>
|
||||
<div className="w-full max-w-xl mb-4">
|
||||
<InputField
|
||||
label={t('section-password:current') as string}
|
||||
onChangeHandler={setBackupPassword}
|
||||
type='password'
|
||||
type="password"
|
||||
value={backupPassword}
|
||||
isRequired
|
||||
error={backupKeyError}
|
||||
errorText={t('section-password:current-wrong') as string}
|
||||
autoComplete='current-password'
|
||||
id='current-password'
|
||||
autoComplete="current-password"
|
||||
id="current-password"
|
||||
/>
|
||||
</div>
|
||||
<div className='flex flex-row items-center mt-3 w-60'>
|
||||
<div className="flex flex-row items-center mt-3 w-60">
|
||||
<Button
|
||||
text={t('settings-personal:emergency.download') as string}
|
||||
onButtonPressed={() => {
|
||||
@@ -335,15 +288,13 @@ export default function PersonalSettings() {
|
||||
password: backupPassword,
|
||||
personalName,
|
||||
setBackupKeyError,
|
||||
setBackupKeyIssued,
|
||||
setBackupKeyIssued
|
||||
});
|
||||
}}
|
||||
color='mineshaft'
|
||||
size='md'
|
||||
active={backupPassword != ''}
|
||||
textDisabled={
|
||||
t('settings-personal:emergency.download') as string
|
||||
}
|
||||
color="mineshaft"
|
||||
size="md"
|
||||
active={backupPassword !== ''}
|
||||
textDisabled={t('settings-personal:emergency.download') as string}
|
||||
/>
|
||||
<FontAwesomeIcon
|
||||
icon={faCheck}
|
||||
@@ -363,8 +314,8 @@ export default function PersonalSettings() {
|
||||
PersonalSettings.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps([
|
||||
"settings",
|
||||
"settings-personal",
|
||||
"section-password",
|
||||
"section-api-key"
|
||||
'settings',
|
||||
'settings-personal',
|
||||
'section-password',
|
||||
'section-api-key'
|
||||
]);
|
||||
|
||||
@@ -2,19 +2,18 @@ import { useEffect, useState } from 'react';
|
||||
import Head from 'next/head';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
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 deleteEnvironment from '@app/pages/api/environments/deleteEnvironment';
|
||||
import updateEnvironment from '@app/pages/api/environments/updateEnvironment';
|
||||
import { faCheck, faCopy, faPlus } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
|
||||
import Button from '~/components/basic/buttons/Button';
|
||||
import AddServiceTokenDialog from '~/components/basic/dialog/AddServiceTokenDialog';
|
||||
import InputField from '~/components/basic/InputField';
|
||||
import EnvironmentTable from '~/components/basic/table/EnvironmentsTable';
|
||||
import ServiceTokenTable from '~/components/basic/table/ServiceTokenTable';
|
||||
import NavHeader from '~/components/navigation/NavHeader';
|
||||
import deleteEnvironment from '~/pages/api/environments/deleteEnvironment';
|
||||
import updateEnvironment from '~/pages/api/environments/updateEnvironment';
|
||||
import { getTranslatedServerSideProps } from '~/utilities/withTranslateProps';
|
||||
|
||||
import createEnvironment from '../../api/environments/createEnvironment';
|
||||
import getServiceTokens from '../../api/serviceToken/getServiceTokens';
|
||||
import deleteWorkspace from '../../api/workspace/deleteWorkspace';
|
||||
@@ -33,9 +32,8 @@ export default function SettingsBasic() {
|
||||
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 [isAddOpen, setIsAddOpen] = useState(false);
|
||||
const [isAddServiceTokenDialogOpen, setIsAddServiceTokenDialogOpen] = useState(false);
|
||||
const [projectIdCopied, setProjectIdCopied] = useState(false);
|
||||
const workspaceId = router.query.id as string;
|
||||
|
||||
@@ -62,13 +60,13 @@ export default function SettingsBasic() {
|
||||
const load = async () => {
|
||||
const userWorkspaces = await getWorkspaces();
|
||||
userWorkspaces.forEach((userWorkspace) => {
|
||||
if (userWorkspace._id == workspaceId) {
|
||||
if (userWorkspace._id === workspaceId) {
|
||||
setWorkspaceName(userWorkspace.name);
|
||||
setEnvironments(userWorkspace.environments);
|
||||
}
|
||||
});
|
||||
const tempServiceTokens = await getServiceTokens({
|
||||
workspaceId,
|
||||
workspaceId
|
||||
});
|
||||
setServiceTokens(tempServiceTokens);
|
||||
};
|
||||
@@ -101,12 +99,12 @@ export default function SettingsBasic() {
|
||||
|
||||
if (userWorkspaces.length > 1) {
|
||||
if (
|
||||
userWorkspaces.filter((workspace) => workspace._id === workspaceId)[0]
|
||||
.name == workspaceToBeDeletedName
|
||||
userWorkspaces.filter((workspace) => workspace._id === workspaceId)[0].name ===
|
||||
workspaceToBeDeletedName
|
||||
) {
|
||||
await deleteWorkspace(workspaceId);
|
||||
const userWorkspaces = await getWorkspaces();
|
||||
router.push('/dashboard/' + userWorkspaces[0]._id);
|
||||
const ws = await getWorkspaces();
|
||||
router.push(`/dashboard/${ws[0]._id}`);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -114,7 +112,7 @@ export default function SettingsBasic() {
|
||||
const onCreateEnvironment = async ({ name, slug }: EnvData) => {
|
||||
const res = await createEnvironment(workspaceId, {
|
||||
environmentName: name,
|
||||
environmentSlug: slug,
|
||||
environmentSlug: slug
|
||||
});
|
||||
if (res) {
|
||||
// TODO: on react-query migration do an api call to resync
|
||||
@@ -122,20 +120,15 @@ export default function SettingsBasic() {
|
||||
}
|
||||
};
|
||||
|
||||
const onUpdateEnvironment = async (
|
||||
oldSlug: string,
|
||||
{ name, slug }: EnvData
|
||||
) => {
|
||||
const onUpdateEnvironment = async (oldSlug: string, { name, slug }: EnvData) => {
|
||||
const res = await updateEnvironment(workspaceId, {
|
||||
oldEnvironmentSlug: oldSlug,
|
||||
environmentName: name,
|
||||
environmentSlug: slug,
|
||||
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))
|
||||
);
|
||||
setEnvironments((env) => env.map((el) => (el.slug === oldSlug ? { name, slug } : el)));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -143,19 +136,15 @@ export default function SettingsBasic() {
|
||||
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)
|
||||
);
|
||||
setEnvironments((env) => env.filter(({ slug }) => slug !== slugToBeDelete));
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className='bg-bunker-800 max-h-screen flex flex-col justify-between text-white'>
|
||||
<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' />
|
||||
<title>{t('common:head-title', { title: t('settings-project:title') })}</title>
|
||||
<link rel="icon" href="/infisical.ico" />
|
||||
</Head>
|
||||
<AddServiceTokenDialog
|
||||
isOpen={isAddServiceTokenDialogOpen}
|
||||
@@ -166,104 +155,94 @@ export default function SettingsBasic() {
|
||||
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={true}
|
||||
/>
|
||||
<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'>
|
||||
<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 pt-6 pb-4 flex flex-col items-start 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'>
|
||||
<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=''
|
||||
label=""
|
||||
onChangeHandler={modifyWorkspaceName}
|
||||
type='varName'
|
||||
type="varName"
|
||||
value={workspaceName}
|
||||
placeholder=''
|
||||
placeholder=""
|
||||
isRequired
|
||||
/>
|
||||
</div>
|
||||
<div className='flex justify-start w-full'>
|
||||
<div className={`flex justify-start max-w-sm mt-4 mb-2`}>
|
||||
<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'
|
||||
color="mineshaft"
|
||||
size="md"
|
||||
active={buttonReady}
|
||||
iconDisabled={faCheck}
|
||||
textDisabled='Saved'
|
||||
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'>
|
||||
<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'>
|
||||
<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'
|
||||
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'>
|
||||
<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>
|
||||
<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'
|
||||
type="text"
|
||||
value={workspaceId}
|
||||
id='myInput'
|
||||
className='bg-white/0 text-gray-400 py-2 w-60 px-2 min-w-md outline-none'
|
||||
id="myInput"
|
||||
className="bg-white/0 text-gray-400 py-2 w-60 px-2 min-w-md outline-none"
|
||||
disabled
|
||||
></input>
|
||||
<div className='group font-normal group relative inline-block text-gray-400 underline hover:text-primary duration-200'>
|
||||
/>
|
||||
<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'
|
||||
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={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'>
|
||||
<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'>
|
||||
<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}
|
||||
@@ -271,37 +250,37 @@ export default function SettingsBasic() {
|
||||
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'>
|
||||
<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'>
|
||||
<p className="text-sm text-gray-400">
|
||||
{t('section-token:service-tokens-description')}
|
||||
</p>
|
||||
<p className='text-sm text-gray-400 mb-4'>
|
||||
<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'
|
||||
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'>
|
||||
<div className="w-48 mt-2">
|
||||
<Button
|
||||
text={t('section-token:add-new') as string}
|
||||
onButtonPressed={() => {
|
||||
setIsAddServiceTokenDialogOpen(true);
|
||||
}}
|
||||
color='mineshaft'
|
||||
color="mineshaft"
|
||||
icon={faPlus}
|
||||
size='md'
|
||||
size="md"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -313,31 +292,27 @@ export default function SettingsBasic() {
|
||||
</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'>
|
||||
<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'
|
||||
type="varName"
|
||||
value={workspaceToBeDeletedName}
|
||||
placeholder=''
|
||||
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'
|
||||
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'>
|
||||
<p className="mt-0.5 ml-1 text-xs text-gray-500">
|
||||
{t('settings-project:delete-project-note')}
|
||||
</p>
|
||||
</div>
|
||||
@@ -353,5 +328,5 @@ SettingsBasic.requireAuth = true;
|
||||
export const getServerSideProps = getTranslatedServerSideProps([
|
||||
'settings',
|
||||
'settings-project',
|
||||
'section-token',
|
||||
'section-token'
|
||||
]);
|
||||
|
||||
Reference in New Issue
Block a user