mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-15 00:52:09 +00:00
Merge branch 'main' into feature/google-sign
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
faAngleDown,
|
||||
faEye,
|
||||
@@ -45,16 +45,16 @@ const EventFilter = ({ selected, select }: ListBoxProps): JSX.Element => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<Listbox value={t(`activity:event.${selected}`)} onChange={select}>
|
||||
<Listbox value={t(`activity.event.${selected}`)} onChange={select}>
|
||||
<div className="relative">
|
||||
<Listbox.Button className="bg-mineshaft-800 hover:bg-mineshaft-700 duration-200 cursor-pointer rounded-md h-10 flex items-center justify-between pl-4 pr-2 w-52 text-bunker-200 text-sm">
|
||||
<Listbox.Button className="flex h-10 w-52 cursor-pointer items-center justify-between rounded-md bg-mineshaft-800 pl-4 pr-2 text-sm text-bunker-200 duration-200 hover:bg-mineshaft-700">
|
||||
{selected !== '' ? (
|
||||
<p className="select-none text-bunker-100">{t(`activity:event.${selected}`)}</p>
|
||||
<p className="select-none text-bunker-100">{t(`activity.event.${selected}`)}</p>
|
||||
) : (
|
||||
<p className="select-none">{String(t('common:select-event'))}</p>
|
||||
<p className="select-none">{String(t('common.select-event'))}</p>
|
||||
)}
|
||||
{selected !== '' ? (
|
||||
<FontAwesomeIcon icon={faX} className="pl-2 w-2 p-2" onClick={() => select('')} />
|
||||
<FontAwesomeIcon icon={faX} className="w-2 p-2 pl-2" onClick={() => select('')} />
|
||||
) : (
|
||||
<FontAwesomeIcon icon={faAngleDown} className="pl-4 pr-2" />
|
||||
)}
|
||||
@@ -65,12 +65,12 @@ const EventFilter = ({ selected, select }: ListBoxProps): JSX.Element => {
|
||||
leaveFrom="opacity-100"
|
||||
leaveTo="opacity-0"
|
||||
>
|
||||
<Listbox.Options className="border border-mineshaft-700 z-50 w-52 p-1 absolute mt-1 max-h-60 overflow-auto rounded-md bg-bunker text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm">
|
||||
<Listbox.Options className="absolute z-50 mt-1 max-h-60 w-52 overflow-auto rounded-md border border-mineshaft-700 bg-bunker p-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm">
|
||||
{eventOptions.map((event, id) => (
|
||||
<Listbox.Option
|
||||
key={`${event.name}.${id + 1}`}
|
||||
className={`px-4 h-10 flex items-center text-sm cursor-pointer hover:bg-mineshaft-700 text-bunker-200 rounded-md ${
|
||||
selected === t(`activity:event.${event.name}`) && 'bg-mineshaft-700'
|
||||
className={`flex h-10 cursor-pointer items-center rounded-md px-4 text-sm text-bunker-200 hover:bg-mineshaft-700 ${
|
||||
selected === t(`activity.event.${event.name}`) && 'bg-mineshaft-700'
|
||||
}`}
|
||||
value={event.name}
|
||||
>
|
||||
@@ -79,7 +79,7 @@ const EventFilter = ({ selected, select }: ListBoxProps): JSX.Element => {
|
||||
className={`block truncate ${isSelected ? 'font-semibold' : 'font-normal'}`}
|
||||
>
|
||||
<FontAwesomeIcon icon={event.icon} className="pr-4" />{' '}
|
||||
{t(`activity:event.${event.name}`)}
|
||||
{t(`activity.event.${event.name}`)}
|
||||
</span>
|
||||
)}
|
||||
</Listbox.Option>
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
import crypto from 'crypto';
|
||||
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import Link from 'next/link';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import {
|
||||
faBookOpen,
|
||||
faFileLines,
|
||||
@@ -147,17 +147,17 @@ const Layout = ({ children }: LayoutProps) => {
|
||||
() => [
|
||||
{
|
||||
href: `/dashboard/${workspaceMapping[workspaceSelected as any]}`,
|
||||
title: t('nav:menu.secrets'),
|
||||
title: t('nav.menu.secrets'),
|
||||
emoji: <FontAwesomeIcon icon={faKey} />
|
||||
},
|
||||
{
|
||||
href: `/users/${workspaceMapping[workspaceSelected as any]}`,
|
||||
title: t('nav:menu.members'),
|
||||
title: t('nav.menu.members'),
|
||||
emoji: <FontAwesomeIcon icon={faUser} />
|
||||
},
|
||||
{
|
||||
href: `/integrations/${workspaceMapping[workspaceSelected as any]}`,
|
||||
title: t('nav:menu.integrations'),
|
||||
title: t('nav.menu.integrations'),
|
||||
emoji: <FontAwesomeIcon icon={faPlug} />
|
||||
},
|
||||
{
|
||||
@@ -167,7 +167,7 @@ const Layout = ({ children }: LayoutProps) => {
|
||||
},
|
||||
{
|
||||
href: `/settings/project/${workspaceMapping[workspaceSelected as any]}`,
|
||||
title: t('nav:menu.project-settings'),
|
||||
title: t('nav.menu.project-settings'),
|
||||
emoji: <FontAwesomeIcon icon={faGear} />
|
||||
}
|
||||
],
|
||||
@@ -256,7 +256,7 @@ const Layout = ({ children }: LayoutProps) => {
|
||||
<div>
|
||||
<div className="mt-6 mb-6 flex h-20 w-full flex-col items-center justify-center bg-bunker-600 px-4">
|
||||
<div className="ml-1 mb-1 self-start text-xs font-semibold tracking-wide text-gray-400">
|
||||
{t('nav:menu.project')}
|
||||
{t('nav.menu.project')}
|
||||
</div>
|
||||
{Object.keys(workspaceMapping).length > 0 ? (
|
||||
<Listbox
|
||||
@@ -375,7 +375,7 @@ const Layout = ({ children }: LayoutProps) => {
|
||||
<div className="flex h-screen w-screen flex-col items-center justify-center bg-bunker-800 z-[200] md:hidden">
|
||||
<FontAwesomeIcon icon={faMobile} className="mb-8 text-7xl text-gray-300" />
|
||||
<p className="max-w-sm px-6 text-center text-lg text-gray-200">
|
||||
{` ${t('common:no-mobile')} `}
|
||||
{` ${t('common.no-mobile')} `}
|
||||
</p>
|
||||
</div>
|
||||
</>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Fragment } from 'react';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Dialog, Transition } from '@headlessui/react';
|
||||
|
||||
import Button from '../buttons/Button';
|
||||
@@ -34,10 +34,9 @@ const ActivateBotDialog = ({
|
||||
try {
|
||||
// type check
|
||||
if (!selectedIntegrationOption) return;
|
||||
|
||||
|
||||
// start integration or probe for PAT
|
||||
integrationOptionPress(selectedIntegrationOption);
|
||||
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
@@ -71,20 +70,20 @@ const ActivateBotDialog = ({
|
||||
leaveFrom="opacity-100 scale-100"
|
||||
leaveTo="opacity-0 scale-95"
|
||||
>
|
||||
<Dialog.Panel className="w-full max-w-md transform overflow-hidden rounded-md bg-bunker-800 border border-gray-700 p-6 text-left align-middle shadow-xl transition-all">
|
||||
<Dialog.Panel className="w-full max-w-md transform overflow-hidden rounded-md border border-gray-700 bg-bunker-800 p-6 text-left align-middle shadow-xl transition-all">
|
||||
<Dialog.Title as="h3" className="text-lg font-medium leading-6 text-gray-400">
|
||||
{t('integrations:grant-access-to-secrets')}
|
||||
{t('integrations.grant-access-to-secrets')}
|
||||
</Dialog.Title>
|
||||
<div className="mt-2 mb-2">
|
||||
<p className="text-sm text-gray-500">
|
||||
{t('integrations:why-infisical-needs-access')}
|
||||
{t('integrations.why-infisical-needs-access')}
|
||||
</p>
|
||||
</div>
|
||||
<div className="mt-6 max-w-max">
|
||||
<Button
|
||||
onButtonPressed={submit}
|
||||
color="mineshaft"
|
||||
text={t('integrations:grant-access-button') as string}
|
||||
text={t('integrations.grant-access-button') as string}
|
||||
size="md"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Fragment, useState } from 'react';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { faCheck, faCopy } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { Dialog, Transition } from '@headlessui/react';
|
||||
@@ -15,7 +15,7 @@ const expiryMapping = {
|
||||
'7 days': 604800,
|
||||
'1 month': 2592000,
|
||||
'6 months': 15552000,
|
||||
'12 months': 31104000,
|
||||
'12 months': 31104000
|
||||
};
|
||||
|
||||
type Props = {
|
||||
@@ -27,12 +27,7 @@ type Props = {
|
||||
};
|
||||
|
||||
// TODO: convert to TS
|
||||
const AddApiKeyDialog = ({
|
||||
isOpen,
|
||||
closeModal,
|
||||
apiKeys,
|
||||
setApiKeys,
|
||||
}: Props) => {
|
||||
const AddApiKeyDialog = ({ isOpen, closeModal, apiKeys, setApiKeys }: Props) => {
|
||||
const [apiKey, setApiKey] = useState('');
|
||||
const [apiKeyName, setApiKeyName] = useState('');
|
||||
const [apiKeyExpiresIn, setApiKeyExpiresIn] = useState('1 day');
|
||||
@@ -42,7 +37,7 @@ const AddApiKeyDialog = ({
|
||||
const generateAPIKey = async () => {
|
||||
const newApiKey = await addAPIKey({
|
||||
name: apiKeyName,
|
||||
expiresIn: expiryMapping[apiKeyExpiresIn as keyof typeof expiryMapping],
|
||||
expiresIn: expiryMapping[apiKeyExpiresIn as keyof typeof expiryMapping]
|
||||
});
|
||||
|
||||
setApiKeys([...apiKeys, newApiKey.apiKeyData]);
|
||||
@@ -73,143 +68,130 @@ const AddApiKeyDialog = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<div className='z-50'>
|
||||
<div className="z-50">
|
||||
<Transition appear show={isOpen} as={Fragment}>
|
||||
<Dialog as='div' className='relative' onClose={closeModal}>
|
||||
<Dialog as="div" className="relative" onClose={closeModal}>
|
||||
<Transition.Child
|
||||
as={Fragment}
|
||||
enter='ease-out duration-300'
|
||||
enterFrom='opacity-0'
|
||||
enterTo='opacity-100'
|
||||
leave='ease-in duration-200'
|
||||
leaveFrom='opacity-100'
|
||||
leaveTo='opacity-0'
|
||||
enter="ease-out duration-300"
|
||||
enterFrom="opacity-0"
|
||||
enterTo="opacity-100"
|
||||
leave="ease-in duration-200"
|
||||
leaveFrom="opacity-100"
|
||||
leaveTo="opacity-0"
|
||||
>
|
||||
<div className='fixed inset-0 bg-bunker-700 bg-opacity-80' />
|
||||
<div className="fixed inset-0 bg-bunker-700 bg-opacity-80" />
|
||||
</Transition.Child>
|
||||
|
||||
<div className='fixed inset-0 overflow-y-auto'>
|
||||
<div className='flex min-h-full items-center justify-center p-4 text-center'>
|
||||
<div className="fixed inset-0 overflow-y-auto">
|
||||
<div className="flex min-h-full items-center justify-center p-4 text-center">
|
||||
<Transition.Child
|
||||
as={Fragment}
|
||||
enter='ease-out duration-300'
|
||||
enterFrom='opacity-0 scale-95'
|
||||
enterTo='opacity-100 scale-100'
|
||||
leave='ease-in duration-200'
|
||||
leaveFrom='opacity-100 scale-100'
|
||||
leaveTo='opacity-0 scale-95'
|
||||
enter="ease-out duration-300"
|
||||
enterFrom="opacity-0 scale-95"
|
||||
enterTo="opacity-100 scale-100"
|
||||
leave="ease-in duration-200"
|
||||
leaveFrom="opacity-100 scale-100"
|
||||
leaveTo="opacity-0 scale-95"
|
||||
>
|
||||
{apiKey === '' ? (
|
||||
<Dialog.Panel className='w-full max-w-md transform rounded-md bg-bunker-800 border border-gray-700 p-6 text-left align-middle shadow-xl transition-all'>
|
||||
<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.Title
|
||||
as='h3'
|
||||
className='text-lg font-medium leading-6 text-gray-400 z-50'
|
||||
as="h3"
|
||||
className="z-50 text-lg font-medium leading-6 text-gray-400"
|
||||
>
|
||||
{t('section-api-key:add-dialog.title')}
|
||||
{t('section.api-key.add-dialog.title')}
|
||||
</Dialog.Title>
|
||||
<div className='mt-2 mb-4'>
|
||||
<div className='flex flex-col'>
|
||||
<p className='text-sm text-gray-500'>
|
||||
{t('section-api-key:add-dialog.description')}
|
||||
<div className="mt-2 mb-4">
|
||||
<div className="flex flex-col">
|
||||
<p className="text-sm text-gray-500">
|
||||
{t('section.api-key.add-dialog.description')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className='max-h-28 mb-2'>
|
||||
<div className="mb-2 max-h-28">
|
||||
<InputField
|
||||
label={t('section-api-key:add-dialog.name')}
|
||||
label={t('section.api-key.add-dialog.name')}
|
||||
onChangeHandler={setApiKeyName}
|
||||
type='varName'
|
||||
type="varName"
|
||||
value={apiKeyName}
|
||||
placeholder=''
|
||||
placeholder=""
|
||||
isRequired
|
||||
/>
|
||||
</div>
|
||||
<div className='max-h-28'>
|
||||
<div className="max-h-28">
|
||||
<ListBox
|
||||
isSelected={apiKeyExpiresIn}
|
||||
onChange={setApiKeyExpiresIn}
|
||||
data={[
|
||||
'1 day',
|
||||
'7 days',
|
||||
'1 month',
|
||||
'6 months',
|
||||
'12 months',
|
||||
]}
|
||||
data={['1 day', '7 days', '1 month', '6 months', '12 months']}
|
||||
isFull
|
||||
text={`${t('common:expired-in')}: `}
|
||||
text={`${t('common.expired-in')}: `}
|
||||
/>
|
||||
</div>
|
||||
<div className='max-w-max'>
|
||||
<div className='mt-6 flex flex-col justify-start w-max'>
|
||||
<div className="max-w-max">
|
||||
<div className="mt-6 flex w-max flex-col justify-start">
|
||||
<Button
|
||||
onButtonPressed={() => generateAPIKey()}
|
||||
color='mineshaft'
|
||||
text={t('section-api-key:add-dialog.add') as string}
|
||||
textDisabled={
|
||||
t('section-api-key:add-dialog.add') as string
|
||||
}
|
||||
size='md'
|
||||
color="mineshaft"
|
||||
text={t('section.api-key.add-dialog.add') as string}
|
||||
textDisabled={t('section.api-key.add-dialog.add') as string}
|
||||
size="md"
|
||||
active={apiKeyName !== ''}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Dialog.Panel>
|
||||
) : (
|
||||
<Dialog.Panel className='w-full max-w-md transform rounded-md bg-bunker-800 border border-gray-700 p-6 text-left align-middle shadow-xl transition-all'>
|
||||
<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.Title
|
||||
as='h3'
|
||||
className='text-lg font-medium leading-6 text-gray-400 z-50'
|
||||
as="h3"
|
||||
className="z-50 text-lg font-medium leading-6 text-gray-400"
|
||||
>
|
||||
{t('section-api-key:add-dialog.copy-service-token')}
|
||||
{t('section.api-key.add-dialog.copy-service-token')}
|
||||
</Dialog.Title>
|
||||
<div className='mt-2 mb-4'>
|
||||
<div className='flex flex-col'>
|
||||
<p className='text-sm text-gray-500'>
|
||||
{t(
|
||||
'section-api-key:add-dialog.copy-service-token-description'
|
||||
)}
|
||||
<div className="mt-2 mb-4">
|
||||
<div className="flex flex-col">
|
||||
<p className="text-sm text-gray-500">
|
||||
{t('section.api-key.add-dialog.copy-service-token-description')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className='w-full'>
|
||||
<div className='flex justify-end items-center bg-white/[0.07] text-base mt-2 mr-2 rounded-md text-gray-400 w-full h-20'>
|
||||
<div className="w-full">
|
||||
<div className="mt-2 mr-2 flex h-20 w-full items-center justify-end rounded-md bg-white/[0.07] text-base text-gray-400">
|
||||
<input
|
||||
type='text'
|
||||
type="text"
|
||||
value={apiKey}
|
||||
disabled
|
||||
id='apiKey'
|
||||
className='invisible bg-white/0 text-gray-400 py-2 w-full px-2 min-w-full outline-none'
|
||||
/>
|
||||
<div className='bg-white/0 max-w-md text-sm text-gray-400 py-2 w-full pl-14 pr-2 break-words outline-none'>
|
||||
id="apiKey"
|
||||
className="invisible w-full min-w-full bg-white/0 py-2 px-2 text-gray-400 outline-none"
|
||||
/>
|
||||
<div className="w-full max-w-md break-words bg-white/0 py-2 pl-14 pr-2 text-sm text-gray-400 outline-none">
|
||||
{apiKey}
|
||||
</div>
|
||||
<div className='group font-normal h-full relative inline-block text-gray-400 underline hover:text-primary duration-200'>
|
||||
<div className="group relative inline-block h-full font-normal text-gray-400 underline duration-200 hover:text-primary">
|
||||
<button
|
||||
type="button"
|
||||
onClick={copyToClipboard}
|
||||
className='h-full pl-3.5 pr-4 border-l border-white/20 py-2 hover:bg-white/[0.12] duration-200'
|
||||
className="h-full border-l border-white/20 py-2 pl-3.5 pr-4 duration-200 hover:bg-white/[0.12]"
|
||||
>
|
||||
{apiKeyCopied ? (
|
||||
<FontAwesomeIcon
|
||||
icon={faCheck}
|
||||
className='pr-0.5'
|
||||
/>
|
||||
<FontAwesomeIcon icon={faCheck} className="pr-0.5" />
|
||||
) : (
|
||||
<FontAwesomeIcon icon={faCopy} />
|
||||
)}
|
||||
</button>
|
||||
<span className='absolute hidden group-hover:flex group-hover:animate-popup duration-300 w-28 -left-8 -top-20 translate-y-full px-3 py-2 bg-chicago-900 rounded-md text-center text-gray-400 text-sm'>
|
||||
{t('common:click-to-copy')}
|
||||
<span className="absolute -left-8 -top-20 hidden w-28 translate-y-full rounded-md bg-chicago-900 px-3 py-2 text-center text-sm text-gray-400 duration-300 group-hover:flex group-hover:animate-popup">
|
||||
{t('common.click-to-copy')}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='mt-6 flex flex-col justify-start w-max'>
|
||||
<div className="mt-6 flex w-max flex-col justify-start">
|
||||
<Button
|
||||
onButtonPressed={() => closeAddApiKeyModal()}
|
||||
color='mineshaft'
|
||||
text='Close'
|
||||
size='md'
|
||||
color="mineshaft"
|
||||
text="Close"
|
||||
size="md"
|
||||
/>
|
||||
</div>
|
||||
</Dialog.Panel>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Fragment, useState } from 'react';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Dialog, Transition } from '@headlessui/react';
|
||||
|
||||
import addIncidentContact from '@app/pages/api/organization/addIncidentContact';
|
||||
@@ -18,7 +18,7 @@ const AddIncidentContactDialog = ({
|
||||
isOpen,
|
||||
closeModal,
|
||||
incidentContacts,
|
||||
setIncidentContacts,
|
||||
setIncidentContacts
|
||||
}: Props) => {
|
||||
const [incidentContactEmail, setIncidentContactEmail] = useState('');
|
||||
const { t } = useTranslation();
|
||||
@@ -29,69 +29,61 @@ const AddIncidentContactDialog = ({
|
||||
? incidentContacts.concat([incidentContactEmail])
|
||||
: [incidentContactEmail]
|
||||
);
|
||||
addIncidentContact(
|
||||
localStorage.getItem('orgData.id') as string,
|
||||
incidentContactEmail
|
||||
);
|
||||
addIncidentContact(localStorage.getItem('orgData.id') as string, incidentContactEmail);
|
||||
closeModal();
|
||||
};
|
||||
return (
|
||||
<div>
|
||||
<Transition appear show={isOpen} as={Fragment}>
|
||||
<Dialog as='div' className='relative z-10' onClose={closeModal}>
|
||||
<Dialog as="div" className="relative z-10" onClose={closeModal}>
|
||||
<Transition.Child
|
||||
as={Fragment}
|
||||
enter='ease-out duration-300'
|
||||
enterFrom='opacity-0'
|
||||
enterTo='opacity-100'
|
||||
leave='ease-in duration-200'
|
||||
leaveFrom='opacity-100'
|
||||
leaveTo='opacity-0'
|
||||
enter="ease-out duration-300"
|
||||
enterFrom="opacity-0"
|
||||
enterTo="opacity-100"
|
||||
leave="ease-in duration-200"
|
||||
leaveFrom="opacity-100"
|
||||
leaveTo="opacity-0"
|
||||
>
|
||||
<div className='fixed inset-0 bg-black bg-opacity-70' />
|
||||
<div className="fixed inset-0 bg-black bg-opacity-70" />
|
||||
</Transition.Child>
|
||||
|
||||
<div className='fixed inset-0 overflow-y-auto'>
|
||||
<div className='flex min-h-full items-center justify-center p-4 text-center'>
|
||||
<div className="fixed inset-0 overflow-y-auto">
|
||||
<div className="flex min-h-full items-center justify-center p-4 text-center">
|
||||
<Transition.Child
|
||||
as={Fragment}
|
||||
enter='ease-out duration-300'
|
||||
enterFrom='opacity-0 scale-95'
|
||||
enterTo='opacity-100 scale-100'
|
||||
leave='ease-in duration-200'
|
||||
leaveFrom='opacity-100 scale-100'
|
||||
leaveTo='opacity-0 scale-95'
|
||||
enter="ease-out duration-300"
|
||||
enterFrom="opacity-0 scale-95"
|
||||
enterTo="opacity-100 scale-100"
|
||||
leave="ease-in duration-200"
|
||||
leaveFrom="opacity-100 scale-100"
|
||||
leaveTo="opacity-0 scale-95"
|
||||
>
|
||||
<Dialog.Panel className='w-full max-w-md transform overflow-hidden rounded-md bg-bunker-800 border border-gray-700 p-6 text-left align-middle shadow-xl transition-all'>
|
||||
<Dialog.Title
|
||||
as='h3'
|
||||
className='text-lg font-medium leading-6 text-gray-400'
|
||||
>
|
||||
{t('section-incident:add-dialog.title')}
|
||||
<Dialog.Panel className="w-full max-w-md transform overflow-hidden rounded-md border border-gray-700 bg-bunker-800 p-6 text-left align-middle shadow-xl transition-all">
|
||||
<Dialog.Title as="h3" className="text-lg font-medium leading-6 text-gray-400">
|
||||
{t('section.incident.add-dialog.title')}
|
||||
</Dialog.Title>
|
||||
<div className='mt-2 mb-2'>
|
||||
<p className='text-sm text-gray-500'>
|
||||
{t('section-incident:add-dialog.description')}
|
||||
<div className="mt-2 mb-2">
|
||||
<p className="text-sm text-gray-500">
|
||||
{t('section.incident.add-dialog.description')}
|
||||
</p>
|
||||
</div>
|
||||
<div className='max-h-28'>
|
||||
<div className="max-h-28">
|
||||
<InputField
|
||||
label={t('common:email')}
|
||||
label={t('common.email')}
|
||||
onChangeHandler={setIncidentContactEmail}
|
||||
type='varName'
|
||||
type="varName"
|
||||
value={incidentContactEmail}
|
||||
placeholder=''
|
||||
placeholder=""
|
||||
isRequired
|
||||
/>
|
||||
</div>
|
||||
<div className='mt-6 max-w-max'>
|
||||
<div className="mt-6 max-w-max">
|
||||
<Button
|
||||
onButtonPressed={submit}
|
||||
color='mineshaft'
|
||||
text={
|
||||
t('section-incident:add-dialog.add-incident') as string
|
||||
}
|
||||
size='md'
|
||||
color="mineshaft"
|
||||
text={t('section.incident.add-dialog.add-incident') as string}
|
||||
size="md"
|
||||
/>
|
||||
</div>
|
||||
</Dialog.Panel>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Fragment } from 'react';
|
||||
import { Trans, useTranslation } from 'react-i18next';
|
||||
import { useRouter } from 'next/router';
|
||||
import { Trans, useTranslation } from 'next-i18next';
|
||||
import { Dialog, Transition } from '@headlessui/react';
|
||||
|
||||
import Button from '../buttons/Button';
|
||||
@@ -21,7 +21,7 @@ const AddProjectMemberDialog = ({
|
||||
submitModal,
|
||||
data,
|
||||
email,
|
||||
setEmail,
|
||||
setEmail
|
||||
}: Props) => {
|
||||
const router = useRouter();
|
||||
const { t } = useTranslation();
|
||||
@@ -53,31 +53,31 @@ const AddProjectMemberDialog = ({
|
||||
leaveFrom="opacity-100 scale-100"
|
||||
leaveTo="opacity-0 scale-95"
|
||||
>
|
||||
<Dialog.Panel className="w-full max-w-md transform rounded-md bg-bunker-800 border border-gray-700 p-6 text-left align-middle shadow-xl transition-all">
|
||||
<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">
|
||||
{data?.length > 0 ? (
|
||||
<Dialog.Title
|
||||
as="h3"
|
||||
className="text-lg font-medium leading-6 text-gray-400 z-50"
|
||||
className="z-50 text-lg font-medium leading-6 text-gray-400"
|
||||
>
|
||||
{t('section-members:add-dialog.add-member-to-project')}
|
||||
{t('section.members.add-dialog.add-member-to-project')}
|
||||
</Dialog.Title>
|
||||
) : (
|
||||
<Dialog.Title
|
||||
as="h3"
|
||||
className="text-lg font-medium leading-6 text-gray-400 z-50"
|
||||
className="z-50 text-lg font-medium leading-6 text-gray-400"
|
||||
>
|
||||
{t('section-members:add-dialog.already-all-invited')}
|
||||
{t('section.members.add-dialog.already-all-invited')}
|
||||
</Dialog.Title>
|
||||
)}
|
||||
<div className="mt-2 mb-4">
|
||||
{data?.length > 0 ? (
|
||||
<div className="flex flex-col">
|
||||
<p className="text-sm text-gray-500">
|
||||
{t('section-members:add-dialog.user-will-email')}
|
||||
{t('section.members.add-dialog.user-will-email')}
|
||||
</p>
|
||||
<div className="">
|
||||
<Trans
|
||||
i18nKey="section-members:add-dialog.looking-add"
|
||||
i18nKey="section.members.add-dialog.looking-add"
|
||||
components={[
|
||||
// eslint-disable-next-line react/jsx-key
|
||||
<button
|
||||
@@ -101,22 +101,27 @@ const AddProjectMemberDialog = ({
|
||||
</div>
|
||||
) : (
|
||||
<p className="text-sm text-gray-500">
|
||||
{t('section-members:add-dialog.add-user-org-first')}
|
||||
{t('section.members.add-dialog.add-user-org-first')}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<div className="max-h-28">
|
||||
{data?.length > 0 && (
|
||||
<ListBox isSelected={email || data[0]} onChange={setEmail} data={data} isFull />
|
||||
<ListBox
|
||||
isSelected={email || data[0]}
|
||||
onChange={setEmail}
|
||||
data={data}
|
||||
isFull
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className="max-w-max">
|
||||
{data?.length > 0 ? (
|
||||
<div className="mt-6 flex flex-col justify-start w-max">
|
||||
<div className="mt-6 flex w-max flex-col justify-start">
|
||||
<Button
|
||||
onButtonPressed={submitModal}
|
||||
color="mineshaft"
|
||||
text={t('section-members:add-member') as string}
|
||||
text={t('section.members.add-member') as string}
|
||||
size="md"
|
||||
/>
|
||||
</div>
|
||||
@@ -124,7 +129,7 @@ const AddProjectMemberDialog = ({
|
||||
<Button
|
||||
onButtonPressed={() => router.push(`/settings/org/${router.query.id}`)}
|
||||
color="mineshaft"
|
||||
text={t('section-members:add-dialog.add-user-to-org') as string}
|
||||
text={t('section.members.add-dialog.add-user-to-org') as string}
|
||||
size="md"
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import crypto from 'crypto';
|
||||
|
||||
import { Fragment, useState } from 'react';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { faCheck, faCopy } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { Dialog, Transition } from '@headlessui/react';
|
||||
@@ -9,10 +9,7 @@ import { Dialog, Transition } from '@headlessui/react';
|
||||
import addServiceToken from '@app/pages/api/serviceToken/addServiceToken';
|
||||
import getLatestFileKey from '@app/pages/api/workspace/getLatestFileKey';
|
||||
|
||||
import {
|
||||
decryptAssymmetric,
|
||||
encryptSymmetric,
|
||||
} from '../../utilities/cryptography/crypto';
|
||||
import { decryptAssymmetric, encryptSymmetric } from '../../utilities/cryptography/crypto';
|
||||
import Button from '../buttons/Button';
|
||||
import InputField from '../InputField';
|
||||
import ListBox from '../Listbox';
|
||||
@@ -22,7 +19,7 @@ const expiryMapping = {
|
||||
'7 days': 604800,
|
||||
'1 month': 2592000,
|
||||
'6 months': 15552000,
|
||||
'12 months': 31104000,
|
||||
'12 months': 31104000
|
||||
};
|
||||
|
||||
type Props = {
|
||||
@@ -42,13 +39,11 @@ const AddServiceTokenDialog = ({
|
||||
workspaceName,
|
||||
serviceTokens,
|
||||
environments,
|
||||
setServiceTokens,
|
||||
setServiceTokens
|
||||
}: Props) => {
|
||||
const [serviceToken, setServiceToken] = useState('');
|
||||
const [serviceTokenName, setServiceTokenName] = useState('');
|
||||
const [selectedServiceTokenEnv, setSelectedServiceTokenEnv] = useState(
|
||||
environments?.[0]
|
||||
);
|
||||
const [selectedServiceTokenEnv, setSelectedServiceTokenEnv] = useState(environments?.[0]);
|
||||
const [serviceTokenExpiresIn, setServiceTokenExpiresIn] = useState('1 day');
|
||||
const [serviceTokenCopied, setServiceTokenCopied] = useState(false);
|
||||
const { t } = useTranslation();
|
||||
@@ -60,40 +55,40 @@ const AddServiceTokenDialog = ({
|
||||
ciphertext: latestFileKey.latestKey.encryptedKey,
|
||||
nonce: latestFileKey.latestKey.nonce,
|
||||
publicKey: latestFileKey.latestKey.sender.publicKey,
|
||||
privateKey: localStorage.getItem('PRIVATE_KEY') as string,
|
||||
privateKey: localStorage.getItem('PRIVATE_KEY') as string
|
||||
});
|
||||
|
||||
const randomBytes = crypto.randomBytes(16).toString('hex');
|
||||
const { ciphertext, iv, tag } = encryptSymmetric({
|
||||
plaintext: key,
|
||||
key: randomBytes,
|
||||
key: randomBytes
|
||||
});
|
||||
|
||||
console.log(1234, selectedServiceTokenEnv, environments, selectedServiceTokenEnv?.slug
|
||||
? selectedServiceTokenEnv.slug
|
||||
: environments[0]?.slug)
|
||||
|
||||
console.log(
|
||||
1234,
|
||||
selectedServiceTokenEnv,
|
||||
environments,
|
||||
selectedServiceTokenEnv?.slug ? selectedServiceTokenEnv.slug : environments[0]?.slug
|
||||
);
|
||||
const newServiceToken = await addServiceToken({
|
||||
name: serviceTokenName,
|
||||
workspaceId,
|
||||
environment: selectedServiceTokenEnv?.slug
|
||||
? selectedServiceTokenEnv.slug
|
||||
: environments[0]?.slug,
|
||||
expiresIn:
|
||||
expiryMapping[serviceTokenExpiresIn as keyof typeof expiryMapping],
|
||||
expiresIn: expiryMapping[serviceTokenExpiresIn as keyof typeof expiryMapping],
|
||||
encryptedKey: ciphertext,
|
||||
iv,
|
||||
tag,
|
||||
tag
|
||||
});
|
||||
|
||||
setServiceTokens(serviceTokens.concat([newServiceToken.serviceTokenData]));
|
||||
setServiceToken(`${newServiceToken.serviceToken }.${ randomBytes}`);
|
||||
setServiceToken(`${newServiceToken.serviceToken}.${randomBytes}`);
|
||||
};
|
||||
|
||||
function copyToClipboard() {
|
||||
// Get the text field
|
||||
const copyText = document.getElementById(
|
||||
'serviceToken'
|
||||
) as HTMLInputElement;
|
||||
const copyText = document.getElementById('serviceToken') as HTMLInputElement;
|
||||
|
||||
// Select the text field
|
||||
copyText.select();
|
||||
@@ -115,60 +110,60 @@ const AddServiceTokenDialog = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<div className='z-50'>
|
||||
<div className="z-50">
|
||||
<Transition appear show={isOpen} as={Fragment}>
|
||||
<Dialog as='div' className='relative' onClose={closeModal}>
|
||||
<Dialog as="div" className="relative" onClose={closeModal}>
|
||||
<Transition.Child
|
||||
as={Fragment}
|
||||
enter='ease-out duration-300'
|
||||
enterFrom='opacity-0'
|
||||
enterTo='opacity-100'
|
||||
leave='ease-in duration-200'
|
||||
leaveFrom='opacity-100'
|
||||
leaveTo='opacity-0'
|
||||
enter="ease-out duration-300"
|
||||
enterFrom="opacity-0"
|
||||
enterTo="opacity-100"
|
||||
leave="ease-in duration-200"
|
||||
leaveFrom="opacity-100"
|
||||
leaveTo="opacity-0"
|
||||
>
|
||||
<div className='fixed inset-0 bg-bunker-700 bg-opacity-80' />
|
||||
<div className="fixed inset-0 bg-bunker-700 bg-opacity-80" />
|
||||
</Transition.Child>
|
||||
|
||||
<div className='fixed inset-0 overflow-y-auto'>
|
||||
<div className='flex min-h-full items-center justify-center p-4 text-center'>
|
||||
<div className="fixed inset-0 overflow-y-auto">
|
||||
<div className="flex min-h-full items-center justify-center p-4 text-center">
|
||||
<Transition.Child
|
||||
as={Fragment}
|
||||
enter='ease-out duration-300'
|
||||
enterFrom='opacity-0 scale-95'
|
||||
enterTo='opacity-100 scale-100'
|
||||
leave='ease-in duration-200'
|
||||
leaveFrom='opacity-100 scale-100'
|
||||
leaveTo='opacity-0 scale-95'
|
||||
enter="ease-out duration-300"
|
||||
enterFrom="opacity-0 scale-95"
|
||||
enterTo="opacity-100 scale-100"
|
||||
leave="ease-in duration-200"
|
||||
leaveFrom="opacity-100 scale-100"
|
||||
leaveTo="opacity-0 scale-95"
|
||||
>
|
||||
{serviceToken === '' ? (
|
||||
<Dialog.Panel className='w-full max-w-md transform rounded-md bg-bunker-800 border border-gray-700 p-6 text-left align-middle shadow-xl transition-all'>
|
||||
<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.Title
|
||||
as='h3'
|
||||
className='text-lg font-medium leading-6 text-gray-400 z-50'
|
||||
as="h3"
|
||||
className="z-50 text-lg font-medium leading-6 text-gray-400"
|
||||
>
|
||||
{t('section-token:add-dialog.title', {
|
||||
target: workspaceName,
|
||||
{t('section.token.add-dialog.title', {
|
||||
target: workspaceName
|
||||
})}
|
||||
</Dialog.Title>
|
||||
<div className='mt-2 mb-4'>
|
||||
<div className='flex flex-col'>
|
||||
<p className='text-sm text-gray-500'>
|
||||
{t('section-token:add-dialog.description')}
|
||||
<div className="mt-2 mb-4">
|
||||
<div className="flex flex-col">
|
||||
<p className="text-sm text-gray-500">
|
||||
{t('section.token.add-dialog.description')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className='max-h-28 mb-2'>
|
||||
<div className="mb-2 max-h-28">
|
||||
<InputField
|
||||
label={t('section-token:add-dialog.name')}
|
||||
label={t('section.token.add-dialog.name')}
|
||||
onChangeHandler={setServiceTokenName}
|
||||
type='varName'
|
||||
type="varName"
|
||||
value={serviceTokenName}
|
||||
placeholder=''
|
||||
placeholder=""
|
||||
isRequired
|
||||
/>
|
||||
</div>
|
||||
<div className='max-h-28 mb-2'>
|
||||
<div className="mb-2 max-h-28">
|
||||
<ListBox
|
||||
isSelected={
|
||||
selectedServiceTokenEnv?.name
|
||||
@@ -178,103 +173,88 @@ const AddServiceTokenDialog = ({
|
||||
data={environments.map(({ name }) => name)}
|
||||
onChange={(envName) =>
|
||||
setSelectedServiceTokenEnv(
|
||||
environments.find(
|
||||
({ name }) => envName === name
|
||||
) || {
|
||||
environments.find(({ name }) => envName === name) || {
|
||||
name: 'unknown',
|
||||
slug: 'unknown',
|
||||
slug: 'unknown'
|
||||
}
|
||||
)
|
||||
}
|
||||
isFull
|
||||
text={`${t('common:environment')}: `}
|
||||
text={`${t('common.environment')}: `}
|
||||
/>
|
||||
</div>
|
||||
<div className='max-h-28'>
|
||||
<div className="max-h-28">
|
||||
<ListBox
|
||||
isSelected={serviceTokenExpiresIn}
|
||||
onChange={setServiceTokenExpiresIn}
|
||||
data={[
|
||||
'1 day',
|
||||
'7 days',
|
||||
'1 month',
|
||||
'6 months',
|
||||
'12 months',
|
||||
]}
|
||||
data={['1 day', '7 days', '1 month', '6 months', '12 months']}
|
||||
isFull
|
||||
text={`${t('common:expired-in')}: `}
|
||||
text={`${t('common.expired-in')}: `}
|
||||
/>
|
||||
</div>
|
||||
<div className='max-w-max'>
|
||||
<div className='mt-6 flex flex-col justify-start w-max'>
|
||||
<div className="max-w-max">
|
||||
<div className="mt-6 flex w-max flex-col justify-start">
|
||||
<Button
|
||||
onButtonPressed={() => generateServiceToken()}
|
||||
color='mineshaft'
|
||||
text={t('section-token:add-dialog.add') as string}
|
||||
textDisabled={
|
||||
t('section-token:add-dialog.add') as string
|
||||
}
|
||||
size='md'
|
||||
color="mineshaft"
|
||||
text={t('section.token.add-dialog.add') as string}
|
||||
textDisabled={t('section.token.add-dialog.add') as string}
|
||||
size="md"
|
||||
active={serviceTokenName !== ''}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Dialog.Panel>
|
||||
) : (
|
||||
<Dialog.Panel className='w-full max-w-md transform rounded-md bg-bunker-800 border border-gray-700 p-6 text-left align-middle shadow-xl transition-all'>
|
||||
<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.Title
|
||||
as='h3'
|
||||
className='text-lg font-medium leading-6 text-gray-400 z-50'
|
||||
as="h3"
|
||||
className="z-50 text-lg font-medium leading-6 text-gray-400"
|
||||
>
|
||||
{t('section-token:add-dialog.copy-service-token')}
|
||||
{t('section.token.add-dialog.copy-service-token')}
|
||||
</Dialog.Title>
|
||||
<div className='mt-2 mb-4'>
|
||||
<div className='flex flex-col'>
|
||||
<p className='text-sm text-gray-500'>
|
||||
{t(
|
||||
'section-token:add-dialog.copy-service-token-description'
|
||||
)}
|
||||
<div className="mt-2 mb-4">
|
||||
<div className="flex flex-col">
|
||||
<p className="text-sm text-gray-500">
|
||||
{t('section.token.add-dialog.copy-service-token-description')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className='w-full'>
|
||||
<div className='flex justify-end items-center bg-white/[0.07] text-base mt-2 mr-2 rounded-md text-gray-400 w-full h-20'>
|
||||
<div className="w-full">
|
||||
<div className="mt-2 mr-2 flex h-20 w-full items-center justify-end rounded-md bg-white/[0.07] text-base text-gray-400">
|
||||
<input
|
||||
type='text'
|
||||
type="text"
|
||||
value={serviceToken}
|
||||
id='serviceToken'
|
||||
className='invisible bg-white/0 text-gray-400 py-2 w-full px-2 min-w-full outline-none'
|
||||
/>
|
||||
<div className='bg-white/0 max-w-md text-sm text-gray-400 py-2 w-full pl-14 pr-2 break-words outline-none'>
|
||||
id="serviceToken"
|
||||
className="invisible w-full min-w-full bg-white/0 py-2 px-2 text-gray-400 outline-none"
|
||||
/>
|
||||
<div className="w-full max-w-md break-words bg-white/0 py-2 pl-14 pr-2 text-sm text-gray-400 outline-none">
|
||||
{serviceToken}
|
||||
</div>
|
||||
<div className='group font-normal h-full relative inline-block text-gray-400 underline hover:text-primary duration-200'>
|
||||
<div className="group relative inline-block h-full font-normal text-gray-400 underline duration-200 hover:text-primary">
|
||||
<button
|
||||
onClick={copyToClipboard}
|
||||
type="button"
|
||||
className='h-full pl-3.5 pr-4 border-l border-white/20 py-2 hover:bg-white/[0.12] duration-200'
|
||||
className="h-full border-l border-white/20 py-2 pl-3.5 pr-4 duration-200 hover:bg-white/[0.12]"
|
||||
>
|
||||
{serviceTokenCopied ? (
|
||||
<FontAwesomeIcon
|
||||
icon={faCheck}
|
||||
className='pr-0.5'
|
||||
/>
|
||||
<FontAwesomeIcon icon={faCheck} className="pr-0.5" />
|
||||
) : (
|
||||
<FontAwesomeIcon icon={faCopy} />
|
||||
)}
|
||||
</button>
|
||||
<span className='absolute hidden group-hover:flex group-hover:animate-popup duration-300 w-28 -left-8 -top-20 translate-y-full px-3 py-2 bg-chicago-900 rounded-md text-center text-gray-400 text-sm'>
|
||||
{t('common:click-to-copy')}
|
||||
<span className="absolute -left-8 -top-20 hidden w-28 translate-y-full rounded-md bg-chicago-900 px-3 py-2 text-center text-sm text-gray-400 duration-300 group-hover:flex group-hover:animate-popup">
|
||||
{t('common.click-to-copy')}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='mt-6 flex flex-col justify-start w-max'>
|
||||
<div className="mt-6 flex w-max flex-col justify-start">
|
||||
<Button
|
||||
onButtonPressed={() => closeAddServiceTokenModal()}
|
||||
color='mineshaft'
|
||||
text='Close'
|
||||
size='md'
|
||||
color="mineshaft"
|
||||
text="Close"
|
||||
size="md"
|
||||
/>
|
||||
</div>
|
||||
</Dialog.Panel>
|
||||
|
||||
Reference in New Issue
Block a user