refactor(ui): changed frontend to normal i18n without SSR

This commit is contained in:
akhilmhdh
2023-05-09 23:28:23 +05:30
parent 420d71d923
commit 3561c589b1
198 changed files with 5008 additions and 5253 deletions
@@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import { useState } from 'react';
import { useTranslation } from 'next-i18next';
import { useTranslation } from 'react-i18next';
import { plans } from 'public/data/frequentConstants';
import { useNotificationContext } from '@app/components/context/Notifications/NotificationProvider';
@@ -21,12 +21,12 @@ import {
useGetUserWsKey,
useRenameOrg,
useUpdateOrgUserRole,
useUploadWsKey,
useUploadWsKey
} from '@app/hooks/api';
import {
OrgIncidentContactsTable,
OrgMembersTable,
import {
OrgIncidentContactsTable,
OrgMembersTable,
OrgNameChangeSection,
OrgServiceAccountsTable
} from './components';
@@ -44,9 +44,11 @@ export const OrgSettingsPage = () => {
const orgId = currentOrg?._id || '';
const { data: orgUsers, isLoading: isOrgUserLoading } = useGetOrgUsers(orgId);
const { data: workspaceMemberships, isLoading: IsWsMembershipLoading } = useGetUserWorkspaceMemberships(orgId);
const { data: workspaceMemberships, isLoading: IsWsMembershipLoading } =
useGetUserWorkspaceMemberships(orgId);
const { data: wsKey } = useGetUserWsKey(currentWorkspace?._id || '');
const { data: incidentContact, isLoading: IsIncidentContactLoading } = useGetOrgIncidentContact(orgId);
const { data: incidentContact, isLoading: IsIncidentContactLoading } =
useGetOrgIncidentContact(orgId);
const renameOrg = useRenameOrg();
const removeUserOrgMembership = useDeleteOrgMembership();
@@ -239,18 +241,16 @@ export const OrgSettingsPage = () => {
//
return (
<div className="container mx-auto flex flex-col justify-between bg-bunker-800 text-white">
<NavHeader pageName={t('settings-org:title')} />
<div className="my-8 max-w-5xl ml-8">
<p className="text-3xl font-semibold text-gray-200">{t('settings-org:title')}</p>
<p className="text-base font-normal text-gray-400">
{t('settings-org:description')}
</p>
<NavHeader pageName={t('settings.org.title')} />
<div className="my-8 ml-8 max-w-5xl">
<p className="text-3xl font-semibold text-gray-200">{t('settings.org.title')}</p>
<p className="text-base font-normal text-gray-400">{t('settings.org.description')}</p>
</div>
<div className="max-w-8xl ml-6 mr-6 flex flex-col text-mineshaft-50">
<OrgNameChangeSection orgName={currentOrg?.name} onOrgNameChange={onRenameOrg} />
<div className="w-full rounded-md bg-white/5 p-6 mb-6">
<div className="mb-6 w-full rounded-md bg-white/5 p-6">
<p className="mr-4 mb-4 text-xl font-semibold text-white">
{t('section-members:org-members')}
{t('section.members.org-members')}
</p>
<OrgMembersTable
isLoading={isOrgUserLoading || IsWsMembershipLoading}
@@ -268,19 +268,17 @@ export const OrgSettingsPage = () => {
/>
</div>
<div className="mb-6 mt-2 w-full rounded-md bg-white/5 p-6">
<p className="mr-4 mb-4 text-xl font-semibold text-white">
Service Accounts
</p>
<p className="mr-4 mb-4 text-xl font-semibold text-white">Service Accounts</p>
<OrgServiceAccountsTable />
</div>
<div className="mb-6 mt-2 flex w-full flex-col items-start rounded-md bg-white/5 px-6 pt-6 pb-6">
<div className="flex w-full max-w-5xl flex-row items-center justify-between">
<div className="flex w-full max-w-3xl flex-col justify-between">
<p className="mb-3 min-w-max text-xl font-semibold">
{t('section-incident:incident-contacts')}
{t('section.incident.incident-contacts')}
</p>
<p className="mb-2 min-w-max text-xs text-gray-500">
{t('section-incident:incident-contacts-description')}
{t('section.incident.incident-contacts-description')}
</p>
</div>
</div>
@@ -39,7 +39,7 @@ export const OrgNameChangeSection = ({ onOrgNameChange, orgName }: Props): JSX.E
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">
<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">
<Controller
defaultValue=""
@@ -60,7 +60,7 @@ export const OrgNameChangeSection = ({ onOrgNameChange, orgName }: Props): JSX.E
isDisabled={!isDirty || isSubmitting}
leftIcon={<FontAwesomeIcon icon={faCheck} />}
>
{t('common:save-changes')}
{t('common.save-changes')}
</Button>
</div>
</form>
@@ -10,7 +10,8 @@ import NavHeader from '@app/components/navigation/NavHeader';
import {
decryptAssymmetric,
decryptSymmetric,
encryptSymmetric} from '@app/components/utilities/cryptography/crypto';
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';
@@ -31,7 +32,8 @@ import {
useNameWorkspaceSecrets,
useRenameWorkspace,
useToggleAutoCapitalization,
useUpdateWsEnvironment} from '@app/hooks/api';
useUpdateWsEnvironment
} from '@app/hooks/api';
import { AutoCapitalizationSection } from './components/AutoCapitalizationSection/AutoCapitalizationSection';
import { SecretTagsSection } from './components/SecretTagsSection';
@@ -67,7 +69,8 @@ export const ProjectSettingsPage = () => {
const updateWsEnv = useUpdateWsEnvironment();
const deleteWsEnv = useDeleteWsEnvironment();
const { data: isBlindIndexed, isLoading: isBlindIndexedLoading } = useGetWorkspaceIndexStatus(workspaceID);
const { data: isBlindIndexed, isLoading: isBlindIndexedLoading } =
useGetWorkspaceIndexStatus(workspaceID);
// service token
const { data: serviceTokens, isLoading: isServiceTokenLoading } = useGetUserWsServiceTokens({
@@ -212,7 +215,12 @@ export const ProjectSettingsPage = () => {
}
};
const onCreateServiceToken = async ({ environment, expiresIn, name, permissions }: CreateServiceToken) => {
const onCreateServiceToken = async ({
environment,
expiresIn,
name,
permissions
}: CreateServiceToken) => {
// type guard
if (!latestFileKey) return '';
try {
@@ -229,7 +237,7 @@ export const ProjectSettingsPage = () => {
plaintext: key,
key: randomBytes
});
const res = await createServiceToken.mutateAsync({
encryptedKey: ciphertext,
iv,
@@ -240,10 +248,10 @@ export const ProjectSettingsPage = () => {
workspaceId: workspaceID,
randomBytes,
permissions: Object.entries(permissions)
.filter(([, permissionsValue]) => permissionsValue)
.map(([permissionsKey]) => permissionsKey)
.filter(([, permissionsValue]) => permissionsValue)
.map(([permissionsKey]) => permissionsKey)
});
createNotification({
text: 'Successfully created a service token',
type: 'success'
@@ -324,7 +332,7 @@ export const ProjectSettingsPage = () => {
publicKey: latestFileKey.sender.publicKey,
privateKey: localStorage.getItem('PRIVATE_KEY') as string
});
const secretsToUpdate = encryptedSecrets.map((encryptedSecret) => {
const secretName = decryptSymmetric({
ciphertext: encryptedSecret.secretKeyCiphertext,
@@ -332,30 +340,30 @@ export const ProjectSettingsPage = () => {
tag: encryptedSecret.secretKeyTag,
key
});
return ({
return {
secretName,
_id: encryptedSecret._id
});
};
});
await nameWorkspaceSecrets.mutateAsync({
workspaceId: currentWorkspace._id,
secretsToUpdate
});
}
};
return (
<div className="dark container mx-auto flex flex-col px-8 text-mineshaft-50 dark:[color-scheme:dark]">
{/* TODO(akhilmhdh): Remove this right when layout is refactored */}
<div className="relative right-5">
<NavHeader pageName={t('settings-project:title')} isProjectRelated />
<NavHeader pageName={t('settings.project.title')} isProjectRelated />
</div>
<div className="my-8 flex max-w-5xl flex-row items-center justify-between text-xl">
<div className="flex flex-col items-start justify-start text-3xl">
<p className="mr-4 font-semibold text-gray-200">{t('settings-project:title')}</p>
<p className="mr-4 font-semibold text-gray-200">{t('settings.project.title')}</p>
<p className="mr-4 text-base font-normal text-gray-400">
{t('settings-project:description')}
{t('settings.project.description')}
</p>
</div>
</div>
@@ -392,13 +400,11 @@ export const ProjectSettingsPage = () => {
onAutoCapitalizationChange={onAutoCapitalizationToggle}
/>
{!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">
<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-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">
<FormControl
label={
@@ -421,10 +427,10 @@ export const ProjectSettingsPage = () => {
isDisabled={deleteProjectInput !== currentWorkspace?.name || isDeleting}
isLoading={isDeleting}
>
{t('settings-project:delete-project')}
{t('settings.project.delete-project')}
</Button>
<p className="mt-3 ml-0.5 text-xs text-gray-500">
{t('settings-project:delete-project-note')}
{t('settings.project.delete-project-note')}
</p>
</div>
</div>
@@ -14,7 +14,7 @@ export const AutoCapitalizationSection = ({
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">
<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
className="data-[state=checked]:bg-primary"
id="autoCapitalization"
@@ -23,7 +23,7 @@ export const AutoCapitalizationSection = ({
onAutoCapitalizationChange(state as boolean);
}}
>
{t('settings-project:auto-capitalization-description')}
{t('settings.project.auto-capitalization-description')}
</Checkbox>
</div>
);
@@ -29,12 +29,12 @@ 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">
<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">
{t('settings-project:project-id-description')}
{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')}
{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"
@@ -42,12 +42,12 @@ export const CopyProjectIDSection = ({ workspaceID }: Props): JSX.Element => {
rel="noopener"
className="text-primary duration-200 hover:opacity-80"
>
{t('settings-project:docs')}
{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-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">
<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>
<IconButton
ariaLabel="copy icon"
@@ -57,7 +57,7 @@ export const CopyProjectIDSection = ({ workspaceID }: Props): JSX.Element => {
>
<FontAwesomeIcon icon={isProjectIdCopied ? faCheck : faCopy} />
<span className="absolute -left-8 -top-20 hidden w-28 translate-y-full rounded-md bg-bunker-800 py-2 pl-3 text-center text-sm text-gray-400 group-hover:flex group-hover:animate-fadeIn">
{t('common:click-to-copy')}
{t('common.click-to-copy')}
</span>
</IconButton>
</div>
@@ -42,7 +42,7 @@ 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">
<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">
<Controller
defaultValue=""
@@ -63,7 +63,7 @@ export const ProjectNameChangeSection = ({
isDisabled={!isDirty || isSubmitting}
leftIcon={<FontAwesomeIcon icon={faCheck} />}
>
{t('common:save-changes')}
{t('common.save-changes')}
</Button>
</div>
</form>
@@ -38,17 +38,21 @@ const apiTokenExpiry = [
{ label: '1 Month', value: 2592000 },
{ label: '6 months', value: 15552000 },
{ label: '12 months', value: 31104000 },
{ label: 'Never', value: null },
{ label: 'Never', value: null }
];
const createServiceTokenSchema = yup.object({
name: yup.string().required().label('Service Token Name'),
environment: yup.string().required().label('Environment'),
expiresIn: yup.string().optional().label('Service Token Expiration'),
permissions: yup.object().shape({
read: yup.boolean().required(),
write: yup.boolean().required()
}).defined().required()
permissions: yup
.object()
.shape({
read: yup.boolean().required(),
write: yup.boolean().required()
})
.defined()
.required()
});
export type CreateServiceToken = yup.InferType<typeof createServiceTokenSchema>;
@@ -93,7 +97,7 @@ export const ServiceTokenSection = ({
'createAPIToken',
'deleteAPITokenConfirmation'
] as const);
const {
control,
reset,
@@ -119,8 +123,8 @@ export const ServiceTokenSection = ({
<div className="mt-4 mb-4 flex w-full flex-col items-start rounded-md bg-white/5 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-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
@@ -145,16 +149,16 @@ export const ServiceTokenSection = ({
>
<ModalTrigger asChild>
<Button color="mineshaft" leftIcon={<FontAwesomeIcon icon={faPlus} />}>
{t('section-token:add-new')}
{t('section.token.add-new')}
</Button>
</ModalTrigger>
<ModalContent
title={
t('section-token:add-dialog.title', {
t('section.token.add-dialog.title', {
target: workspaceName
}) as string
}
subTitle={t('section-token:add-dialog.description') as string}
subTitle={t('section.token.add-dialog.description') as string}
>
{!hasServiceToken ? (
<form onSubmit={handleSubmit(onFormSubmit)}>
@@ -164,7 +168,7 @@ export const ServiceTokenSection = ({
defaultValue=""
render={({ field, fieldState: { error } }) => (
<FormControl
label={t('section-token:add-dialog.name')}
label={t('section.token.add-dialog.name')}
isError={Boolean(error)}
errorText={error?.message}
>
@@ -229,15 +233,18 @@ export const ServiceTokenSection = ({
read: true,
write: false
}}
render={({ field: { onChange, value }, fieldState: { error }}) => {
const options = [{
label: 'Read (default)',
value: 'read'
}, {
label: 'Write (optional)',
value: 'write'
}];
render={({ field: { onChange, value }, fieldState: { error } }) => {
const options = [
{
label: 'Read (default)',
value: 'read'
},
{
label: 'Write (optional)',
value: 'write'
}
];
return (
<FormControl
label="Permissions"
@@ -246,23 +253,23 @@ export const ServiceTokenSection = ({
>
<>
{options.map(({ label, value: optionValue }) => {
// TODO: refactor
return (
<Checkbox
id={value[optionValue]}
key={optionValue}
className="data-[state=checked]:bg-primary"
isChecked={value[optionValue]}
isDisabled={ optionValue === 'read'}
onCheckedChange={(state) => {
onChange({
...value,
[optionValue]: state
});
}}
>
{label}
</Checkbox>
// TODO: refactor
return (
<Checkbox
id={value[optionValue]}
key={optionValue}
className="data-[state=checked]:bg-primary"
isChecked={value[optionValue]}
isDisabled={optionValue === 'read'}
onCheckedChange={(state) => {
onChange({
...value,
[optionValue]: state
});
}}
>
{label}
</Checkbox>
);
})}
</>
@@ -297,7 +304,7 @@ export const ServiceTokenSection = ({
>
<FontAwesomeIcon icon={isTokenCopied ? faCheck : faCopy} />
<span className="absolute -left-8 -top-20 hidden w-28 translate-y-full rounded-md bg-bunker-800 py-2 pl-3 text-center text-sm text-gray-400 group-hover:flex group-hover:animate-fadeIn">
{t('common:click-to-copy')}
{t('common.click-to-copy')}
</span>
</IconButton>
</div>