mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-14 21:51:56 +00:00
refactor(ui): changed frontend to normal i18n without SSR
This commit is contained in:
@@ -95,8 +95,8 @@ export const DashboardEnvOverview = ({ onEnvChange }: { onEnvChange: any }) => {
|
||||
<FormProvider {...method}>
|
||||
<form autoComplete="off">
|
||||
{/* breadcrumb row */}
|
||||
<div className="relative right-6">
|
||||
<NavHeader pageName={t('dashboard:title')} isProjectRelated />
|
||||
<div className="relative right-5">
|
||||
<NavHeader pageName={t('dashboard.title')} isProjectRelated />
|
||||
</div>
|
||||
<div className="mt-6">
|
||||
<p className="text-3xl font-semibold text-bunker-100">Secrets Overview</p>
|
||||
@@ -161,7 +161,7 @@ export const DashboardEnvOverview = ({ onEnvChange }: { onEnvChange: any }) => {
|
||||
<div
|
||||
className={`${
|
||||
isDashboardSecretEmpty ? '' : ''
|
||||
} no-scrollbar::-webkit-scrollbar mt-3 border rounded-md border-mineshaft-600 flex h-full max-h-[calc(100vh-370px)] w-full min-w-[60.3rem] flex-grow flex-row items-start justify-center overflow-x-hidden no-scrollbar`}
|
||||
} no-scrollbar::-webkit-scrollbar mt-3 flex h-full max-h-[calc(100vh-370px)] w-full min-w-[60.3rem] flex-grow flex-row items-start justify-center overflow-x-hidden rounded-md border border-mineshaft-600 no-scrollbar`}
|
||||
>
|
||||
{!isDashboardSecretEmpty && (
|
||||
<TableContainer className="border-none">
|
||||
@@ -190,7 +190,7 @@ export const DashboardEnvOverview = ({ onEnvChange }: { onEnvChange: any }) => {
|
||||
</div>
|
||||
)}
|
||||
{/* In future, we should add an option to add environments here
|
||||
<div className="ml-10 h-full flex items-start justify-center">
|
||||
<div className="flex items-start justify-center h-full ml-10">
|
||||
<Button
|
||||
leftIcon={<FontAwesomeIcon icon={faPlus}/>}
|
||||
onClick={() => prepend(DEFAULT_SECRET_VALUE, { shouldFocus: false })}
|
||||
|
||||
@@ -419,7 +419,7 @@ export const DashboardPage = ({ envFromTop }: { envFromTop: string }) => {
|
||||
{/* breadcrumb row */}
|
||||
<div className="relative right-6 mb-6 -top-2">
|
||||
<NavHeader
|
||||
pageName={t('dashboard:title')}
|
||||
pageName={t('dashboard.title')}
|
||||
currentEnv={
|
||||
userAvailableEnvs?.filter((envir) => envir.slug === envFromTop)[0].name || ''
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import crypto from 'crypto';
|
||||
|
||||
import { useState } from 'react';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { faMinus, faPlus, faShuffle } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
|
||||
@@ -28,7 +28,7 @@ export const GenRandomNumber = ({ onGenerate }: Props) => {
|
||||
leftIcon={<FontAwesomeIcon icon={faShuffle} />}
|
||||
onClick={onGenerateRandomHex}
|
||||
>
|
||||
{t('dashboard:sidebar.generate-random-hex')}
|
||||
{t('dashboard.sidebar.generate-random-hex')}
|
||||
</Button>
|
||||
<div className="rounded-r-md bg-mineshaft p-2">
|
||||
<div className="flex rounded-md border-mineshaft-400 bg-bunker-800 p-1 px-2">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ChangeEvent, DragEvent } from 'react';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { faUpload } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { twMerge } from 'tailwind-merge';
|
||||
@@ -78,55 +78,53 @@ export const SecretDropzone = ({ isSmaller, onParsedEnv, onAddNewSecret }: Props
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="mx-1">
|
||||
<div
|
||||
onDragEnter={handleDrag}
|
||||
onDragLeave={handleDrag}
|
||||
onDragOver={handleDrag}
|
||||
onDrop={handleDrop}
|
||||
className={twMerge(
|
||||
'relative mb-4 mt-4 max-w-[calc(100vw-292px)] flex w-full cursor-pointer text-mineshaft-200 items-center py-8 justify-center space-x-2 rounded-md bg-mineshaft-900 px-2 opacity-60 outline-dashed outline-2 outline-chicago-600 duration-200 hover:opacity-100',
|
||||
isDragActive && 'opacity-100',
|
||||
!isSmaller && 'flex-col space-y-4 max-w-3xl py-20',
|
||||
isLoading && 'bg-bunker-800'
|
||||
)}
|
||||
>
|
||||
{isLoading ? (
|
||||
<div className="mb-16 flex items-center justify-center pt-16">
|
||||
<img src="/images/loading/loading.gif" height={70} width={120} alt="loading animation" />
|
||||
<div
|
||||
onDragEnter={handleDrag}
|
||||
onDragLeave={handleDrag}
|
||||
onDragOver={handleDrag}
|
||||
onDrop={handleDrop}
|
||||
className={twMerge(
|
||||
'relative mx-0.5 mb-4 mt-4 flex w-full max-w-[calc(100vw-292px)] cursor-pointer items-center justify-center space-x-2 rounded-md bg-mineshaft-900 py-8 px-2 text-mineshaft-200 opacity-60 outline-dashed outline-2 outline-chicago-600 duration-200 hover:opacity-100',
|
||||
isDragActive && 'opacity-100',
|
||||
!isSmaller && 'max-w-3xl flex-col space-y-4 py-20',
|
||||
isLoading && 'bg-bunker-800'
|
||||
)}
|
||||
>
|
||||
{isLoading ? (
|
||||
<div className="mb-16 flex items-center justify-center pt-16">
|
||||
<img src="/images/loading/loading.gif" height={70} width={120} alt="loading animation" />
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div>
|
||||
<FontAwesomeIcon icon={faUpload} size={isSmaller ? '2x' : '5x'} />
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div>
|
||||
<FontAwesomeIcon icon={faUpload} size={isSmaller ? '2x' : '5x'} />
|
||||
</div>
|
||||
<div>
|
||||
<p className="">{t(isSmaller ? 'common:drop-zone-keys' : 'common:drop-zone')}</p>
|
||||
</div>
|
||||
<input
|
||||
id="fileSelect"
|
||||
type="file"
|
||||
className="absolute h-full w-full cursor-pointer opacity-0"
|
||||
accept=".txt,.env,.yml,.yaml"
|
||||
onChange={handleFileUpload}
|
||||
/>
|
||||
{!isSmaller && (
|
||||
<>
|
||||
<div className="flex w-full flex-row items-center justify-center py-4">
|
||||
<div className="w-1/5 border-t border-mineshaft-700" />
|
||||
<p className="mx-4 text-xs text-mineshaft-400">OR</p>
|
||||
<div className="w-1/5 border-t border-mineshaft-700" />
|
||||
</div>
|
||||
<div>
|
||||
<Button variant="star" onClick={onAddNewSecret}>
|
||||
Add a new secret
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
)}{' '}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
<p className="">{t(isSmaller ? 'common.drop-zone-keys' : 'common.drop-zone')}</p>
|
||||
</div>
|
||||
<input
|
||||
id="fileSelect"
|
||||
type="file"
|
||||
className="absolute h-full w-full cursor-pointer opacity-0"
|
||||
accept=".txt,.env,.yml,.yaml"
|
||||
onChange={handleFileUpload}
|
||||
/>
|
||||
{!isSmaller && (
|
||||
<>
|
||||
<div className="flex w-full flex-row items-center justify-center py-4">
|
||||
<div className="w-1/5 border-t border-mineshaft-700" />
|
||||
<p className="mx-4 text-xs text-mineshaft-400">OR</p>
|
||||
<div className="w-1/5 border-t border-mineshaft-700" />
|
||||
</div>
|
||||
<div>
|
||||
<Button variant="star" onClick={onAddNewSecret}>
|
||||
Add a new secret
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
)}{' '}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -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>
|
||||
|
||||
+2
-2
@@ -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>
|
||||
|
||||
+2
-2
@@ -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>
|
||||
);
|
||||
|
||||
+7
-7
@@ -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>
|
||||
|
||||
+2
-2
@@ -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>
|
||||
|
||||
+46
-39
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user