mirror of
https://github.com/Infisical/infisical.git
synced 2025-03-25 14:05:03 +00:00
Added overrides for secrets
This commit is contained in:
@ -1,6 +1,25 @@
|
||||
import React from "react";
|
||||
import { Switch } from "@headlessui/react";
|
||||
|
||||
|
||||
interface OverrideProps {
|
||||
id: string;
|
||||
keyName: string;
|
||||
value: string;
|
||||
pos: number;
|
||||
}
|
||||
|
||||
interface ToggleProps {
|
||||
enabled: boolean;
|
||||
setEnabled: (value: boolean) => void;
|
||||
addOverride: (value: OverrideProps) => void;
|
||||
keyName: string;
|
||||
value: string;
|
||||
pos: number;
|
||||
id: string;
|
||||
deleteOverride: (id: string) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a typical 'iPhone' toggle (e.g., user for overriding secrets with personal values)
|
||||
* @param obj
|
||||
@ -8,11 +27,19 @@ import { Switch } from "@headlessui/react";
|
||||
* @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 {
|
||||
export default function Toggle ({ enabled, setEnabled, addOverride, keyName, value, pos, id, deleteOverride }: ToggleProps): JSX.Element {
|
||||
console.log(755, pos, enabled)
|
||||
return (
|
||||
<Switch
|
||||
checked={enabled}
|
||||
onChange={setEnabled}
|
||||
onChange={() => {
|
||||
if (enabled == false) {
|
||||
addOverride({ id, keyName, value, pos });
|
||||
} else {
|
||||
deleteOverride(id);
|
||||
}
|
||||
setEnabled(!enabled);
|
||||
}}
|
||||
className={`${
|
||||
enabled ? 'bg-primary' : 'bg-bunker-400'
|
||||
} relative inline-flex h-5 w-9 items-center rounded-full`}
|
||||
|
@ -13,6 +13,7 @@ interface DashboardInputFieldProps {
|
||||
type: 'varName' | 'value';
|
||||
blurred: boolean;
|
||||
duplicates: string[];
|
||||
override?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -33,7 +34,8 @@ const DashboardInputField = ({
|
||||
type,
|
||||
value,
|
||||
blurred,
|
||||
duplicates
|
||||
duplicates,
|
||||
override
|
||||
}: DashboardInputFieldProps) => {
|
||||
const ref = useRef<HTMLDivElement | null>(null);
|
||||
const syncScroll = (e: SyntheticEvent<HTMLDivElement>) => {
|
||||
@ -85,6 +87,7 @@ const DashboardInputField = ({
|
||||
<div
|
||||
className={`group relative whitespace-pre flex flex-col justify-center w-full max-w-2xl border border-mineshaft-500 rounded-md`}
|
||||
>
|
||||
{override == true && <div className='bg-yellow-300 absolute top-[0.1rem] right-[0.1rem] z-10 w-min text-xxs px-1 text-black opacity-80 rounded-sm'>Override enabled</div>}
|
||||
<input
|
||||
value={value}
|
||||
onChange={(e) => onChangeHandler(e.target.value, position)}
|
||||
@ -99,10 +102,13 @@ const DashboardInputField = ({
|
||||
<div
|
||||
ref={ref}
|
||||
className={`${
|
||||
blurred
|
||||
blurred && !override
|
||||
? 'text-bunker-800 group-hover:text-gray-400 peer-focus:text-gray-400 peer-active:text-gray-400'
|
||||
: ''
|
||||
} absolute flex flex-row whitespace-pre font-mono z-0 ph-no-capture max-w-2xl overflow-x-scroll bg-bunker-800 h-9 rounded-md text-gray-400 text-md px-2 py-1.5 w-full min-w-16 outline-none focus:ring-2 focus:ring-primary/50 duration-100 no-scrollbar no-scrollbar::-webkit-scrollbar`}
|
||||
} ${
|
||||
override ? 'text-yellow-300' : 'text-gray-400'
|
||||
}
|
||||
absolute flex flex-row whitespace-pre font-mono z-0 ph-no-capture max-w-2xl overflow-x-scroll bg-bunker-800 h-9 rounded-md text-md px-2 py-1.5 w-full min-w-16 outline-none focus:ring-2 focus:ring-primary/50 duration-100 no-scrollbar no-scrollbar::-webkit-scrollbar`}
|
||||
>
|
||||
{value.split(REGEX).map((word, id) => {
|
||||
if (word.match(REGEX) !== null) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { useState } from 'react';
|
||||
import { faX } from '@fortawesome/free-solid-svg-icons';
|
||||
import { faBackward, faDotCircle, faRotateLeft, faX } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
|
||||
import Button from '../basic/buttons/Button';
|
||||
@ -13,7 +13,14 @@ interface SecretProps {
|
||||
key: string;
|
||||
value: string;
|
||||
pos: number;
|
||||
visibility: string;
|
||||
id: string;
|
||||
}
|
||||
|
||||
interface OverrideProps {
|
||||
id: string;
|
||||
keyName: string;
|
||||
value: string;
|
||||
pos: number;
|
||||
}
|
||||
|
||||
interface SideBarProps {
|
||||
@ -22,6 +29,8 @@ interface SideBarProps {
|
||||
modifyKey: (value: string) => void;
|
||||
modifyValue: (value: string) => void;
|
||||
modifyVisibility: (value: string) => void;
|
||||
addOverride: (value: OverrideProps) => void;
|
||||
deleteOverride: (id: string) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -33,7 +42,7 @@ interface SideBarProps {
|
||||
* @param {function} obj.modifyVisibility - function that modifies the secret visibility
|
||||
* @returns the sidebar with 'secret's settings'
|
||||
*/
|
||||
const SideBar = ({ toggleSidebar, data, modifyKey, modifyValue, modifyVisibility }: SideBarProps) => {
|
||||
const SideBar = ({ toggleSidebar, data, modifyKey, modifyValue, modifyVisibility, addOverride, deleteOverride }: SideBarProps) => {
|
||||
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'>
|
||||
@ -44,7 +53,7 @@ const SideBar = ({ toggleSidebar, data, modifyKey, modifyValue, modifyVisibility
|
||||
<FontAwesomeIcon icon={faX} className='w-4 h-4 text-bunker-300 cursor-pointer'/>
|
||||
</div>
|
||||
</div>
|
||||
<div className='mt-4 px-4'>
|
||||
<div className='mt-4 px-4 pointer-events-none'>
|
||||
<p className='text-sm text-bunker-300'>Key</p>
|
||||
<DashboardInputField
|
||||
onChangeHandler={modifyKey}
|
||||
@ -61,25 +70,34 @@ const SideBar = ({ toggleSidebar, data, modifyKey, modifyValue, modifyVisibility
|
||||
onChangeHandler={modifyValue}
|
||||
type="value"
|
||||
position={data[0].pos}
|
||||
value={data[0].value}
|
||||
value={data[0].value + "xxx" + data[0].pos}
|
||||
duplicates={[]}
|
||||
blurred={true}
|
||||
blurred={true}
|
||||
/>
|
||||
<div className='absolute bg-bunker-800 right-[1rem] top-[1.65rem] z-50'>
|
||||
<div className='absolute bg-bunker-800 right-[1.07rem] top-[1.6rem] 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} />
|
||||
<Toggle
|
||||
enabled={overrideEnabled}
|
||||
setEnabled={setOverrideEnabled}
|
||||
addOverride={addOverride}
|
||||
keyName={data[0].key}
|
||||
value={data[0].value}
|
||||
pos={data[0].pos}
|
||||
id={data[0].id}
|
||||
deleteOverride={deleteOverride}
|
||||
/>
|
||||
</div>
|
||||
<div className={`relative ${!overrideEnabled && "opacity-40 pointer-events-none"} duration-200`}>
|
||||
<DashboardInputField
|
||||
onChangeHandler={modifyValue}
|
||||
type="value"
|
||||
position={data[0].pos}
|
||||
value={"ValueValueValue"}
|
||||
value={"ValueValueValue" + data[0].pos}
|
||||
duplicates={[]}
|
||||
blurred={true}
|
||||
/>
|
||||
@ -97,9 +115,57 @@ const SideBar = ({ toggleSidebar, data, modifyKey, modifyValue, modifyVisibility
|
||||
isFull={true}
|
||||
/>
|
||||
</div>
|
||||
<div className={`mt-4 px-4`}>
|
||||
<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'>
|
||||
<div className='w-full h-52 px-4 mt-4 text-sm text-bunker-300 overflow-x-none'>
|
||||
<p className=''>Version History</p>
|
||||
<div className='p-1 rounded-md bg-bunker-800 border border-mineshaft-500 overflow-x-none'>
|
||||
<div className='h-48 overflow-y-scroll overflow-x-none'>
|
||||
<div className='flex flex-row'>
|
||||
<div className='pr-1 flex flex-col items-center'>
|
||||
<div className='p-1'><FontAwesomeIcon icon={faDotCircle} /></div>
|
||||
<div className='w-0 h-full border-l mt-1'></div>
|
||||
</div>
|
||||
<div className='flex flex-col w-full max-w-[calc(100%-2.3rem)]'>
|
||||
<div className='pr-2 pt-1'>Current</div>
|
||||
<div className=''><p className='break-words'><span className='py-0.5 px-1 rounded-md bg-primary-300/20 mr-1.5'>Key:</span>{data[0].key}</p></div>
|
||||
<div className=''><p className='break-words'><span className='py-0.5 px-1 rounded-md bg-primary-300/20 mr-1.5'>Value:</span>{data[0].value}</p></div>
|
||||
<div className='pb-1'><p className='break-words'><span className='py-0.5 px-1 rounded-md bg-primary-300/20 mr-1.5'>Visibility:</span>{'shared'}</p></div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex flex-row'>
|
||||
<div className='pr-1 flex flex-col items-center'>
|
||||
<div className='cursor-pointer p-1 hover:bg-bunker-500 rounded-md'><FontAwesomeIcon icon={faRotateLeft} /></div>
|
||||
<div className='w-0 h-full border-l'></div>
|
||||
</div>
|
||||
<div className='flex flex-col max-w-[calc(100%-2.3rem)]'>
|
||||
<div className='pr-2 pt-1'>12/22/2022 12:36 EST</div>
|
||||
<div className='w-full pr-2'><span className='py-0.5 px-1 rounded-md bg-primary-200/10 mr-1'>Key:</span> KeyKeyKey</div>
|
||||
<div className='w-full pr-2'><span className='py-0.5 px-1 rounded-md bg-primary-200/10 mr-1'>Value:</span> ValueValueValue</div>
|
||||
<div className='pb-1'><p className='break-words'><span className='py-0.5 px-1 rounded-md bg-primary-300/20 mr-1.5'>Visibility:</span>{'shared'}</p></div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex flex-row'>
|
||||
<div className='pr-1 flex flex-col items-center'>
|
||||
<div className='cursor-pointer p-1 hover:bg-bunker-500 rounded-md'><FontAwesomeIcon icon={faRotateLeft} /></div>
|
||||
<div className='w-0 h-full border-l'></div>
|
||||
</div>
|
||||
<div className='flex flex-col max-w-[calc(100%-2.3rem)]'>
|
||||
<div className='pr-2 pt-1'>12/21/2022 09:11 EST</div>
|
||||
<div className='w-full pr-2'><span className='py-0.5 px-1 rounded-md bg-primary-200/10 mr-1'>Key:</span> KeyKey</div>
|
||||
<div className='w-full pr-2'><span className='py-0.5 px-1 rounded-md bg-primary-200/10 mr-1'>Value:</span> ValueValue</div>
|
||||
<div className='pb-1'><p className='break-words'><span className='py-0.5 px-1 rounded-md bg-primary-300/20 mr-1.5'>Visibility:</span>{'shared'}</p></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className={`relative mt-4 px-4 pt-4`}>
|
||||
<div className='flex flex-row justify-between'>
|
||||
<p className='text-sm text-bunker-300'>Comments & notes</p>
|
||||
<div className="bg-yellow rounded-md h-min">
|
||||
<p className="relative text-black text-xs px-1.5 h-min">Coming soon!</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className='h-32 opacity-50 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>
|
||||
|
@ -6,7 +6,6 @@ import {
|
||||
faArrowDownAZ,
|
||||
faArrowDownZA,
|
||||
faCheck,
|
||||
faCircleInfo,
|
||||
faCopy,
|
||||
faDownload,
|
||||
faEllipsis,
|
||||
@ -83,6 +82,7 @@ const KeyPair = ({
|
||||
position={keyPair.pos}
|
||||
value={keyPair.value}
|
||||
blurred={isBlurred}
|
||||
override={keyPair.value == "user1234" && true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -176,7 +176,7 @@ export default function Dashboard() {
|
||||
prevSort == 'alphabetical' ? '-alphabetical' : 'alphabetical'
|
||||
);
|
||||
|
||||
sortValuesHandler(dataToReorder);
|
||||
sortValuesHandler(dataToReorder, "");
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
@ -238,11 +238,43 @@ export default function Dashboard() {
|
||||
]);
|
||||
};
|
||||
|
||||
/**
|
||||
* This function add an ovverrided version of a certain secret to the current user
|
||||
* @param {object} obj
|
||||
* @param {string} obj.id - if of this secret that is about to be overriden
|
||||
* @param {string} obj.keyName - key name of this secret
|
||||
* @param {string} obj.value - value of this secret
|
||||
* @param {string} obj.pos - position of this secret on the dashboard
|
||||
*/
|
||||
const addOverride = ({ id, keyName, value, pos }) => {
|
||||
setIsNew(false);
|
||||
const tempdata = [
|
||||
...data,
|
||||
{
|
||||
id: id,
|
||||
pos: pos,
|
||||
key: keyName,
|
||||
value: value,
|
||||
type: 'personal'
|
||||
}
|
||||
];
|
||||
sortValuesHandler(tempdata, sortMethod == "alhpabetical" ? "-alphabetical" : "alphabetical");
|
||||
};
|
||||
|
||||
const deleteRow = (id) => {
|
||||
setButtonReady(true);
|
||||
setData(data.filter((row) => row.id !== id));
|
||||
};
|
||||
|
||||
/**
|
||||
* This function deleted the override of a certain secrer
|
||||
* @param {string} id - id of a secret to be deleted
|
||||
*/
|
||||
const deleteOverride = (id) => {
|
||||
setButtonReady(true);
|
||||
setData(data.filter((row) => !(row.id == id && row.type == 'personal')));
|
||||
};
|
||||
|
||||
const modifyValue = (value, pos) => {
|
||||
setData((oldData) => {
|
||||
oldData[pos].value = value;
|
||||
@ -335,10 +367,11 @@ export default function Dashboard() {
|
||||
setBlurred(!blurred);
|
||||
};
|
||||
|
||||
const sortValuesHandler = (dataToSort) => {
|
||||
const sortValuesHandler = (dataToSort, specificSortMethod) => {
|
||||
const howToSort = specificSortMethod != "" ? specificSortMethod : sortMethod
|
||||
const sortedData = (dataToSort != 1 ? dataToSort : data)
|
||||
.sort((a, b) =>
|
||||
sortMethod == 'alphabetical'
|
||||
howToSort == 'alphabetical'
|
||||
? a.key.localeCompare(b.key)
|
||||
: b.key.localeCompare(a.key)
|
||||
)
|
||||
@ -397,12 +430,14 @@ export default function Dashboard() {
|
||||
/>
|
||||
</Head>
|
||||
<div className="flex flex-row">
|
||||
{sidebarSecretNumber != -1 && <SideBar
|
||||
{sidebarSecretNumber != -1 && <SideBar
|
||||
toggleSidebar={toggleSidebar}
|
||||
data={data.filter(row => row.pos == sidebarSecretNumber)}
|
||||
modifyKey={listenChangeKey}
|
||||
modifyValue={listenChangeValue}
|
||||
modifyVisibility={listenChangeVisibility}
|
||||
addOverride={addOverride}
|
||||
deleteOverride={deleteOverride}
|
||||
/>}
|
||||
<div className="w-full max-h-96 pb-2">
|
||||
<NavHeader pageName="Secrets" isProjectRelated={true} />
|
||||
@ -550,101 +585,33 @@ export default function Dashboard() {
|
||||
<div
|
||||
className={`bg-white/5 mt-1 mb-1 rounded-md pb-2 max-w-5xl overflow-visible`}
|
||||
>
|
||||
<div className="rounded-t-md sticky top-0 z-20 bg-bunker flex flex-row pl-4 pr-6 pt-4 pb-2 items-center justify-between text-gray-300 font-bold">
|
||||
{/* <FontAwesomeIcon icon={faAngleDown} /> */}
|
||||
<div className="flex flex-row items-center">
|
||||
<p className="pl-2 text-lg">Personal</p>
|
||||
<div className="group font-normal group relative inline-block text-gray-300 underline hover:text-primary duration-200">
|
||||
<FontAwesomeIcon
|
||||
className="ml-3 mt-1 text-lg"
|
||||
icon={faCircleInfo}
|
||||
/>
|
||||
<span className="absolute hidden group-hover:flex group-hover:animate-popdown duration-300 w-44 -left-16 -top-7 translate-y-full px-2 py-2 bg-gray-700 rounded-md text-center text-gray-100 text-sm after:content-[''] after:absolute after:left-1/2 after:bottom-[100%] after:-translate-x-1/2 after:border-8 after:border-x-transparent after:border-t-transparent after:border-b-gray-700">
|
||||
Personal keys are only visible to you
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="data1" className="px-1">
|
||||
{data
|
||||
.filter(
|
||||
(keyPair) =>
|
||||
keyPair.key
|
||||
.toLowerCase()
|
||||
.includes(searchKeys.toLowerCase()) &&
|
||||
keyPair.type == 'personal'
|
||||
)
|
||||
?.map((keyPair) => (
|
||||
<KeyPair
|
||||
key={keyPair.id}
|
||||
keyPair={keyPair}
|
||||
deleteRow={deleteCertainRow}
|
||||
modifyValue={listenChangeValue}
|
||||
modifyKey={listenChangeKey}
|
||||
modifyVisibility={listenChangeVisibility}
|
||||
isBlurred={blurred}
|
||||
duplicates={data
|
||||
?.map((item) => item.key)
|
||||
.filter(
|
||||
(item, index) =>
|
||||
index !==
|
||||
data?.map((item) => item.key).indexOf(item)
|
||||
)}
|
||||
toggleSidebar={toggleSidebar}
|
||||
sidebarSecretNumber={sidebarSecretNumber}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className={`bg-white/5 mt-1 mb-2 rounded-md p-1 pb-2 max-w-5xl ${
|
||||
data?.length > 8 ? 'h-3/4' : 'h-min'
|
||||
}`}
|
||||
>
|
||||
<div className="sticky top-0 z-40 bg-bunker flex flex-row pl-4 pr-5 pt-4 pb-2 items-center justify-between text-gray-300 font-bold">
|
||||
{/* <FontAwesomeIcon icon={faAngleDown} /> */}
|
||||
<div className="flex flex-row items-center">
|
||||
<p className="pl-2 text-lg">Shared</p>
|
||||
<div className="group font-normal group relative inline-block text-gray-300 underline hover:text-primary duration-200">
|
||||
<FontAwesomeIcon
|
||||
className="ml-3 text-lg mt-1"
|
||||
icon={faCircleInfo}
|
||||
/>
|
||||
<span className="absolute hidden group-hover:flex group-hover:animate-popdown duration-300 w-44 -left-16 -top-7 translate-y-full px-2 py-2 bg-gray-700 rounded-md text-center text-gray-100 text-sm after:content-[''] after:absolute after:left-1/2 after:bottom-[100%] after:-translate-x-1/2 after:border-8 after:border-x-transparent after:border-t-transparent after:border-b-gray-700">
|
||||
Shared keys are visible to your whole team
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="data2" className="data2">
|
||||
{data
|
||||
.filter(
|
||||
(keyPair) =>
|
||||
keyPair.key
|
||||
.toLowerCase()
|
||||
.includes(searchKeys.toLowerCase()) &&
|
||||
keyPair.type == 'shared'
|
||||
)
|
||||
?.map((keyPair) => (
|
||||
<KeyPair
|
||||
key={keyPair.id}
|
||||
keyPair={keyPair}
|
||||
deleteRow={deleteCertainRow}
|
||||
modifyValue={listenChangeValue}
|
||||
modifyKey={listenChangeKey}
|
||||
modifyVisibility={listenChangeVisibility}
|
||||
isBlurred={blurred}
|
||||
duplicates={data
|
||||
?.map((item) => item.key)
|
||||
.filter(
|
||||
(item, index) =>
|
||||
index !==
|
||||
data?.map((item) => item.key).indexOf(item)
|
||||
)}
|
||||
toggleSidebar={toggleSidebar}
|
||||
sidebarSecretNumber={sidebarSecretNumber}
|
||||
/>
|
||||
))}
|
||||
<div id="data1" className="px-1 pt-2">
|
||||
{data?.filter(row => !(data
|
||||
?.map((item) => item.key)
|
||||
.filter(
|
||||
(item, index) =>
|
||||
index !==
|
||||
data?.map((item) => item.key).indexOf(item)
|
||||
).includes(row.key) && row.type == 'shared')).map((keyPair) => (
|
||||
<KeyPair
|
||||
key={keyPair.id}
|
||||
keyPair={keyPair}
|
||||
deleteRow={deleteCertainRow}
|
||||
modifyValue={listenChangeValue}
|
||||
modifyKey={listenChangeKey}
|
||||
modifyVisibility={listenChangeVisibility}
|
||||
isBlurred={blurred}
|
||||
duplicates={data
|
||||
?.map((item) => item.key)
|
||||
.filter(
|
||||
(item, index) =>
|
||||
index !==
|
||||
data?.map((item) => item.key).indexOf(item)
|
||||
)}
|
||||
toggleSidebar={toggleSidebar}
|
||||
sidebarSecretNumber={sidebarSecretNumber}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full max-w-5xl">
|
||||
|
Reference in New Issue
Block a user