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
@@ -2,10 +2,12 @@ import { useEffect, useMemo, useState } from 'react';
import { FormProvider, useForm } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
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 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 {
useGetProjectSecretsByKey,
@@ -27,6 +29,8 @@ export const DashboardEnvOverview = ({ onEnvChange }: { onEnvChange: any }) => {
const workspaceId = currentWorkspace?._id as string;
const { data: latestFileKey } = useGetUserWsKey(workspaceId);
const [searchFilter, setSearchFilter] = useState('');
useEffect(() => {
if (!isLoading && !workspaceId && router.isReady) {
router.push('/noprojects');
@@ -88,7 +92,7 @@ export const DashboardEnvOverview = ({ onEnvChange }: { onEnvChange: any }) => {
}
// 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 (
<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>
</p>
</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="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">
@@ -167,7 +180,7 @@ export const DashboardEnvOverview = ({ onEnvChange }: { onEnvChange: any }) => {
<TableContainer className="border-none">
<table className="secret-table relative w-full bg-mineshaft-900">
<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
key={`row-${key}`}
secrets={secrets?.secrets?.[key]}
@@ -184,8 +197,9 @@ export const DashboardEnvOverview = ({ onEnvChange }: { onEnvChange: any }) => {
{isDashboardSecretEmpty && (
<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">
<span className="mb-1">No secrets are available in this project yet.</span>
<span>You can go into any environment to add secrets there.</span>
<FontAwesomeIcon icon={faKey} className="text-4xl mb-4" />
<span className="mb-1">No secrets found.</span>
<span>To add more secrets you can explore any environment.</span>
</div>
</div>
)}
@@ -1,6 +1,6 @@
/* eslint-disable react/jsx-no-useless-fragment */
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 { twMerge } from 'tailwind-merge';
@@ -29,7 +29,9 @@ const DashboardInput = ({
const syntaxHighlight = useCallback((val: string) => {
if (val === undefined)
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)
return <span className="w-full font-sans text-bunker-400/80">EMPTY</span>;
@@ -38,7 +38,7 @@ export const OrgSettingsPage = () => {
const { currentOrg } = useOrganization();
const { currentWorkspace } = useWorkspace();
const { user } = useUser();
const { subscriptionPlan } = useSubscription();
const { subscription } = useSubscription();
const { createNotification } = useNotificationContext();
const orgId = currentOrg?._id || '';
@@ -60,14 +60,7 @@ export const OrgSettingsPage = () => {
const [completeInviteLink, setcompleteInviteLink] = useState<string | undefined>('');
const isMoreUsersNotAllowed =
(orgUsers || []).length >= 5 &&
subscriptionPlan === plans.starter &&
host === 'https://app.infisical.com' &&
currentWorkspace?._id !== '63ea8121b6e2b0543ba79616' &&
currentWorkspace?._id !== '634870246fd2e26f28e76996' &&
currentWorkspace?._id !== '63d823cef9e728a0a961255a' &&
currentWorkspace?._id !== '6412ec319db25595ac00b8c6';
const isMoreUsersNotAllowed = ((subscription?.membersUsed || 0) >= (subscription?.membersLimit || 1)) && host === 'https://app.infisical.com';
const onRenameOrg = async (name: string) => {
if (!currentOrg?._id) return;
@@ -13,7 +13,6 @@ import {
encryptSymmetric
} from '@app/components/utilities/cryptography/crypto';
import { Button, FormControl, Input } from '@app/components/v2';
import { plans } from '@app/const';
import { useSubscription, useWorkspace } from '@app/context';
import { useToggle } from '@app/hooks';
import {
@@ -89,10 +88,9 @@ export const ProjectSettingsPage = () => {
const deleteWsTag = useDeleteWsTag();
// get user subscription
const { subscriptionPlan } = useSubscription();
const { subscription } = useSubscription();
const host = window.location.origin;
const isEnvServiceAllowed =
subscriptionPlan !== plans.starter || host !== 'https://app.infisical.com';
const isEnvServiceAllowed = ((currentWorkspace?.environments || []).length < (subscription?.envLimit || 3) && host === 'https://app.infisical.com');
const onRenameWorkspace = async (name: string) => {
try {
@@ -402,7 +400,7 @@ export const ProjectSettingsPage = () => {
{!isBlindIndexedLoading && !isBlindIndexed && (
<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-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">
@@ -418,6 +416,7 @@ export const ProjectSettingsPage = () => {
onChange={(e) => setDeleteProjectInput(e.target.value)}
value={deleteProjectInput}
placeholder="Type the project name to delete"
className="bg-mineshaft-800"
/>
</FormControl>
</div>
@@ -13,7 +13,7 @@ export const AutoCapitalizationSection = ({
}: Props) => {
const { t } = useTranslation();
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>
<Checkbox
className="data-[state=checked]:bg-primary"
@@ -28,24 +28,9 @@ export const CopyProjectIDSection = ({ workspaceID }: Props): JSX.Element => {
};
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="mt-4 self-start text-base font-normal text-gray-400">
{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>
<p className="mt-4 text-sm text-bunker-300 mb-2">{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">
<p className="mr-2 pl-4 font-bold">{`${t('common.project-id')}:`}</p>
<p className="mr-4">{workspaceID}</p>
@@ -1,5 +1,5 @@
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 { yupResolver } from '@hookform/resolvers/yup';
import * as yup from 'yup';
@@ -82,7 +82,7 @@ export const EnvironmentSection = ({
};
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="flex w-full flex-col">
<p className="mb-3 text-xl font-semibold">Project Environments</p>
@@ -128,32 +128,27 @@ export const EnvironmentSection = ({
<Td>{slug}</Td>
<Td className="flex items-center justify-end">
<IconButton
className="mr-3"
className="mr-3 py-2"
onClick={() => {
if (isEnvServiceAllowed) {
handlePopUpOpen('createUpdateEnv', { name, slug });
reset({ environmentName: name, environmentSlug: slug });
} else {
handlePopUpOpen('upgradePlan');
}
handlePopUpOpen('createUpdateEnv', { name, slug });
reset({ environmentName: name, environmentSlug: slug });
}}
colorSchema="secondary"
colorSchema="primary"
variant="plain"
ariaLabel="update"
>
<FontAwesomeIcon icon={faPencil} />
</IconButton>
<IconButton
onClick={() => {
if (isEnvServiceAllowed) {
handlePopUpOpen('deleteEnv', { name, slug });
} else {
handlePopUpOpen('upgradePlan');
}
handlePopUpOpen('deleteEnv', { name, slug });
}}
size="lg"
colorSchema="danger"
variant="plain"
ariaLabel="update"
>
<FontAwesomeIcon icon={faTrashCan} />
<FontAwesomeIcon icon={faXmark} />
</IconButton>
</Td>
</Tr>
@@ -11,7 +11,7 @@ export const ProjectIndexSecretsSection = ({
onEnableBlindIndices
}: Props) => {
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-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.
@@ -41,14 +41,14 @@ export const ProjectNameChangeSection = ({
return (
<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>
<div className="mb-2 w-full max-w-lg">
<Controller
defaultValue=""
render={({ field, fieldState: { error } }) => (
<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>
)}
control={control}
@@ -74,7 +74,7 @@ export const SecretTagsSection = ({
};
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-col">
<p className="mb-3 text-xl font-semibold">Secret Tags</p>
@@ -120,23 +120,11 @@ export const ServiceTokenSection = ({
};
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-col">
<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="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>
<p className="text-sm text-gray-400 mb-4">{t('section.token.service-tokens-description')}</p>
</div>
<div>
<Modal
@@ -359,7 +347,7 @@ export const ServiceTokenSection = ({
))}
{!isLoading && tokens?.length === 0 && (
<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} />
</Td>
</Tr>