mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-07 12:27:28 +00:00
Added memoization and did performance optimizations
This commit is contained in:
@@ -11,20 +11,21 @@ interface DashboardInputFieldProps {
|
|||||||
onChangeHandler: (value: string, position: number) => void;
|
onChangeHandler: (value: string, position: number) => void;
|
||||||
value: string;
|
value: string;
|
||||||
type: 'varName' | 'value';
|
type: 'varName' | 'value';
|
||||||
blurred: boolean;
|
blurred?: boolean;
|
||||||
duplicates: string[];
|
isDuplicate?: boolean;
|
||||||
override?: boolean;
|
override?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This component renders the input fields on the dashboard
|
* This component renders the input fields on the dashboard
|
||||||
* @param {object} obj - the order number of a keyPair
|
* @param {object} obj - the order number of a keyPair
|
||||||
* @param {number} obj.pos - the order number of a keyPair
|
* @param {number} obj.position - the order number of a keyPair
|
||||||
* @param {function} obj.onChangeHandler - what happens when the input is modified
|
* @param {function} obj.onChangeHandler - what happens when the input is modified
|
||||||
* @param {string} obj.type - whether the input field is for a Key Name or for a Key Value
|
* @param {string} obj.type - whether the input field is for a Key Name or for a Key Value
|
||||||
* @param {string} obj.value - value of the InputField
|
* @param {string} obj.value - value of the InputField
|
||||||
* @param {boolean} obj.blurred - whether the input field should be blurred (behind the gray dots) or not; this can be turned on/off in the dashboard
|
* @param {boolean} obj.blurred - whether the input field should be blurred (behind the gray dots) or not; this can be turned on/off in the dashboard
|
||||||
* @param {string[]} obj.duplicates - list of all the duplicated key names on the dashboard
|
* @param {boolean} obj.isDuplicate - if the key name is duplicated
|
||||||
|
* @param {boolean} obj.override - whether a secret/row should be displalyed as overriden
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -34,7 +35,7 @@ const DashboardInputField = ({
|
|||||||
type,
|
type,
|
||||||
value,
|
value,
|
||||||
blurred,
|
blurred,
|
||||||
duplicates,
|
isDuplicate,
|
||||||
override
|
override
|
||||||
}: DashboardInputFieldProps) => {
|
}: DashboardInputFieldProps) => {
|
||||||
const ref = useRef<HTMLDivElement | null>(null);
|
const ref = useRef<HTMLDivElement | null>(null);
|
||||||
@@ -44,11 +45,11 @@ const DashboardInputField = ({
|
|||||||
ref.current.scrollTop = e.currentTarget.scrollTop;
|
ref.current.scrollTop = e.currentTarget.scrollTop;
|
||||||
ref.current.scrollLeft = e.currentTarget.scrollLeft;
|
ref.current.scrollLeft = e.currentTarget.scrollLeft;
|
||||||
};
|
};
|
||||||
|
console.log('rerender', value)
|
||||||
|
|
||||||
if (type === 'varName') {
|
if (type === 'varName') {
|
||||||
const startsWithNumber = !isNaN(Number(value.charAt(0))) && value != '';
|
const startsWithNumber = !isNaN(Number(value.charAt(0))) && value != '';
|
||||||
const hasDuplicates = duplicates?.includes(value);
|
const error = startsWithNumber || isDuplicate;
|
||||||
const error = startsWithNumber || hasDuplicates;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex-col w-full">
|
<div className="flex-col w-full">
|
||||||
@@ -74,7 +75,7 @@ const DashboardInputField = ({
|
|||||||
Should not start with a number
|
Should not start with a number
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
{hasDuplicates && !startsWithNumber && (
|
{isDuplicate && !startsWithNumber && (
|
||||||
<p className="text-red text-xs mt-0.5 mx-1 mb-2 max-w-xs">
|
<p className="text-red text-xs mt-0.5 mx-1 mb-2 max-w-xs">
|
||||||
Secret names should be unique
|
Secret names should be unique
|
||||||
</p>
|
</p>
|
||||||
@@ -159,4 +160,8 @@ const DashboardInputField = ({
|
|||||||
return <>Something Wrong</>;
|
return <>Something Wrong</>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default React.memo(DashboardInputField);
|
function inputPropsAreEqual(prev: DashboardInputFieldProps, next: DashboardInputFieldProps) {
|
||||||
|
return prev.value === next.value && prev.type === next.type && prev.position === next.position && prev.blurred === next.blurred && prev.override === next.override && prev.duplicate === next.duplicate;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default React.memo(DashboardInputField, inputPropsAreEqual);
|
||||||
|
|||||||
@@ -0,0 +1,102 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { faEllipsis, faShuffle, faX } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
|
|
||||||
|
import Button from '../basic/buttons/Button';
|
||||||
|
import DashboardInputField from './DashboardInputField';
|
||||||
|
|
||||||
|
interface SecretDataProps {
|
||||||
|
type: 'personal' | 'shared';
|
||||||
|
pos: number;
|
||||||
|
key: string;
|
||||||
|
value: string;
|
||||||
|
id: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface KeyPairProps {
|
||||||
|
keyPair: SecretDataProps;
|
||||||
|
deleteRow: (id: string) => void;
|
||||||
|
modifyKey: (value: string, position: number) => void;
|
||||||
|
modifyValue: (value: string, position: number) => void;
|
||||||
|
isBlurred: boolean;
|
||||||
|
isDuplicate: boolean;
|
||||||
|
toggleSidebar: (id: string) => void;
|
||||||
|
sidebarSecretId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This component represent a single row for an environemnt variable on the dashboard
|
||||||
|
* @param {object} obj
|
||||||
|
* @param {String[]} obj.keyPair - data related to the environment variable (id, pos, key, value, public/private)
|
||||||
|
* @param {function} obj.deleteRow - a function to delete a certain keyPair
|
||||||
|
* @param {function} obj.modifyKey - modify the key of a certain environment variable
|
||||||
|
* @param {function} obj.modifyValue - modify the value of a certain environment variable
|
||||||
|
* @param {boolean} obj.isBlurred - if the blurring setting is turned on
|
||||||
|
* @param {boolean} obj.isDuplicate - list of all the duplicates secret names on the dashboard
|
||||||
|
* @param {function} obj.toggleSidebar - open/close/switch sidebar
|
||||||
|
* @param {string} obj.sidebarSecretId - the id of a secret for the side bar is displayed
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
const KeyPair = ({
|
||||||
|
keyPair,
|
||||||
|
deleteRow,
|
||||||
|
modifyKey,
|
||||||
|
modifyValue,
|
||||||
|
isBlurred,
|
||||||
|
isDuplicate,
|
||||||
|
toggleSidebar,
|
||||||
|
sidebarSecretId
|
||||||
|
}: KeyPairProps) => {
|
||||||
|
return (
|
||||||
|
<div className={`mx-1 flex flex-col items-center ml-1 ${keyPair.id == sidebarSecretId && "bg-mineshaft-500 duration-200"} rounded-md`}>
|
||||||
|
<div className="relative flex flex-row justify-between w-full max-w-5xl mr-auto max-h-14 my-1 items-start px-1">
|
||||||
|
{keyPair.type == "personal" && <div className="group font-normal group absolute top-[1rem] left-[0.2rem] z-40 inline-block text-gray-300 underline hover:text-primary duration-200">
|
||||||
|
<div className='w-1 h-1 rounded-full bg-primary z-40'></div>
|
||||||
|
<span className="absolute z-50 hidden group-hover:flex group-hover:animate-popdown duration-200 w-[10.5rem] -left-[0.4rem] -top-[1.7rem] translate-y-full px-2 py-2 bg-mineshaft-500 rounded-b-md rounded-r-md text-center text-gray-100 text-sm after:content-[''] after:absolute after:left-0 after:bottom-[100%] after:-translate-x-0 after:border-8 after:border-x-transparent after:border-t-transparent after:border-b-mineshaft-500">
|
||||||
|
This secret is overriden
|
||||||
|
</span>
|
||||||
|
</div>}
|
||||||
|
<div className="min-w-xl w-96">
|
||||||
|
<div className="flex pr-1 items-center rounded-lg mt-4 md:mt-0 max-h-16">
|
||||||
|
<DashboardInputField
|
||||||
|
onChangeHandler={modifyKey}
|
||||||
|
type="varName"
|
||||||
|
position={keyPair.pos}
|
||||||
|
value={keyPair.key}
|
||||||
|
isDuplicate={isDuplicate}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="w-full min-w-5xl">
|
||||||
|
<div className="flex min-w-7xl items-center pl-1 pr-1.5 rounded-lg mt-4 md:mt-0 max-h-10 ">
|
||||||
|
<DashboardInputField
|
||||||
|
onChangeHandler={modifyValue}
|
||||||
|
type="value"
|
||||||
|
position={keyPair.pos}
|
||||||
|
value={keyPair.value}
|
||||||
|
blurred={isBlurred}
|
||||||
|
override={keyPair.type == "personal"}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div onClick={() => toggleSidebar(keyPair.id)} className="cursor-pointer w-9 h-9 bg-mineshaft-700 hover:bg-chicago-700 rounded-md flex flex-row justify-center items-center duration-200">
|
||||||
|
<FontAwesomeIcon
|
||||||
|
className="text-gray-300 px-2.5 text-lg mt-0.5"
|
||||||
|
icon={faEllipsis}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="w-2"></div>
|
||||||
|
<div className="bg-[#9B3535] hover:bg-red rounded-md duration-200">
|
||||||
|
<Button
|
||||||
|
onButtonPressed={() => deleteRow(keyPair.id)}
|
||||||
|
color="none"
|
||||||
|
size="icon-sm"
|
||||||
|
icon={faX}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default React.memo(KeyPair);
|
||||||
@@ -8,13 +8,11 @@ import {
|
|||||||
faCheck,
|
faCheck,
|
||||||
faCopy,
|
faCopy,
|
||||||
faDownload,
|
faDownload,
|
||||||
faEllipsis,
|
|
||||||
faEye,
|
faEye,
|
||||||
faEyeSlash,
|
faEyeSlash,
|
||||||
faFolderOpen,
|
faFolderOpen,
|
||||||
faMagnifyingGlass,
|
faMagnifyingGlass,
|
||||||
faPlus,
|
faPlus,
|
||||||
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';
|
||||||
|
|
||||||
@@ -22,8 +20,8 @@ import Button from '~/components/basic/buttons/Button';
|
|||||||
import ListBox from '~/components/basic/Listbox';
|
import ListBox from '~/components/basic/Listbox';
|
||||||
import BottonRightPopup from '~/components/basic/popups/BottomRightPopup';
|
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 DropZone from '~/components/dashboard/DropZone';
|
import DropZone from '~/components/dashboard/DropZone';
|
||||||
|
import KeyPair from '~/components/dashboard/KeyPair';
|
||||||
import SideBar from '~/components/dashboard/SideBar';
|
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';
|
||||||
@@ -45,95 +43,6 @@ interface SecretDataProps {
|
|||||||
id: string;
|
id: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface KeyPairProps {
|
|
||||||
keyPair: SecretDataProps;
|
|
||||||
deleteRow: (id: string) => void;
|
|
||||||
modifyKey: (value: string, position: number) => void;
|
|
||||||
modifyValue: (value: string, position: number) => void;
|
|
||||||
isBlurred: boolean;
|
|
||||||
duplicates: any[];
|
|
||||||
toggleSidebar: (id: string) => void;
|
|
||||||
sidebarSecretId: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This component represent a single row for an environemnt variable on the dashboard
|
|
||||||
* @param {object} obj
|
|
||||||
* @param {String[]} obj.keyPair - data related to the environment variable (id, pos, key, value, public/private)
|
|
||||||
* @param {function} obj.deleteRow - a function to delete a certain keyPair
|
|
||||||
* @param {function} obj.modifyKey - modify the key of a certain environment variable
|
|
||||||
* @param {function} obj.modifyValue - modify the value of a certain environment variable
|
|
||||||
* @param {boolean} obj.isBlurred - if the blurring setting is turned on
|
|
||||||
* @param {string[]} obj.duplicates - list of all the duplicates secret names on the dashboard
|
|
||||||
* @param {string[]} obj.toggleSidebar - open/close/switch sidebar
|
|
||||||
* @param {string[]} obj.sidebarSecretId - the id of a secret for the side bar is displayed
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
const KeyPair = ({
|
|
||||||
keyPair,
|
|
||||||
deleteRow,
|
|
||||||
modifyKey,
|
|
||||||
modifyValue,
|
|
||||||
isBlurred,
|
|
||||||
duplicates,
|
|
||||||
toggleSidebar,
|
|
||||||
sidebarSecretId
|
|
||||||
}: KeyPairProps) => {
|
|
||||||
return (
|
|
||||||
<div className={`mx-1 flex flex-col items-center ml-1 ${keyPair.id == sidebarSecretId && "bg-mineshaft-500 duration-200"} rounded-md`}>
|
|
||||||
<div className="relative flex flex-row justify-between w-full max-w-5xl mr-auto max-h-14 my-1 items-start px-1">
|
|
||||||
{keyPair.type == "personal" && <div className="group font-normal group absolute top-[1rem] left-[0.2rem] z-40 inline-block text-gray-300 underline hover:text-primary duration-200">
|
|
||||||
<div className='w-1 h-1 rounded-full bg-primary z-40'></div>
|
|
||||||
<span className="absolute z-50 hidden group-hover:flex group-hover:animate-popdown duration-200 w-[10.5rem] -left-[0.4rem] -top-[1.7rem] translate-y-full px-2 py-2 bg-mineshaft-500 rounded-b-md rounded-r-md text-center text-gray-100 text-sm after:content-[''] after:absolute after:left-0 after:bottom-[100%] after:-translate-x-0 after:border-8 after:border-x-transparent after:border-t-transparent after:border-b-mineshaft-500">
|
|
||||||
This secret is overriden
|
|
||||||
</span>
|
|
||||||
</div>}
|
|
||||||
<div className="min-w-xl w-96">
|
|
||||||
<div className="flex pr-1 items-center rounded-lg mt-4 md:mt-0 max-h-16">
|
|
||||||
<DashboardInputField
|
|
||||||
onChangeHandler={modifyKey}
|
|
||||||
type="varName"
|
|
||||||
position={keyPair.pos}
|
|
||||||
value={keyPair.key}
|
|
||||||
duplicates={duplicates}
|
|
||||||
blurred={false}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="w-full min-w-5xl">
|
|
||||||
<div className="flex min-w-7xl items-center pl-1 pr-1.5 rounded-lg mt-4 md:mt-0 max-h-10 ">
|
|
||||||
<DashboardInputField
|
|
||||||
onChangeHandler={modifyValue}
|
|
||||||
type="value"
|
|
||||||
position={keyPair.pos}
|
|
||||||
value={keyPair.value}
|
|
||||||
blurred={isBlurred}
|
|
||||||
override={keyPair.type == "personal"}
|
|
||||||
duplicates={[]}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div onClick={() => toggleSidebar(keyPair.id)} className="cursor-pointer w-9 h-9 bg-mineshaft-700 hover:bg-chicago-700 rounded-md flex flex-row justify-center items-center duration-200">
|
|
||||||
<FontAwesomeIcon
|
|
||||||
className="text-gray-300 px-2.5 text-lg mt-0.5"
|
|
||||||
icon={faEllipsis}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="w-2"></div>
|
|
||||||
<div className="bg-[#9B3535] hover:bg-red rounded-md duration-200">
|
|
||||||
<Button
|
|
||||||
onButtonPressed={() => deleteRow(keyPair.id)}
|
|
||||||
color="none"
|
|
||||||
size="icon-sm"
|
|
||||||
icon={faX}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* this function finds the teh duplicates in an array
|
* this function finds the teh duplicates in an array
|
||||||
* @param arr - array of anything (e.g., with secret keys and types (personal/shared))
|
* @param arr - array of anything (e.g., with secret keys and types (personal/shared))
|
||||||
@@ -653,7 +562,7 @@ export default function Dashboard() {
|
|||||||
modifyValue={listenChangeValue}
|
modifyValue={listenChangeValue}
|
||||||
modifyKey={listenChangeKey}
|
modifyKey={listenChangeKey}
|
||||||
isBlurred={blurred}
|
isBlurred={blurred}
|
||||||
duplicates={findDuplicates(data?.map((item) => [item.key, item.type]))}
|
isDuplicate={findDuplicates(data?.map((item) => [item.key, item.type]))?.includes(keyPair.value)}
|
||||||
toggleSidebar={toggleSidebar}
|
toggleSidebar={toggleSidebar}
|
||||||
sidebarSecretId={sidebarSecretId}
|
sidebarSecretId={sidebarSecretId}
|
||||||
/>
|
/>
|
||||||
|
|||||||
Reference in New Issue
Block a user