mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-11 19:28:58 +00:00
Finished the first ddraft of the dashboard sidebar
This commit is contained in:
@@ -0,0 +1,28 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { Switch } from "@headlessui/react";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a typical 'iPhone' toggle (e.g., user for overriding secrets with personal values)
|
||||||
|
* @param obj
|
||||||
|
* @param {boolean} obj.enabled - whether the toggle is turned on or off
|
||||||
|
* @param {function} obj.setEnabled - change the state of the toggle
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export default function Toggle ({ enabled, setEnabled }: { enabled: boolean; setEnabled: (value: boolean) => void; }): JSX.Element {
|
||||||
|
return (
|
||||||
|
<Switch
|
||||||
|
checked={enabled}
|
||||||
|
onChange={setEnabled}
|
||||||
|
className={`${
|
||||||
|
enabled ? 'bg-primary' : 'bg-bunker-400'
|
||||||
|
} relative inline-flex h-5 w-9 items-center rounded-full`}
|
||||||
|
>
|
||||||
|
<span className="sr-only">Enable notifications</span>
|
||||||
|
<span
|
||||||
|
className={`${
|
||||||
|
enabled ? 'translate-x-[1.26rem]' : 'translate-x-0.5'
|
||||||
|
} inline-block h-3.5 w-3.5 transform rounded-full bg-bunker-800 transition`}
|
||||||
|
/>
|
||||||
|
</Switch>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -80,7 +80,7 @@ export default function Button(props: ButtonProps): JSX.Element {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const textStyle = classNames(
|
const textStyle = classNames(
|
||||||
"relative duration-200",
|
"relative duration-200 text-center w-full",
|
||||||
|
|
||||||
// Show the loading sign if the loading indicator is on
|
// Show the loading sign if the loading indicator is on
|
||||||
props.loading ? "opacity-0" : "opacity-100",
|
props.loading ? "opacity-0" : "opacity-100",
|
||||||
|
|||||||
@@ -0,0 +1,93 @@
|
|||||||
|
import { Fragment,useState } from 'react';
|
||||||
|
import { faShuffle } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
|
import { Menu, Transition } from '@headlessui/react';
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the menu that is used to (re)generate secrets (currently we only have ranom hex, in future we will have more options)
|
||||||
|
* @returns the popup-menu for randomly generating secrets
|
||||||
|
*/
|
||||||
|
const GenerateSecretMenu = () => {
|
||||||
|
const [randomStringLength, setRandomStringLength] = useState(32);
|
||||||
|
|
||||||
|
return <Menu as="div" className="relative inline-block text-left">
|
||||||
|
<div>
|
||||||
|
<Menu.Button className="inline-flex w-full justify-center rounded-md text-sm font-medium text-gray-200 rounded-md hover:bg-white/10 duration-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75">
|
||||||
|
<div className='p-1 rounded-md hover:bg-white/5'>
|
||||||
|
<FontAwesomeIcon icon={faShuffle} className='text-bunker-300'/>
|
||||||
|
</div>
|
||||||
|
</Menu.Button>
|
||||||
|
</div>
|
||||||
|
<Transition
|
||||||
|
as={Fragment}
|
||||||
|
enter="transition ease-out duration-100"
|
||||||
|
enterFrom="transform opacity-0 scale-95"
|
||||||
|
enterTo="transform opacity-100 scale-100"
|
||||||
|
leave="transition ease-in duration-75"
|
||||||
|
leaveFrom="transform opacity-100 scale-100"
|
||||||
|
leaveTo="transform opacity-0 scale-95"
|
||||||
|
>
|
||||||
|
<Menu.Items className="absolute z-50 drop-shadow-xl right-0 mt-0.5 w-[20rem] origin-top-right rounded-md bg-bunker border border-mineshaft-500 shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none px-1 py-1">
|
||||||
|
<div
|
||||||
|
onClick={() => {
|
||||||
|
if (randomStringLength > 32) {
|
||||||
|
setRandomStringLength(32);
|
||||||
|
} else if (randomStringLength < 2) {
|
||||||
|
setRandomStringLength(2);
|
||||||
|
} else {
|
||||||
|
// modifyValue(
|
||||||
|
// [...Array(randomStringLength)]
|
||||||
|
// .map(() => Math.floor(Math.random() * 16).toString(16))
|
||||||
|
// .join(''),
|
||||||
|
// keyPair.pos
|
||||||
|
// );
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
className="relative flex flex-row justify-start items-center cursor-pointer select-none py-2 px-2 rounded-md text-gray-400 hover:bg-white/10 duration-200 hover:text-gray-200 w-full"
|
||||||
|
>
|
||||||
|
<FontAwesomeIcon
|
||||||
|
className="text-lg pl-1.5 pr-3"
|
||||||
|
icon={faShuffle}
|
||||||
|
/>
|
||||||
|
<div className="text-sm justify-between flex flex-row w-full">
|
||||||
|
<p>Generate Random Hex</p>
|
||||||
|
<p>digits</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-row absolute bottom-[0.4rem] right-[3.3rem] w-16 bg-bunker-800 border border-chicago-700 rounded-md text-bunker-200 ">
|
||||||
|
<div
|
||||||
|
className="m-0.5 px-1 cursor-pointer rounded-md hover:bg-chicago-700"
|
||||||
|
onClick={() => {
|
||||||
|
if (randomStringLength > 1) {
|
||||||
|
setRandomStringLength(randomStringLength - 1);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
-
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
onChange={(e) =>
|
||||||
|
setRandomStringLength(parseInt(e.target.value))
|
||||||
|
}
|
||||||
|
value={randomStringLength}
|
||||||
|
className="text-center z-20 peer text-sm bg-transparent w-full outline-none"
|
||||||
|
spellCheck="false"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
className="m-0.5 px-1 pb-0.5 cursor-pointer rounded-md hover:bg-chicago-700"
|
||||||
|
onClick={() => {
|
||||||
|
if (randomStringLength < 32) {
|
||||||
|
setRandomStringLength(randomStringLength + 1);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
+
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Menu.Items>
|
||||||
|
</Transition>
|
||||||
|
</Menu>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default GenerateSecretMenu;
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
|
import { faX } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
|
|
||||||
|
import Button from '../basic/buttons/Button';
|
||||||
|
import Toggle from '../basic/Toggle';
|
||||||
|
import DashboardInputField from './DashboardInputField';
|
||||||
|
import GenerateSecretMenu from './GenerateSecretMenu';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns the sidebar with 'secret's settings'
|
||||||
|
*/
|
||||||
|
const SideBar = () => {
|
||||||
|
const [overrideEnabled, setOverrideEnabled] = useState(false)
|
||||||
|
|
||||||
|
return <div className='absolute border-l border-mineshaft-500 bg-bunker fixed h-full w-96 top-14 right-0 z-50 shadow-xl flex flex-col justify-between'>
|
||||||
|
<div className='h-min'>
|
||||||
|
<div className="flex flex-row px-4 py-3 border-b border-mineshaft-500 justify-between items-center">
|
||||||
|
<p className="font-semibold text-lg text-bunker-200">Secret</p>
|
||||||
|
<FontAwesomeIcon icon={faX} className='w-4 h-4 text-bunker-300 cursor-pointer'/>
|
||||||
|
</div>
|
||||||
|
<div className='mt-4 px-4 pointer-events-none'>
|
||||||
|
<p className='text-sm text-bunker-300'>Key</p>
|
||||||
|
<DashboardInputField
|
||||||
|
onChangeHandler={() => {}}
|
||||||
|
type="varName"
|
||||||
|
position={1}
|
||||||
|
value={"KeyKeyKey"}
|
||||||
|
duplicates={[]}
|
||||||
|
blurred={false}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className={`relative mt-2 px-4 ${overrideEnabled && "opacity-40 pointer-events-none"} duration-200`}>
|
||||||
|
<p className='text-sm text-bunker-300'>Value</p>
|
||||||
|
<DashboardInputField
|
||||||
|
onChangeHandler={() => {}}
|
||||||
|
type="value"
|
||||||
|
position={1}
|
||||||
|
value={"ValueValueValue"}
|
||||||
|
duplicates={[]}
|
||||||
|
blurred={true}
|
||||||
|
/>
|
||||||
|
<div className='absolute right-[1.7rem] top-[1.65rem] z-50'>
|
||||||
|
<GenerateSecretMenu />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className='mt-4 px-4'>
|
||||||
|
<div className='flex flex-row items-center justify-between my-2 pl-1 pr-2'>
|
||||||
|
<p className='text-sm text-bunker-300'>Override value with a personal value</p>
|
||||||
|
<Toggle enabled={overrideEnabled} setEnabled={setOverrideEnabled} />
|
||||||
|
</div>
|
||||||
|
<div className={`relative ${!overrideEnabled && "opacity-40 pointer-events-none"} duration-200`}>
|
||||||
|
<DashboardInputField
|
||||||
|
onChangeHandler={() => {}}
|
||||||
|
type="value"
|
||||||
|
position={1}
|
||||||
|
value={"ValueValueValue"}
|
||||||
|
duplicates={[]}
|
||||||
|
blurred={true}
|
||||||
|
/>
|
||||||
|
<div className='absolute right-3 top-[0.3rem] z-50'>
|
||||||
|
<GenerateSecretMenu />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={`mt-6`}>
|
||||||
|
<p className='text-sm text-bunker-300'>Comments & notes</p>
|
||||||
|
<div className='h-32 w-full bg-bunker-800 p-2 rounded-md border border-mineshaft-500 rounded-md text-sm text-bunker-300'>
|
||||||
|
Leave your comment here...
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className='mt-full px-4 mb-[4.7rem]'>
|
||||||
|
<Button
|
||||||
|
onButtonPressed={() => console.log('Saved')}
|
||||||
|
text="Save Changes"
|
||||||
|
color="primary"
|
||||||
|
size="md"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SideBar;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { Fragment, useCallback, useEffect, useState } from 'react';
|
import React, { useCallback, useEffect, useState } from 'react';
|
||||||
import Head from 'next/head';
|
import Head from 'next/head';
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
@@ -14,14 +14,10 @@ import {
|
|||||||
faEyeSlash,
|
faEyeSlash,
|
||||||
faFolderOpen,
|
faFolderOpen,
|
||||||
faMagnifyingGlass,
|
faMagnifyingGlass,
|
||||||
faPeopleGroup,
|
|
||||||
faPerson,
|
|
||||||
faPlus,
|
faPlus,
|
||||||
faShuffle,
|
|
||||||
faX
|
faX
|
||||||
} from '@fortawesome/free-solid-svg-icons';
|
} from '@fortawesome/free-solid-svg-icons';
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { Menu, Transition } from '@headlessui/react';
|
|
||||||
|
|
||||||
import Button from '~/components/basic/buttons/Button';
|
import Button from '~/components/basic/buttons/Button';
|
||||||
import ListBox from '~/components/basic/Listbox';
|
import ListBox from '~/components/basic/Listbox';
|
||||||
@@ -29,14 +25,13 @@ import BottonRightPopup from '~/components/basic/popups/BottomRightPopup';
|
|||||||
import { useNotificationContext } from '~/components/context/Notifications/NotificationProvider';
|
import { useNotificationContext } from '~/components/context/Notifications/NotificationProvider';
|
||||||
import DashboardInputField from '~/components/dashboard/DashboardInputField';
|
import DashboardInputField from '~/components/dashboard/DashboardInputField';
|
||||||
import DropZone from '~/components/dashboard/DropZone';
|
import DropZone from '~/components/dashboard/DropZone';
|
||||||
|
import SideBar from '~/components/dashboard/Sidebar';
|
||||||
import NavHeader from '~/components/navigation/NavHeader';
|
import NavHeader from '~/components/navigation/NavHeader';
|
||||||
import getSecretsForProject from '~/components/utilities/secrets/getSecretsForProject';
|
import getSecretsForProject from '~/components/utilities/secrets/getSecretsForProject';
|
||||||
import pushKeys from '~/components/utilities/secrets/pushKeys';
|
import pushKeys from '~/components/utilities/secrets/pushKeys';
|
||||||
import pushKeysIntegration from '~/components/utilities/secrets/pushKeysIntegration';
|
|
||||||
import guidGenerator from '~/utilities/randomId';
|
import guidGenerator from '~/utilities/randomId';
|
||||||
|
|
||||||
import { envMapping } from '../../public/data/frequentConstants';
|
import { envMapping } from '../../public/data/frequentConstants';
|
||||||
import getWorkspaceIntegrations from '../api/integrations/getWorkspaceIntegrations';
|
|
||||||
import getUser from '../api/user/getUser';
|
import getUser from '../api/user/getUser';
|
||||||
import checkUserAction from '../api/userActions/checkUserAction';
|
import checkUserAction from '../api/userActions/checkUserAction';
|
||||||
import registerUserAction from '../api/userActions/registerUserAction';
|
import registerUserAction from '../api/userActions/registerUserAction';
|
||||||
@@ -63,7 +58,6 @@ const KeyPair = ({
|
|||||||
isBlurred,
|
isBlurred,
|
||||||
duplicates
|
duplicates
|
||||||
}) => {
|
}) => {
|
||||||
const [randomStringLength, setRandomStringLength] = useState(32);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="px-1 flex flex-col items-center ml-1">
|
<div className="px-1 flex flex-col items-center ml-1">
|
||||||
@@ -90,103 +84,12 @@ const KeyPair = ({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Menu as="div" className="relative inline-block text-left">
|
|
||||||
<div>
|
|
||||||
<Menu.Button className="inline-flex w-full justify-center rounded-md text-sm font-medium text-gray-200 rounded-md hover:bg-white/10 duration-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75">
|
|
||||||
<div className="cursor-pointer w-9 h-9 bg-white/10 rounded-md flex flex-row justify-center items-center opacity-50 hover:opacity-100 duration-200">
|
<div className="cursor-pointer w-9 h-9 bg-white/10 rounded-md flex flex-row justify-center items-center opacity-50 hover:opacity-100 duration-200">
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
className="text-gray-300 px-2.5 text-lg mt-0.5"
|
className="text-gray-300 px-2.5 text-lg mt-0.5"
|
||||||
icon={faEllipsis}
|
icon={faEllipsis}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Menu.Button>
|
|
||||||
</div>
|
|
||||||
<Transition
|
|
||||||
as={Fragment}
|
|
||||||
enter="transition ease-out duration-100"
|
|
||||||
enterFrom="transform opacity-0 scale-95"
|
|
||||||
enterTo="transform opacity-100 scale-100"
|
|
||||||
leave="transition ease-in duration-75"
|
|
||||||
leaveFrom="transform opacity-100 scale-100"
|
|
||||||
leaveTo="transform opacity-0 scale-95"
|
|
||||||
>
|
|
||||||
<Menu.Items className="absolute z-50 drop-shadow-xl right-0 mt-0.5 w-[20rem] origin-top-right rounded-md bg-bunker border border-mineshaft-500 shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none px-1 py-1">
|
|
||||||
<div
|
|
||||||
onClick={() =>
|
|
||||||
modifyVisibility(
|
|
||||||
keyPair.type == 'personal' ? 'shared' : 'personal',
|
|
||||||
keyPair.pos
|
|
||||||
)
|
|
||||||
}
|
|
||||||
className="relative flex justify-start items-center cursor-pointer select-none py-2 px-2 rounded-md text-gray-400 hover:bg-white/10 duration-200 hover:text-gray-200 w-full"
|
|
||||||
>
|
|
||||||
<FontAwesomeIcon
|
|
||||||
className="text-lg pl-1.5 pr-3"
|
|
||||||
icon={keyPair.type == 'personal' ? faPeopleGroup : faPerson}
|
|
||||||
/>
|
|
||||||
<div className="text-sm">
|
|
||||||
{keyPair.type == 'personal' ? 'Make Shared' : 'Make Personal'}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
onClick={() => {
|
|
||||||
if (randomStringLength > 32) {
|
|
||||||
setRandomStringLength(32);
|
|
||||||
} else if (randomStringLength < 2) {
|
|
||||||
setRandomStringLength(2);
|
|
||||||
} else {
|
|
||||||
modifyValue(
|
|
||||||
[...Array(randomStringLength)]
|
|
||||||
.map(() => Math.floor(Math.random() * 16).toString(16))
|
|
||||||
.join(''),
|
|
||||||
keyPair.pos
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
className="relative flex flex-row justify-start items-center cursor-pointer select-none py-2 px-2 rounded-md text-gray-400 hover:bg-white/10 duration-200 hover:text-gray-200 w-full"
|
|
||||||
>
|
|
||||||
<FontAwesomeIcon
|
|
||||||
className="text-lg pl-1.5 pr-3"
|
|
||||||
icon={keyPair.value == '' ? faPlus : faShuffle}
|
|
||||||
/>
|
|
||||||
<div className="text-sm justify-between flex flex-row w-full">
|
|
||||||
<p>Generate Random Hex</p>
|
|
||||||
<p>digits</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="flex flex-row absolute bottom-[0.4rem] right-[3.3rem] w-16 bg-bunker-800 border border-chicago-700 rounded-md text-bunker-200 ">
|
|
||||||
<div
|
|
||||||
className="m-0.5 px-1 cursor-pointer rounded-md hover:bg-chicago-700"
|
|
||||||
onClick={() => {
|
|
||||||
if (randomStringLength > 1) {
|
|
||||||
setRandomStringLength(randomStringLength - 1);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
-
|
|
||||||
</div>
|
|
||||||
<input
|
|
||||||
onChange={(e) =>
|
|
||||||
setRandomStringLength(parseInt(e.target.value))
|
|
||||||
}
|
|
||||||
value={randomStringLength}
|
|
||||||
className="text-center z-20 peer text-sm bg-transparent w-full outline-none"
|
|
||||||
spellCheck="false"
|
|
||||||
/>
|
|
||||||
<div
|
|
||||||
className="m-0.5 px-1 pb-0.5 cursor-pointer rounded-md hover:bg-chicago-700"
|
|
||||||
onClick={() => {
|
|
||||||
if (randomStringLength < 32) {
|
|
||||||
setRandomStringLength(randomStringLength + 1);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
+
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Menu.Items>
|
|
||||||
</Transition>
|
|
||||||
</Menu>
|
|
||||||
<div className="w-2"></div>
|
<div className="w-2"></div>
|
||||||
<div className="opacity-50 hover:opacity-100 duration-200">
|
<div className="opacity-50 hover:opacity-100 duration-200">
|
||||||
<Button
|
<Button
|
||||||
@@ -227,6 +130,7 @@ export default function Dashboard() {
|
|||||||
const [sortMethod, setSortMethod] = useState('alphabetical');
|
const [sortMethod, setSortMethod] = useState('alphabetical');
|
||||||
const [checkDocsPopUpVisible, setCheckDocsPopUpVisible] = useState(false);
|
const [checkDocsPopUpVisible, setCheckDocsPopUpVisible] = useState(false);
|
||||||
const [hasUserEverPushed, setHasUserEverPushed] = useState(false);
|
const [hasUserEverPushed, setHasUserEverPushed] = useState(false);
|
||||||
|
const [sidebarOpen, toggleSidebar] = useState(false);
|
||||||
|
|
||||||
const { createNotification } = useNotificationContext();
|
const { createNotification } = useNotificationContext();
|
||||||
|
|
||||||
@@ -491,6 +395,7 @@ export default function Dashboard() {
|
|||||||
/>
|
/>
|
||||||
</Head>
|
</Head>
|
||||||
<div className="flex flex-row">
|
<div className="flex flex-row">
|
||||||
|
{!sidebarOpen && <SideBar />}
|
||||||
<div className="w-full max-h-96 pb-2">
|
<div className="w-full max-h-96 pb-2">
|
||||||
<NavHeader pageName="Secrets" isProjectRelated={true} />
|
<NavHeader pageName="Secrets" isProjectRelated={true} />
|
||||||
{checkDocsPopUpVisible && (
|
{checkDocsPopUpVisible && (
|
||||||
|
|||||||
Reference in New Issue
Block a user