lots of frontend improvements

This commit is contained in:
Vladyslav Matsiiako
2023-06-09 12:50:17 -07:00
parent 00fae0023a
commit 2bae6cf084
24 changed files with 221 additions and 227 deletions
+3 -1
View File
@@ -28,6 +28,7 @@ interface FeatureSet {
customRateLimits: boolean; customRateLimits: boolean;
customAlerts: boolean; customAlerts: boolean;
auditLogs: boolean; auditLogs: boolean;
envLimit?: number | null;
} }
/** /**
@@ -55,7 +56,8 @@ class EELicenseService {
rbac: true, rbac: true,
customRateLimits: true, customRateLimits: true,
customAlerts: true, customAlerts: true,
auditLogs: false auditLogs: false,
envLimit: null
} }
public localFeatureSet: NodeCache; public localFeatureSet: NodeCache;
@@ -53,7 +53,7 @@ const AddProjectMemberDialog = ({
leaveFrom="opacity-100 scale-100" leaveFrom="opacity-100 scale-100"
leaveTo="opacity-0 scale-95" leaveTo="opacity-0 scale-95"
> >
<Dialog.Panel className="w-full max-w-md transform rounded-md border border-gray-700 bg-bunker-800 p-6 text-left align-middle shadow-xl transition-all"> <Dialog.Panel className="w-full max-w-md transform rounded-md border border-mineshaft-600 bg-mineshaft-800 p-6 text-left align-middle shadow-xl transition-all">
{data?.length > 0 ? ( {data?.length > 0 ? (
<Dialog.Title <Dialog.Title
as="h3" as="h3"
@@ -64,7 +64,7 @@ const AddProjectMemberDialog = ({
) : ( ) : (
<Dialog.Title <Dialog.Title
as="h3" as="h3"
className="z-50 text-lg font-medium leading-6 text-gray-400" className="z-50 text-lg font-medium text-mineshaft-300 mb-4"
> >
{t('section.members.add-dialog.already-all-invited')} {t('section.members.add-dialog.already-all-invited')}
</Dialog.Title> </Dialog.Title>
@@ -25,6 +25,7 @@ type Props = {
changeData: (users: any[]) => void; changeData: (users: any[]) => void;
myUser: string; myUser: string;
filter: string; filter: string;
isUserListLoading: boolean;
}; };
type EnvironmentProps = { type EnvironmentProps = {
@@ -38,7 +39,7 @@ type EnvironmentProps = {
* @param {*} props * @param {*} props
* @returns * @returns
*/ */
const ProjectUsersTable = ({ userData, changeData, myUser, filter }: Props) => { const ProjectUsersTable = ({ userData, changeData, myUser, filter, isUserListLoading }: Props) => {
const [roleSelected, setRoleSelected] = useState( const [roleSelected, setRoleSelected] = useState(
Array(userData?.length).fill(userData.map((user) => user.role)) Array(userData?.length).fill(userData.map((user) => user.role))
); );
@@ -205,7 +206,7 @@ const ProjectUsersTable = ({ userData, changeData, myUser, filter }: Props) => {
}; };
return ( return (
<div className="table-container relative mb-6 mt-1 min-w-max rounded-md border border-mineshaft-700 bg-bunker"> <div className="table-container relative mb-6 mt-1 min-w-max rounded-md border border-mineshaft-600 bg-bunker">
<div className="absolute h-[3.1rem] w-full rounded-t-md bg-white/5" /> <div className="absolute h-[3.1rem] w-full rounded-t-md bg-white/5" />
<UpgradePlanModal <UpgradePlanModal
isOpen={isUpgradeModalOpen} isOpen={isUpgradeModalOpen}
@@ -213,7 +214,7 @@ const ProjectUsersTable = ({ userData, changeData, myUser, filter }: Props) => {
text="You can change user permissions if you switch to Infisical's Professional plan." text="You can change user permissions if you switch to Infisical's Professional plan."
/> />
<table className="my-0.5 w-full"> <table className="my-0.5 w-full">
<thead className="text-xs font-light text-gray-400"> <thead className="text-xs font-light text-gray-400 bg-mineshaft-800">
<tr> <tr>
<th className="py-3.5 pl-4 text-left">NAME</th> <th className="py-3.5 pl-4 text-left">NAME</th>
<th className="py-3.5 pl-4 text-left">EMAIL</th> <th className="py-3.5 pl-4 text-left">EMAIL</th>
@@ -231,7 +232,7 @@ const ProjectUsersTable = ({ userData, changeData, myUser, filter }: Props) => {
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{userData?.filter( {!isUserListLoading && userData?.filter(
(user) => (user) =>
user.firstName?.toLowerCase().includes(filter) || user.firstName?.toLowerCase().includes(filter) ||
user.lastName?.toLowerCase().includes(filter) || user.lastName?.toLowerCase().includes(filter) ||
@@ -245,14 +246,14 @@ const ProjectUsersTable = ({ userData, changeData, myUser, filter }: Props) => {
user.email?.toLowerCase().includes(filter) user.email?.toLowerCase().includes(filter)
) )
.map((row, index) => ( .map((row, index) => (
<tr key={guidGenerator()} className="bg-bunker-600 text-sm hover:bg-bunker-500"> <tr key={guidGenerator()} className="bg-mineshaft-800 text-sm">
<td className="border-t border-mineshaft-700 py-2 pl-4 text-gray-300"> <td className="border-t border-mineshaft-600 py-2 pl-4 text-gray-300">
{row.firstName} {row.lastName} {row.firstName} {row.lastName}
</td> </td>
<td className="border-t border-mineshaft-700 py-2 pl-4 text-gray-300"> <td className="border-t border-mineshaft-600 py-2 pl-4 text-gray-300">
{row.email} {row.email}
</td> </td>
<td className="border-t border-mineshaft-700 py-2 pl-6 pr-10 text-gray-300"> <td className="border-t border-mineshaft-600 py-2 pl-6 pr-10 text-gray-300">
<div className="flex h-full flex-row items-center justify-start"> <div className="flex h-full flex-row items-center justify-start">
<Select <Select
className="w-36 bg-mineshaft-700" className="w-36 bg-mineshaft-700"
@@ -391,6 +392,10 @@ const ProjectUsersTable = ({ userData, changeData, myUser, filter }: Props) => {
</td> </td>
</tr> </tr>
))} ))}
{isUserListLoading && <>
<tr key={guidGenerator()} className="bg-mineshaft-800 text-sm animate-pulse h-14 w-full"/>
<tr key={guidGenerator()} className="bg-mineshaft-800 text-sm animate-pulse h-14 w-full"/>
</>}
</tbody> </tbody>
</table> </table>
</div> </div>
@@ -21,7 +21,7 @@ export const EmptyState = ({
}: Props) => ( }: Props) => (
<div <div
className={twMerge( className={twMerge(
'flex w-full flex-col items-center bg-bunker-700 px-2 pt-6 text-bunker-300', 'flex w-full flex-col items-center bg-mineshaft-800 px-2 pt-6 text-bunker-300',
className className
)} )}
> >
+6 -6
View File
@@ -16,8 +16,8 @@ export const TableContainer = ({
}: TableContainerProps): JSX.Element => ( }: TableContainerProps): JSX.Element => (
<div <div
className={twMerge( className={twMerge(
'relative w-full overflow-x-auto border border-solid border-mineshaft-700 bg-mineshaft-800 font-inter shadow-md', 'relative w-full overflow-x-auto border border-solid border-mineshaft-700 bg-mineshaft-800 font-inter',
isRounded && 'rounded-md', isRounded && 'rounded-lg',
className className
)} )}
> >
@@ -34,7 +34,7 @@ export type TableProps = {
export const Table = ({ children, className }: TableProps): JSX.Element => ( export const Table = ({ children, className }: TableProps): JSX.Element => (
<table <table
className={twMerge( className={twMerge(
'w-full rounded-md bg-bunker-800 p-2 text-left text-sm text-gray-300', 'w-full bg-mineshaft-800 p-2 text-left text-sm text-gray-300',
className className
)} )}
> >
@@ -49,7 +49,7 @@ export type THeadProps = {
}; };
export const THead = ({ children, className }: THeadProps): JSX.Element => ( export const THead = ({ children, className }: THeadProps): JSX.Element => (
<thead className={twMerge('bg-bunker text-xs uppercase text-bunker-300', className)}> <thead className={twMerge('bg-mineshaft-800 text-xs uppercase text-bunker-300', className)}>
{children} {children}
</thead> </thead>
); );
@@ -62,7 +62,7 @@ export type TrProps = {
export const Tr = ({ children, className, ...props }: TrProps): JSX.Element => ( export const Tr = ({ children, className, ...props }: TrProps): JSX.Element => (
<tr <tr
className={twMerge('border border-solid border-mineshaft-700 hover:bg-bunker-700', className)} className={twMerge('border border-solid border-mineshaft-700 cursor-default', className)}
{...props} {...props}
> >
{children} {children}
@@ -76,7 +76,7 @@ export type ThProps = {
}; };
export const Th = ({ children, className }: ThProps): JSX.Element => ( export const Th = ({ children, className }: ThProps): JSX.Element => (
<th className={twMerge('bg-bunker-500 px-5 pt-4 pb-3.5 font-semibold', className)}>{children}</th> <th className={twMerge('bg-mineshaft-800 px-5 pt-4 pb-3.5 font-semibold border-b-2 border-mineshaft-600', className)}>{children}</th>
); );
// table body // table body
@@ -18,7 +18,7 @@ export const UpgradePlanModal = ({ text, isOpen, onOpenChange }: Props): JSX.Ele
href={`/settings/billing/${localStorage.getItem('projectData.id') as string}`} href={`/settings/billing/${localStorage.getItem('projectData.id') as string}`}
key="upgrade-plan" key="upgrade-plan"
> >
<Button className="mr-4 ml-2">Upgrade Plan</Button> <Button className="mr-4 ml-2 mb-2">Upgrade Plan</Button>
</Link>, </Link>,
<ModalClose asChild key="upgrade-plan-cancel"> <ModalClose asChild key="upgrade-plan-cancel">
<Button colorSchema="secondary" variant="plain"> <Button colorSchema="secondary" variant="plain">
@@ -1,14 +1,13 @@
import { createContext, ReactNode, useContext, useMemo } from 'react'; import { createContext, ReactNode, useContext, useMemo } from 'react';
import { useGetOrgSubscription } from '@app/hooks/api'; import { useGetOrgSubscription } from '@app/hooks/api';
import { GetSubscriptionPlan } from '@app/hooks/api/types'; import { SubscriptionPlan } from '@app/hooks/api/types';
import { useWorkspace } from '../WorkspaceContext'; import { useWorkspace } from '../WorkspaceContext';
// import { Subscription } from '@app/hooks/api/workspace/types'; // import { Subscription } from '@app/hooks/api/workspace/types';
type TSubscriptionContext = { type TSubscriptionContext = {
subscription?: GetSubscriptionPlan; subscription?: SubscriptionPlan;
subscriptionPlan: string;
isLoading: boolean; isLoading: boolean;
}; };
@@ -28,7 +27,6 @@ export const SubscriptionProvider = ({ children }: Props): JSX.Element => {
const value = useMemo<TSubscriptionContext>( const value = useMemo<TSubscriptionContext>(
() => ({ () => ({
subscription: data, subscription: data,
subscriptionPlan: data?.data?.[0]?.plan?.product || '',
isLoading isLoading
}), }),
[data, isLoading] [data, isLoading]
+89 -83
View File
@@ -1,7 +1,6 @@
/* eslint-disable jsx-a11y/no-noninteractive-element-interactions */ /* eslint-disable jsx-a11y/no-noninteractive-element-interactions */
import React, { useState } from 'react'; import React, { useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import Image from 'next/image';
import { faAngleDown, faAngleRight, faUpRightFromSquare } from '@fortawesome/free-solid-svg-icons'; import { faAngleDown, faAngleRight, faUpRightFromSquare } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
@@ -48,7 +47,7 @@ const ActivityLogsRow = ({
const { t } = useTranslation(); const { t } = useTranslation();
const renderUser = () => { const renderUser = () => {
if (row?.user) return `User: ${row.user}`; if (row?.user) return `${row.user}`;
if (row?.serviceAccount) return `Service Account: ${row.serviceAccount.name}`; if (row?.serviceAccount) return `Service Account: ${row.serviceAccount.name}`;
if (row?.serviceTokenData.name) return `Service Token: ${row.serviceTokenData.name}`; if (row?.serviceTokenData.name) return `Service Token: ${row.serviceTokenData.name}`;
@@ -56,71 +55,77 @@ const ActivityLogsRow = ({
}; };
return ( return (
<> <>
<tr key={guidGenerator()} className="w-full bg-bunker-800 text-sm duration-100"> <div key={guidGenerator()} className="w-full bg-mineshaft-800 text-sm text-mineshaft-200 duration-100 flex flex-row items-center">
<td <button
onKeyDown={() => null} type="button"
onClick={() => setPayloadOpened(!payloadOpened)} onClick={() => setPayloadOpened(!payloadOpened)}
className="flex cursor-pointer items-center border-t border-mineshaft-700 text-gray-300" className="border-t border-mineshaft-700 pt-[0.58rem]"
> >
<FontAwesomeIcon <FontAwesomeIcon
icon={payloadOpened ? faAngleDown : faAngleRight} icon={payloadOpened ? faAngleDown : faAngleRight}
className={`mt-2.5 ml-6 text-bunker-100 hover:bg-mineshaft-700 ${ className={`ml-6 mb-2 text-mineshaft-300 cursor-pointer ${
payloadOpened && 'bg-mineshaft-500' payloadOpened ? 'bg-mineshaft-500 hover:bg-mineshaft-500' : 'hover:bg-mineshaft-700'
} h-4 w-4 rounded-md p-1 duration-100`} } h-4 w-4 rounded-md p-1 duration-100`}
/> />
</td> </button>
<td className="border-t border-mineshaft-700 py-3 text-gray-300"> <div className="border-t border-mineshaft-700 py-3 w-1/4 pl-6">
{row.payload {row.payload
?.map( ?.map(
(action) => (action) =>
`${String(action.secretVersions.length)} ${t(`activity.event.${action.name}`)}` `${String(action.secretVersions.length)} ${t(`activity.event.${action.name}`)}`
) )
.join(' and ')} .join(' and ')}
</td> </div>
<td className="border-t border-mineshaft-700 py-3 pl-6 text-gray-300">{renderUser()}</td> <div className="border-t border-mineshaft-700 py-3 pl-6 w-1/4">{renderUser()}</div>
<td className="border-t border-mineshaft-700 py-3 pl-6 text-gray-300">{row.channel}</td> <div className="border-t border-mineshaft-700 py-3 pl-6 w-1/4">{row.channel}</div>
<td className="border-t border-mineshaft-700 py-3 pl-6 text-gray-300"> <div className="border-t border-mineshaft-700 py-3 pl-6 w-1/4">
{timeSince(new Date(row.createdAt))} {timeSince(new Date(row.createdAt))}
</td> </div>
</tr> </div>
{payloadOpened && ( {payloadOpened && (
<tr className="h-9 border-t border-mineshaft-700 text-sm text-bunker-200"> <div className="h-9 border-t border-mineshaft-700 text-sm text-bunker-200 bg-mineshaft-900/50 w-full flex flex-row items-center">
<td /> <div className='max-w-xl w-full flex flex-row items-center'>
<td>{String(t('common.timestamp'))}</td> <div className='w-24' />
<td>{row.createdAt}</td> <div className='w-1/2'>{String(t('common.timestamp'))}</div>
</tr> <div className='w-1/2'>{row.createdAt}</div>
</div>
</div>
)} )}
{payloadOpened && {payloadOpened &&
row.payload?.map( row.payload?.map(
(action) => (action) =>
action.secretVersions.length > 0 && ( action.secretVersions.length > 0 && (
<tr <div
key={action._id} key={action.name}
className="h-9 border-t border-mineshaft-700 text-sm text-bunker-200" className="h-9 border-t border-mineshaft-700 text-sm text-bunker-200 bg-mineshaft-900/50 w-full flex flex-row items-center"
> >
<td /> <div className='max-w-xl w-full flex flex-row items-center'>
<td className="">{t(`activity.event.${action.name}`)}</td> <div className='w-24' />
<td <div className='w-1/2'>{t(`activity.event.${action.name}`)}</div>
onKeyDown={() => null} <button
className="cursor-pointer text-primary-300 duration-200 hover:text-primary" type="button"
onClick={() => toggleSidebar(action._id)} onClick={() => toggleSidebar(action._id)}
> className='w-1/2 text-primary-300 hover:text-primary-500 flex flex-row justify-left items-center duration-100'
{action.secretVersions.length + >
(action.secretVersions.length !== 1 ? ' secrets' : ' secret')} {action.secretVersions.length +
<FontAwesomeIcon (action.secretVersions.length !== 1 ? ' secrets' : ' secret')}
icon={faUpRightFromSquare} <FontAwesomeIcon
className="ml-2 mb-0.5 h-3 w-3 font-light" icon={faUpRightFromSquare}
/> className="ml-2 mb-0.5 h-3 w-3 font-light"
</td> />
</tr> </button>
</div>
</div>
) )
)} )}
{payloadOpened && ( {payloadOpened && (
<tr className="h-9 border-t border-mineshaft-700 text-sm text-bunker-200"> <div className="h-9 border-t border-mineshaft-700 text-sm text-bunker-200 bg-mineshaft-900/50 w-full flex flex-row items-center">
<td /> <div className='max-w-xl w-full flex flex-row items-center'>
<td>{String(t('activity.ip-address'))}</td> <div className='w-24' />
<td>{row.ipAddress}</td> <div className='w-1/2'>{String(t('activity.ip-address'))}</div>
</tr> <div className='w-1/2'>{row.ipAddress}</div>
</div>
</div>
)} )}
</> </>
); );
@@ -147,47 +152,48 @@ const ActivityTable = ({
return ( return (
<div className="mt-8 w-full px-6"> <div className="mt-8 w-full px-6">
<div className="table-container relative mb-6 w-full rounded-md border border-mineshaft-700 bg-bunker"> <div className="table-container relative mb-6 w-full rounded-md border border-mineshaft-700 bg-mineshaft-800">
<div className="absolute h-[3rem] w-full rounded-t-md bg-white/5" /> {/* <div className="absolute h-[3rem] w-full rounded-t-md bg-white/5" /> */}
<table className="my-1 w-full"> <div className="my-1 w-full">
<thead className="text-bunker-300"> <div className="text-bunker-300 border-b border-mineshaft-600">
<tr className="text-sm"> <div className="text-sm flex flex-row w-full">
<th aria-label="actions" className="pl-6 pt-2.5 pb-3 text-left" /> <button
<th className="pt-2.5 pb-3 text-left font-semibold"> type="button"
{String(t('common.event')).toUpperCase()} onClick={() => {}}
</th> className="opacity-0"
<th className="pl-6 pt-2.5 pb-3 text-left font-semibold"> >
{String(t('common.user')).toUpperCase()} <FontAwesomeIcon
</th> icon={faAngleRight}
<th className="pl-6 pt-2.5 pb-3 text-left font-semibold"> className="ml-6 mb-2 text-bunker-100 hover:bg-mineshaft-700 cursor-pointer h-4 w-4 rounded-md p-1 duration-100"
{String(t('common.source')).toUpperCase()} />
</th> </button>
<th className="pl-6 pt-2.5 pb-3 text-left font-semibold"> <div className="flex flex-row justify-between w-full">
{String(t('common.time')).toUpperCase()} <div className="pt-2.5 pb-3 text-left font-semibold w-1/4 pl-6">
</th> {String(t('common.event')).toUpperCase()}
<th aria-label="action" /> </div>
</tr> <div className="pl-6 pt-2.5 pb-3 text-left font-semibold w-1/4 pl-6">
</thead> {String(t('common.user')).toUpperCase()}
<tbody> </div>
{data?.map((row, index) => ( <div className="pl-6 pt-2.5 pb-3 text-left font-semibold w-1/4 pl-6">
<ActivityLogsRow {String(t('common.source')).toUpperCase()}
key={`activity.${index + 1}.${row._id}`} </div>
row={row} <div className="pl-6 pt-2.5 pb-3 text-left font-semibold w-1/4 pl-6">
toggleSidebar={toggleSidebar} {String(t('common.time')).toUpperCase()}
/> </div>
))} </div>
</tbody> </div>
</table> </div>
{data?.map((row, index) => (
<ActivityLogsRow
key={`activity.${index + 1}.${row._id}`}
row={row}
toggleSidebar={toggleSidebar}
/>
))}
</div>
</div> </div>
{isLoading && ( {isLoading && (
<div className="mb-8 mt-4 flex w-full justify-center"> <div className="mb-8 mt-4 bg-mineshaft-800 rounded-md h-60 flex w-full justify-center animate-pulse" />
<Image
src="/images/loading/loading.gif"
height={60}
width={100}
alt="loading animation"
/>
</div>
)} )}
</div> </div>
); );
@@ -2,20 +2,20 @@ import { useQuery } from '@tanstack/react-query';
import { apiRequest } from '@app/config/request'; import { apiRequest } from '@app/config/request';
import { GetSubscriptionPlan } from './types'; import { SubscriptionPlan } from './types';
// import { Workspace } from './types'; // import { Workspace } from './types';
const subscriptionKeys = { const subscriptionKeys = {
getOrgSubsription: (orgID: string) => ['subscription', { orgID }] as const getOrgSubsription: (orgID: string) => ['plan', { orgID }] as const
}; };
const fetchOrgSubscription = async (orgID: string) => { const fetchOrgSubscription = async (orgID: string) => {
const { data } = await apiRequest.get<{ subscriptions: GetSubscriptionPlan }>( const { data } = await apiRequest.get<{ plan: SubscriptionPlan }>(
`/api/v1/organization/${orgID}/subscriptions` `/api/v1/organizations/${orgID}/plan`
); );
return data.subscriptions; return data.plan;
}; };
type UseGetOrgSubscriptionProps = { type UseGetOrgSubscriptionProps = {
+14 -23
View File
@@ -1,25 +1,16 @@
export type GetSubscriptionPlan = {
data: { plan: SubscriptionPlan }[];
};
export type SubscriptionPlan = { export type SubscriptionPlan = {
id: string; _id: string;
object: string; membersUsed: number;
active: boolean; membersLimit: number;
aggregate_usage: unknown; auditLogs: boolean;
amount: 1400; customAlerts: boolean;
amount_decimal: 1400; customRateLimits: boolean;
billing_scheme: string; pitRecovery: boolean;
created: 1674833546; rbac: boolean;
currency: string; secretVersioning: boolean;
interval: string; slug: string;
interval_count: 1; tier: number;
livemode: false; workspaceLimit: number;
metadata: {}; workspacesUsed: number;
nickname: null; envLimit: number;
product: string;
tiers_mode: unknown;
transform_usage: unknown;
trial_period_days: unknown;
usage_type: string;
}; };
+4 -5
View File
@@ -31,7 +31,6 @@ import {
SelectItem, SelectItem,
UpgradePlanModal UpgradePlanModal
} from '@app/components/v2'; } from '@app/components/v2';
import { plans } from '@app/const';
import { useOrganization, useSubscription, useUser, useWorkspace } from '@app/context'; import { useOrganization, useSubscription, useUser, useWorkspace } from '@app/context';
import { usePopUp } from '@app/hooks'; import { usePopUp } from '@app/hooks';
import { fetchOrgUsers, useAddUserToWs, useCreateWorkspace, useUploadWsKey } from '@app/hooks/api'; import { fetchOrgUsers, useAddUserToWs, useCreateWorkspace, useUploadWsKey } from '@app/hooks/api';
@@ -59,10 +58,10 @@ export const AppLayout = ({ children }: LayoutProps) => {
const { workspaces, currentWorkspace } = useWorkspace(); const { workspaces, currentWorkspace } = useWorkspace();
const { currentOrg } = useOrganization(); const { currentOrg } = useOrganization();
const { user } = useUser(); const { user } = useUser();
const { subscriptionPlan } = useSubscription(); const { subscription } = useSubscription();
const host = window.location.origin; const host = window.location.origin;
const isAddingProjectsAllowed = const isAddingProjectsAllowed = ((subscription?.workspacesUsed || 0) < (subscription?.workspaceLimit || 1)) || host !== 'https://app.infisical.com';
subscriptionPlan !== plans.starter || (subscriptionPlan === plans.starter && workspaces.length < 3) || host !== 'https://app.infisical.com';
const createWs = useCreateWorkspace(); const createWs = useCreateWorkspace();
const uploadWsKey = useUploadWsKey(); const uploadWsKey = useUploadWsKey();
@@ -104,7 +103,7 @@ export const AppLayout = ({ children }: LayoutProps) => {
}); });
const userWorkspaces = orgUserProjects; const userWorkspaces = orgUserProjects;
if ( if (
(userWorkspaces.length === 0 && (userWorkspaces?.length === 0 &&
router.asPath !== '/noprojects' && router.asPath !== '/noprojects' &&
!router.asPath.includes('home') && !router.asPath.includes('home') &&
!router.asPath.includes('settings')) || !router.asPath.includes('settings')) ||
+18 -2
View File
@@ -6,7 +6,10 @@ import { useRouter } from 'next/router';
import Button from '@app/components/basic/buttons/Button'; import Button from '@app/components/basic/buttons/Button';
import EventFilter from '@app/components/basic/EventFilter'; import EventFilter from '@app/components/basic/EventFilter';
import NavHeader from '@app/components/navigation/NavHeader'; import NavHeader from '@app/components/navigation/NavHeader';
import { UpgradePlanModal } from '@app/components/v2';
import { useSubscription } from '@app/context';
import ActivitySideBar from '@app/ee/components/ActivitySideBar'; import ActivitySideBar from '@app/ee/components/ActivitySideBar';
import { usePopUp } from '@app/hooks/usePopUp';
import getProjectLogs from '../../ee/api/secrets/GetProjectLogs'; import getProjectLogs from '../../ee/api/secrets/GetProjectLogs';
import ActivityTable from '../../ee/components/ActivityTable'; import ActivityTable from '../../ee/components/ActivityTable';
@@ -67,6 +70,10 @@ export default function Activity() {
const currentLimit = 10; const currentLimit = 10;
const [currentSidebarAction, toggleSidebar] = useState<string>(); const [currentSidebarAction, toggleSidebar] = useState<string>();
const { t } = useTranslation(); const { t } = useTranslation();
const { subscription } = useSubscription();
const { popUp, handlePopUpOpen, handlePopUpClose } = usePopUp([
'upgradePlan'
] as const);
// this use effect updates the data in case of a new filter being added // this use effect updates the data in case of a new filter being added
useEffect(() => { useEffect(() => {
@@ -137,11 +144,15 @@ export default function Activity() {
}, [currentLimit, currentOffset]); }, [currentLimit, currentOffset]);
const loadMoreLogs = () => { const loadMoreLogs = () => {
setCurrentOffset(currentOffset + currentLimit); if (subscription?.auditLogs === false) {
handlePopUpOpen('upgradePlan');
} else {
setCurrentOffset(currentOffset + currentLimit);
}
}; };
return ( return (
<div className="mx-6 lg:mx-0 w-full h-screen"> <div className="mx-6 lg:mx-0 w-full h-full">
<Head> <Head>
<title>Audit Logs</title> <title>Audit Logs</title>
<link rel="icon" href="/infisical.ico" /> <link rel="icon" href="/infisical.ico" />
@@ -173,6 +184,11 @@ export default function Activity() {
/> />
</div> </div>
</div> </div>
<UpgradePlanModal
isOpen={popUp.upgradePlan.isOpen}
onOpenChange={() => handlePopUpClose('upgradePlan')}
text="You can see more logs if you switch to Infisical's Business/Professional Plan."
/>
</div> </div>
); );
} }
+13 -12
View File
@@ -11,6 +11,7 @@ import AddProjectMemberDialog from '@app/components/basic/dialog/AddProjectMembe
import ProjectUsersTable from '@app/components/basic/table/ProjectUsersTable'; import ProjectUsersTable from '@app/components/basic/table/ProjectUsersTable';
import NavHeader from '@app/components/navigation/NavHeader'; import NavHeader from '@app/components/navigation/NavHeader';
import guidGenerator from '@app/components/utilities/randomId'; import guidGenerator from '@app/components/utilities/randomId';
import { Input } from '@app/components/v2';
import { import {
decryptAssymmetric, decryptAssymmetric,
@@ -56,6 +57,7 @@ export default function Users() {
const workspaceId = router.query.id as string; const workspaceId = router.query.id as string;
const [userList, setUserList] = useState<any[]>([]); const [userList, setUserList] = useState<any[]>([]);
const [isUserListLoading, setIsUserListLoading] = useState(true);
const [orgUserList, setOrgUserList] = useState<any[]>([]); const [orgUserList, setOrgUserList] = useState<any[]>([]);
useEffect(() => { useEffect(() => {
@@ -81,6 +83,8 @@ export default function Users() {
})); }));
setUserList(tempUserList); setUserList(tempUserList);
setIsUserListLoading(false);
// This is needed to know wha users from an org (if any), we are able to add to a certain project // This is needed to know wha users from an org (if any), we are able to add to a certain project
const orgUsers = await getOrganizationUsers({ const orgUsers = await getOrganizationUsers({
orgId: String(localStorage.getItem('orgData.id')) orgId: String(localStorage.getItem('orgData.id'))
@@ -151,9 +155,8 @@ export default function Users() {
<link rel="icon" href="/infisical.ico" /> <link rel="icon" href="/infisical.ico" />
</Head> </Head>
<NavHeader pageName={t('settings.members.title')} isProjectRelated /> <NavHeader pageName={t('settings.members.title')} isProjectRelated />
<div className="flex flex-col items-start justify-start px-6 py-6 pb-4 text-3xl"> <div className="flex flex-col items-start justify-start px-6 py-6 pb-0 text-3xl mb-4">
<p className="mr-4 font-semibold text-white">{t('settings.members.title')}</p> <p className="mr-4 font-semibold text-white">{t('settings.members.title')}</p>
<p className="mr-4 text-base text-gray-400">{t('settings.members.description')}</p>
</div> </div>
<AddProjectMemberDialog <AddProjectMemberDialog
isOpen={isAddOpen} isOpen={isAddOpen}
@@ -169,20 +172,17 @@ export default function Users() {
setEmail={setEmail} setEmail={setEmail}
/> />
{/* <DeleteUserDialog isOpen={isDeleteOpen} closeModal={closeDeleteModal} submitModal={deleteMembership} userIdToBeDeleted={userIdToBeDeleted}/> */} {/* <DeleteUserDialog isOpen={isDeleteOpen} closeModal={closeDeleteModal} submitModal={deleteMembership} userIdToBeDeleted={userIdToBeDeleted}/> */}
<div className="flex w-full flex-row items-start px-6 pb-1"> <div className="absolute right-4 top-36 flex w-full flex-row items-start px-6 pb-1">
<div className="mt-2 flex h-10 w-full flex-row items-center rounded-md bg-white/5"> <div className="flex w-full max-w-sm flex flex-row ml-auto">
<FontAwesomeIcon <Input
className="rounded-l-md bg-white/5 py-3 pl-4 pr-2 text-gray-400" className="h-[2.3rem] bg-mineshaft-800 placeholder-mineshaft-50 duration-200 focus:bg-mineshaft-700/80"
icon={faMagnifyingGlass} placeholder="Search by secret name..."
/>
<input
className="h-full w-full rounded-r-md bg-white/5 pl-2 text-gray-400 outline-none"
value={searchUsers} value={searchUsers}
onChange={(e) => setSearchUsers(e.target.value)} onChange={(e) => setSearchUsers(e.target.value)}
placeholder={String(t('section.members.search-members'))} leftIcon={<FontAwesomeIcon icon={faMagnifyingGlass} />}
/> />
</div> </div>
<div className="mt-2 ml-2 flex min-w-max flex-row items-start justify-start"> <div className="ml-2 flex min-w-max flex-row items-start justify-start">
<Button <Button
text={String(t('section.members.add-member'))} text={String(t('section.members.add-member'))}
onButtonPressed={openAddModal} onButtonPressed={openAddModal}
@@ -198,6 +198,7 @@ export default function Users() {
changeData={setUserList} changeData={setUserList}
myUser={personalEmail} myUser={personalEmail}
filter={searchUsers} filter={searchUsers}
isUserListLoading={isUserListLoading}
// onClick={openDeleteModal} // onClick={openDeleteModal}
// deleteUser={deleteMembership} // deleteUser={deleteMembership}
// setUserIdToBeDeleted={setUserIdToBeDeleted} // setUserIdToBeDeleted={setUserIdToBeDeleted}
@@ -2,10 +2,12 @@ import { useEffect, useMemo, useState } from 'react';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { faKey, faMagnifyingGlass } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import NavHeader from '@app/components/navigation/NavHeader'; import NavHeader from '@app/components/navigation/NavHeader';
import { Button, TableContainer, Tooltip } from '@app/components/v2'; import { Button, Input, TableContainer, Tooltip } from '@app/components/v2';
import { useWorkspace } from '@app/context'; import { useWorkspace } from '@app/context';
import { import {
useGetProjectSecretsByKey, useGetProjectSecretsByKey,
@@ -27,6 +29,8 @@ export const DashboardEnvOverview = ({ onEnvChange }: { onEnvChange: any }) => {
const workspaceId = currentWorkspace?._id as string; const workspaceId = currentWorkspace?._id as string;
const { data: latestFileKey } = useGetUserWsKey(workspaceId); const { data: latestFileKey } = useGetUserWsKey(workspaceId);
const [searchFilter, setSearchFilter] = useState('');
useEffect(() => { useEffect(() => {
if (!isLoading && !workspaceId && router.isReady) { if (!isLoading && !workspaceId && router.isReady) {
router.push('/noprojects'); router.push('/noprojects');
@@ -88,7 +92,7 @@ export const DashboardEnvOverview = ({ onEnvChange }: { onEnvChange: any }) => {
} }
// when secrets is not loading and secrets list is empty // when secrets is not loading and secrets list is empty
const isDashboardSecretEmpty = !isSecretsLoading && !Object.keys(secrets?.secrets || {})?.length; const isDashboardSecretEmpty = !isSecretsLoading && !Object.keys(secrets?.secrets || {})?.filter((secret: any) => secret.toUpperCase().includes(searchFilter.toUpperCase()))?.length;
return ( return (
<div className="container mx-auto max-w-full px-6 text-mineshaft-50 dark:[color-scheme:dark]"> <div className="container mx-auto max-w-full px-6 text-mineshaft-50 dark:[color-scheme:dark]">
@@ -121,6 +125,15 @@ export const DashboardEnvOverview = ({ onEnvChange }: { onEnvChange: any }) => {
</a> </a>
</p> </p>
</div> </div>
<div className="absolute top-[11.1rem] right-6 flex w-full max-w-sm flex-grow space-x-2">
<Input
className="h-[2.3rem] bg-mineshaft-800 placeholder-mineshaft-50 duration-200 focus:bg-mineshaft-700/80"
placeholder="Search by secret name..."
value={searchFilter}
onChange={(e) => setSearchFilter(e.target.value)}
leftIcon={<FontAwesomeIcon icon={faMagnifyingGlass} />}
/>
</div>
<div className="overflow-y-auto"> <div className="overflow-y-auto">
<div className="sticky top-0 mt-8 flex h-10 min-w-[60.3rem] flex-row rounded-md border border-mineshaft-600 bg-mineshaft-800"> <div className="sticky top-0 mt-8 flex h-10 min-w-[60.3rem] flex-row rounded-md border border-mineshaft-600 bg-mineshaft-800">
<div className="sticky top-0 flex w-10 items-center justify-center border-none px-4"> <div className="sticky top-0 flex w-10 items-center justify-center border-none px-4">
@@ -167,7 +180,7 @@ export const DashboardEnvOverview = ({ onEnvChange }: { onEnvChange: any }) => {
<TableContainer className="border-none"> <TableContainer className="border-none">
<table className="secret-table relative w-full bg-mineshaft-900"> <table className="secret-table relative w-full bg-mineshaft-900">
<tbody className="max-h-screen overflow-y-auto"> <tbody className="max-h-screen overflow-y-auto">
{Object.keys(secrets?.secrets || {}).map((key, index) => ( {Object.keys(secrets?.secrets || {})?.filter((secret: any) => secret.toUpperCase().includes(searchFilter.toUpperCase())).map((key, index) => (
<EnvComparisonRow <EnvComparisonRow
key={`row-${key}`} key={`row-${key}`}
secrets={secrets?.secrets?.[key]} secrets={secrets?.secrets?.[key]}
@@ -184,8 +197,9 @@ export const DashboardEnvOverview = ({ onEnvChange }: { onEnvChange: any }) => {
{isDashboardSecretEmpty && ( {isDashboardSecretEmpty && (
<div className="flex h-40 w-full flex-row rounded-md"> <div className="flex h-40 w-full flex-row rounded-md">
<div className="flex w-full min-w-[11rem] flex-col items-center justify-center rounded-md border-none bg-mineshaft-800 text-bunker-300"> <div className="flex w-full min-w-[11rem] flex-col items-center justify-center rounded-md border-none bg-mineshaft-800 text-bunker-300">
<span className="mb-1">No secrets are available in this project yet.</span> <FontAwesomeIcon icon={faKey} className="text-4xl mb-4" />
<span>You can go into any environment to add secrets there.</span> <span className="mb-1">No secrets found.</span>
<span>To add more secrets you can explore any environment.</span>
</div> </div>
</div> </div>
)} )}
@@ -1,6 +1,6 @@
/* eslint-disable react/jsx-no-useless-fragment */ /* eslint-disable react/jsx-no-useless-fragment */
import { useCallback, useState } from 'react'; import { useCallback, useState } from 'react';
import { faCircle, faEye, faEyeSlash } from '@fortawesome/free-solid-svg-icons'; import { faCircle, faEye, faEyeSlash, faMinus } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
@@ -29,7 +29,9 @@ const DashboardInput = ({
const syntaxHighlight = useCallback((val: string) => { const syntaxHighlight = useCallback((val: string) => {
if (val === undefined) if (val === undefined)
return ( return (
<span className="cursor-default font-sans text-xs italic text-red-500/80">missing</span> <span className="cursor-default font-sans text-xs italic text-red-500/80">
<FontAwesomeIcon icon={faMinus} className="mt-1" />
</span>
); );
if (val?.length === 0) if (val?.length === 0)
return <span className="w-full font-sans text-bunker-400/80">EMPTY</span>; return <span className="w-full font-sans text-bunker-400/80">EMPTY</span>;
@@ -38,7 +38,7 @@ export const OrgSettingsPage = () => {
const { currentOrg } = useOrganization(); const { currentOrg } = useOrganization();
const { currentWorkspace } = useWorkspace(); const { currentWorkspace } = useWorkspace();
const { user } = useUser(); const { user } = useUser();
const { subscriptionPlan } = useSubscription(); const { subscription } = useSubscription();
const { createNotification } = useNotificationContext(); const { createNotification } = useNotificationContext();
const orgId = currentOrg?._id || ''; const orgId = currentOrg?._id || '';
@@ -60,14 +60,7 @@ export const OrgSettingsPage = () => {
const [completeInviteLink, setcompleteInviteLink] = useState<string | undefined>(''); const [completeInviteLink, setcompleteInviteLink] = useState<string | undefined>('');
const isMoreUsersNotAllowed = const isMoreUsersNotAllowed = ((subscription?.membersUsed || 0) >= (subscription?.membersLimit || 1)) && host === 'https://app.infisical.com';
(orgUsers || []).length >= 5 &&
subscriptionPlan === plans.starter &&
host === 'https://app.infisical.com' &&
currentWorkspace?._id !== '63ea8121b6e2b0543ba79616' &&
currentWorkspace?._id !== '634870246fd2e26f28e76996' &&
currentWorkspace?._id !== '63d823cef9e728a0a961255a' &&
currentWorkspace?._id !== '6412ec319db25595ac00b8c6';
const onRenameOrg = async (name: string) => { const onRenameOrg = async (name: string) => {
if (!currentOrg?._id) return; if (!currentOrg?._id) return;
@@ -13,7 +13,6 @@ import {
encryptSymmetric encryptSymmetric
} from '@app/components/utilities/cryptography/crypto'; } from '@app/components/utilities/cryptography/crypto';
import { Button, FormControl, Input } from '@app/components/v2'; import { Button, FormControl, Input } from '@app/components/v2';
import { plans } from '@app/const';
import { useSubscription, useWorkspace } from '@app/context'; import { useSubscription, useWorkspace } from '@app/context';
import { useToggle } from '@app/hooks'; import { useToggle } from '@app/hooks';
import { import {
@@ -89,10 +88,9 @@ export const ProjectSettingsPage = () => {
const deleteWsTag = useDeleteWsTag(); const deleteWsTag = useDeleteWsTag();
// get user subscription // get user subscription
const { subscriptionPlan } = useSubscription(); const { subscription } = useSubscription();
const host = window.location.origin; const host = window.location.origin;
const isEnvServiceAllowed = const isEnvServiceAllowed = ((currentWorkspace?.environments || []).length < (subscription?.envLimit || 3) && host === 'https://app.infisical.com');
subscriptionPlan !== plans.starter || host !== 'https://app.infisical.com';
const onRenameWorkspace = async (name: string) => { const onRenameWorkspace = async (name: string) => {
try { try {
@@ -402,7 +400,7 @@ export const ProjectSettingsPage = () => {
{!isBlindIndexedLoading && !isBlindIndexed && ( {!isBlindIndexedLoading && !isBlindIndexed && (
<ProjectIndexSecretsSection onEnableBlindIndices={onEnableBlindIndices} /> <ProjectIndexSecretsSection onEnableBlindIndices={onEnableBlindIndices} />
)} )}
<div className="mb-6 mt-4 flex w-full flex-col items-start rounded-md border-l border-red bg-white/5 px-6 pl-6 pb-4 pt-4"> <div className="mb-6 mt-4 flex w-full flex-col items-start rounded-md border-l border-red bg-mineshaft-900 px-6 pl-6 pb-4 pt-4">
<p className="text-xl font-bold text-red">{t('settings.project.danger-zone')}</p> <p className="text-xl font-bold text-red">{t('settings.project.danger-zone')}</p>
<p className="text-md mt-2 text-gray-400">{t('settings.project.danger-zone-note')}</p> <p className="text-md mt-2 text-gray-400">{t('settings.project.danger-zone-note')}</p>
<div className="mr-auto mt-4 max-h-28 w-full max-w-md"> <div className="mr-auto mt-4 max-h-28 w-full max-w-md">
@@ -418,6 +416,7 @@ export const ProjectSettingsPage = () => {
onChange={(e) => setDeleteProjectInput(e.target.value)} onChange={(e) => setDeleteProjectInput(e.target.value)}
value={deleteProjectInput} value={deleteProjectInput}
placeholder="Type the project name to delete" placeholder="Type the project name to delete"
className="bg-mineshaft-800"
/> />
</FormControl> </FormControl>
</div> </div>
@@ -13,7 +13,7 @@ export const AutoCapitalizationSection = ({
}: Props) => { }: Props) => {
const { t } = useTranslation(); const { t } = useTranslation();
return ( return (
<div className="mb-6 mt-4 flex w-full flex-col items-start rounded-md bg-white/5 px-6 pb-6 pt-2"> <div className="mb-6 mt-4 flex w-full flex-col items-start rounded-md bg-mineshaft-900 px-6 pb-6 pt-2">
<p className="mb-4 mt-2 text-xl font-semibold">{t('settings.project.auto-capitalization')}</p> <p className="mb-4 mt-2 text-xl font-semibold">{t('settings.project.auto-capitalization')}</p>
<Checkbox <Checkbox
className="data-[state=checked]:bg-primary" className="data-[state=checked]:bg-primary"
@@ -28,24 +28,9 @@ export const CopyProjectIDSection = ({ workspaceID }: Props): JSX.Element => {
}; };
return ( return (
<div className="mb-6 mt-4 flex w-full flex-col items-start rounded-md bg-white/5 px-6 pt-4 pb-2"> <div className="mb-6 mt-4 flex w-full flex-col items-start rounded-md bg-mineshaft-900 px-6 pt-4 pb-2">
<p className="self-start text-xl font-semibold">{t('common.project-id')}</p> <p className="self-start text-xl font-semibold">{t('common.project-id')}</p>
<p className="mt-4 self-start text-base font-normal text-gray-400"> <p className="mt-4 text-sm text-bunker-300 mb-2">{t('settings.project.auto-generated')}</p>
{t('settings.project.project-id-description')}
</p>
<p className="mt-2 self-start text-base font-normal text-gray-400">
{t('settings.project.project-id-description2')}
{/* eslint-disable-next-line react/jsx-no-target-blank */}
<a
href="https://infisical.com/docs/documentation/getting-started/introduction"
target="_blank"
rel="noopener"
className="text-primary duration-200 hover:opacity-80"
>
{t('settings.project.docs')}
</a>
</p>
<p className="mt-4 text-xs text-bunker-300">{t('settings.project.auto-generated')}</p>
<div className="mt-2 mb-3 mr-2 flex items-center justify-end rounded-md bg-white/[0.07] text-base text-gray-400"> <div className="mt-2 mb-3 mr-2 flex items-center justify-end rounded-md bg-white/[0.07] text-base text-gray-400">
<p className="mr-2 pl-4 font-bold">{`${t('common.project-id')}:`}</p> <p className="mr-2 pl-4 font-bold">{`${t('common.project-id')}:`}</p>
<p className="mr-4">{workspaceID}</p> <p className="mr-4">{workspaceID}</p>
@@ -1,5 +1,5 @@
import { Controller, useForm } from 'react-hook-form'; import { Controller, useForm } from 'react-hook-form';
import { faPencil, faPlus, faTrashCan } from '@fortawesome/free-solid-svg-icons'; import { faPencil, faPlus, faXmark } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import * as yup from 'yup'; import * as yup from 'yup';
@@ -82,7 +82,7 @@ export const EnvironmentSection = ({
}; };
return ( return (
<div className="mt-4 mb-4 flex w-full flex-col items-start rounded-md bg-white/5 p-6"> <div className="mt-4 mb-4 flex w-full flex-col items-start rounded-md bg-mineshaft-900 p-6">
<div className="mb-2 flex w-full flex-row justify-between"> <div className="mb-2 flex w-full flex-row justify-between">
<div className="flex w-full flex-col"> <div className="flex w-full flex-col">
<p className="mb-3 text-xl font-semibold">Project Environments</p> <p className="mb-3 text-xl font-semibold">Project Environments</p>
@@ -128,32 +128,27 @@ export const EnvironmentSection = ({
<Td>{slug}</Td> <Td>{slug}</Td>
<Td className="flex items-center justify-end"> <Td className="flex items-center justify-end">
<IconButton <IconButton
className="mr-3" className="mr-3 py-2"
onClick={() => { onClick={() => {
if (isEnvServiceAllowed) { handlePopUpOpen('createUpdateEnv', { name, slug });
handlePopUpOpen('createUpdateEnv', { name, slug }); reset({ environmentName: name, environmentSlug: slug });
reset({ environmentName: name, environmentSlug: slug });
} else {
handlePopUpOpen('upgradePlan');
}
}} }}
colorSchema="secondary" colorSchema="primary"
variant="plain"
ariaLabel="update" ariaLabel="update"
> >
<FontAwesomeIcon icon={faPencil} /> <FontAwesomeIcon icon={faPencil} />
</IconButton> </IconButton>
<IconButton <IconButton
onClick={() => { onClick={() => {
if (isEnvServiceAllowed) { handlePopUpOpen('deleteEnv', { name, slug });
handlePopUpOpen('deleteEnv', { name, slug });
} else {
handlePopUpOpen('upgradePlan');
}
}} }}
size="lg"
colorSchema="danger" colorSchema="danger"
variant="plain"
ariaLabel="update" ariaLabel="update"
> >
<FontAwesomeIcon icon={faTrashCan} /> <FontAwesomeIcon icon={faXmark} />
</IconButton> </IconButton>
</Td> </Td>
</Tr> </Tr>
@@ -11,7 +11,7 @@ export const ProjectIndexSecretsSection = ({
onEnableBlindIndices onEnableBlindIndices
}: Props) => { }: Props) => {
return ( return (
<div className="rounded-md bg-white/5 p-6 my-2"> <div className="rounded-md bg-mineshaft-900 p-6 my-2">
<p className="mb-4 text-xl font-semibold">Blind Indices</p> <p className="mb-4 text-xl font-semibold">Blind Indices</p>
<p className="mb-4 text-sm text-gray-400"> <p className="mb-4 text-sm text-gray-400">
Your project, created before the introduction of blind indexing, contains unindexed secrets. To access individual secrets by name through the SDK and public API, please enable blind indexing. Your project, created before the introduction of blind indexing, contains unindexed secrets. To access individual secrets by name through the SDK and public API, please enable blind indexing.
@@ -41,14 +41,14 @@ export const ProjectNameChangeSection = ({
return ( return (
<form onSubmit={handleSubmit(onFormSubmit)}> <form onSubmit={handleSubmit(onFormSubmit)}>
<div className="mb-6 flex w-full flex-col items-start rounded-md bg-white/5 px-6 pb-6 pt-3"> <div className="mb-6 flex w-full flex-col items-start rounded-md bg-mineshaft-900 px-6 pb-6 pt-3">
<p className="mb-4 mt-2 text-xl font-semibold">{t('common.display-name')}</p> <p className="mb-4 mt-2 text-xl font-semibold">{t('common.display-name')}</p>
<div className="mb-2 w-full max-w-lg"> <div className="mb-2 w-full max-w-lg">
<Controller <Controller
defaultValue="" defaultValue=""
render={({ field, fieldState: { error } }) => ( render={({ field, fieldState: { error } }) => (
<FormControl isError={Boolean(error)} errorText={error?.message}> <FormControl isError={Boolean(error)} errorText={error?.message}>
<Input placeholder="Type your project name" {...field} /> <Input placeholder="Type your project name" {...field} className="bg-mineshaft-800" />
</FormControl> </FormControl>
)} )}
control={control} control={control}
@@ -74,7 +74,7 @@ export const SecretTagsSection = ({
}; };
return ( return (
<div className="mt-4 mb-4 flex w-full flex-col items-start rounded-md bg-white/5 p-6"> <div className="mt-4 mb-4 flex w-full flex-col items-start rounded-md bg-mineshaft-900 p-6">
<div className="flex w-full flex-row justify-between"> <div className="flex w-full flex-row justify-between">
<div className="flex w-full flex-col"> <div className="flex w-full flex-col">
<p className="mb-3 text-xl font-semibold">Secret Tags</p> <p className="mb-3 text-xl font-semibold">Secret Tags</p>
@@ -120,23 +120,11 @@ export const ServiceTokenSection = ({
}; };
return ( return (
<div className="mt-4 mb-4 flex w-full flex-col items-start rounded-md bg-white/5 p-6"> <div className="mt-4 mb-4 flex w-full flex-col items-start rounded-md bg-mineshaft-900 p-6">
<div className="flex w-full flex-row justify-between"> <div className="flex w-full flex-row justify-between">
<div className="flex w-full flex-col"> <div className="flex w-full flex-col">
<p className="mb-3 text-xl font-semibold">{t('section.token.service-tokens')}</p> <p className="mb-3 text-xl font-semibold">{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">{t('section.token.service-tokens-description')}</p>
<p className="mb-4 text-sm text-gray-400">
Please, make sure you are on the
<a
className="ml-1 text-primary underline underline-offset-2"
href="https://infisical.com/docs/cli/overview"
target="_blank"
rel="noreferrer"
>
latest version of CLI
</a>
.
</p>
</div> </div>
<div> <div>
<Modal <Modal
@@ -359,7 +347,7 @@ export const ServiceTokenSection = ({
))} ))}
{!isLoading && tokens?.length === 0 && ( {!isLoading && tokens?.length === 0 && (
<Tr> <Tr>
<Td colSpan={4} className="py-6 text-center text-bunker-400"> <Td colSpan={4} className="bg-mineshaft-800 text-center text-bunker-400">
<EmptyState title="No service tokens found" icon={faKey} /> <EmptyState title="No service tokens found" icon={faKey} />
</Td> </Td>
</Tr> </Tr>