mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-07 05:27:48 +00:00
improve access account styling, add folder path badge to flat view,
increase log gap
This commit is contained in:
@@ -1,10 +1,11 @@
|
|||||||
import { useMemo, useState } from "react";
|
import { useMemo, useState } from "react";
|
||||||
|
import { faCopy } from "@fortawesome/free-regular-svg-icons";
|
||||||
import { faUpRightFromSquare } from "@fortawesome/free-solid-svg-icons";
|
import { faUpRightFromSquare } from "@fortawesome/free-solid-svg-icons";
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
import ms from "ms";
|
import ms from "ms";
|
||||||
|
|
||||||
import { createNotification } from "@app/components/notifications";
|
import { createNotification } from "@app/components/notifications";
|
||||||
import { Button, FormLabel, Input, Modal, ModalClose, ModalContent } from "@app/components/v2";
|
import { FormLabel, IconButton, Input, Modal, ModalContent } from "@app/components/v2";
|
||||||
import { PamResourceType, TPamAccount } from "@app/hooks/api/pam";
|
import { PamResourceType, TPamAccount } from "@app/hooks/api/pam";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@@ -28,21 +29,10 @@ export const PamAccessAccountModal = ({ isOpen, onOpenChange, account }: Props)
|
|||||||
|
|
||||||
if (!account) return null;
|
if (!account) return null;
|
||||||
|
|
||||||
const copyCommand = () => {
|
|
||||||
navigator.clipboard.writeText(command);
|
|
||||||
|
|
||||||
createNotification({
|
|
||||||
text: "Command copied to clipboard",
|
|
||||||
type: "info"
|
|
||||||
});
|
|
||||||
|
|
||||||
onOpenChange(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal isOpen={isOpen} onOpenChange={onOpenChange}>
|
<Modal isOpen={isOpen} onOpenChange={onOpenChange}>
|
||||||
<ModalContent
|
<ModalContent
|
||||||
className="max-w-2xl"
|
className="max-w-2xl pb-2"
|
||||||
title="Access Account"
|
title="Access Account"
|
||||||
subTitle={`Access ${account.name} using a CLI command.`}
|
subTitle={`Access ${account.name} using a CLI command.`}
|
||||||
>
|
>
|
||||||
@@ -57,7 +47,27 @@ export const PamAccessAccountModal = ({ isOpen, onOpenChange, account }: Props)
|
|||||||
isError={!isDurationValid}
|
isError={!isDurationValid}
|
||||||
/>
|
/>
|
||||||
<FormLabel label="CLI Command" className="mt-4" />
|
<FormLabel label="CLI Command" className="mt-4" />
|
||||||
<Input value={command} isDisabled />
|
<div className="flex gap-2">
|
||||||
|
<Input value={command} isDisabled className="opacity-50" />
|
||||||
|
<IconButton
|
||||||
|
ariaLabel="copy"
|
||||||
|
variant="outline_bg"
|
||||||
|
colorSchema="secondary"
|
||||||
|
onClick={() => {
|
||||||
|
navigator.clipboard.writeText(command);
|
||||||
|
|
||||||
|
createNotification({
|
||||||
|
text: "Command copied to clipboard",
|
||||||
|
type: "info"
|
||||||
|
});
|
||||||
|
|
||||||
|
onOpenChange(false);
|
||||||
|
}}
|
||||||
|
className="w-10"
|
||||||
|
>
|
||||||
|
<FontAwesomeIcon icon={faCopy} />
|
||||||
|
</IconButton>
|
||||||
|
</div>
|
||||||
<a
|
<a
|
||||||
href="https://infisical.com/docs/cli/overview"
|
href="https://infisical.com/docs/cli/overview"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
@@ -67,22 +77,6 @@ export const PamAccessAccountModal = ({ isOpen, onOpenChange, account }: Props)
|
|||||||
<span>Install the Infisical CLI</span>
|
<span>Install the Infisical CLI</span>
|
||||||
<FontAwesomeIcon icon={faUpRightFromSquare} className="size-3" />
|
<FontAwesomeIcon icon={faUpRightFromSquare} className="size-3" />
|
||||||
</a>
|
</a>
|
||||||
<div className="mt-6 flex items-center">
|
|
||||||
<Button
|
|
||||||
isDisabled={!isDurationValid}
|
|
||||||
className="mr-4"
|
|
||||||
size="sm"
|
|
||||||
colorSchema="secondary"
|
|
||||||
onClick={copyCommand}
|
|
||||||
>
|
|
||||||
Copy Command
|
|
||||||
</Button>
|
|
||||||
<ModalClose asChild>
|
|
||||||
<Button colorSchema="secondary" variant="plain">
|
|
||||||
Cancel
|
|
||||||
</Button>
|
|
||||||
</ModalClose>
|
|
||||||
</div>
|
|
||||||
</ModalContent>
|
</ModalContent>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import {
|
|||||||
faCopy,
|
faCopy,
|
||||||
faEdit,
|
faEdit,
|
||||||
faEllipsisV,
|
faEllipsisV,
|
||||||
|
faFolder,
|
||||||
faRightToBracket,
|
faRightToBracket,
|
||||||
faTrash
|
faTrash
|
||||||
} from "@fortawesome/free-solid-svg-icons";
|
} from "@fortawesome/free-solid-svg-icons";
|
||||||
@@ -37,9 +38,19 @@ type Props = {
|
|||||||
onUpdate: (resource: TPamAccount) => void;
|
onUpdate: (resource: TPamAccount) => void;
|
||||||
onDelete: (resource: TPamAccount) => void;
|
onDelete: (resource: TPamAccount) => void;
|
||||||
search: string;
|
search: string;
|
||||||
|
isFlatView: boolean;
|
||||||
|
accountPath?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const PamAccountRow = ({ account, search, onAccess, onUpdate, onDelete }: Props) => {
|
export const PamAccountRow = ({
|
||||||
|
account,
|
||||||
|
search,
|
||||||
|
onAccess,
|
||||||
|
onUpdate,
|
||||||
|
onDelete,
|
||||||
|
isFlatView,
|
||||||
|
accountPath
|
||||||
|
}: Props) => {
|
||||||
const { id, name } = account;
|
const { id, name } = account;
|
||||||
|
|
||||||
const { image, name: resourceTypeName } = PAM_RESOURCE_TYPE_MAP[account.resource.resourceType];
|
const { image, name: resourceTypeName } = PAM_RESOURCE_TYPE_MAP[account.resource.resourceType];
|
||||||
@@ -81,6 +92,14 @@ export const PamAccountRow = ({ account, search, onAccess, onUpdate, onDelete }:
|
|||||||
<HighlightText text={account.resource.name} highlight={search} />
|
<HighlightText text={account.resource.name} highlight={search} />
|
||||||
</span>
|
</span>
|
||||||
</Badge>
|
</Badge>
|
||||||
|
{isFlatView && accountPath && (
|
||||||
|
<Badge className="flex h-5 w-min items-center gap-1.5 whitespace-nowrap bg-bunker-300/20 text-bunker-300">
|
||||||
|
<FontAwesomeIcon icon={faFolder} />
|
||||||
|
<span>
|
||||||
|
<HighlightText text={accountPath} highlight={search} />
|
||||||
|
</span>
|
||||||
|
</Badge>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Td>
|
</Td>
|
||||||
|
|||||||
@@ -114,10 +114,11 @@ export const PamAccountsTable = ({ accounts, folders, projectId }: Props) => {
|
|||||||
setOrderBy
|
setOrderBy
|
||||||
} = usePagination<OrderBy>(OrderBy.Name, { initPerPage: 20, initSearch });
|
} = usePagination<OrderBy>(OrderBy.Name, { initPerPage: 20, initSearch });
|
||||||
|
|
||||||
const { foldersByParentId, pathMap } = useMemo(() => {
|
const { foldersByParentId, pathMap, folderPaths } = useMemo(() => {
|
||||||
const foldersById: Record<string, TPamFolder> = {};
|
const foldersById: Record<string, TPamFolder> = {};
|
||||||
const tempFoldersByParentId: Record<string, TPamFolder[]> = { null: [] };
|
const tempFoldersByParentId: Record<string, TPamFolder[]> = { null: [] };
|
||||||
const tempPathMap: Record<string, string> = { "/": "null" };
|
const tempPathMap: Record<string, string> = { "/": "null" };
|
||||||
|
const tempFolderPaths: Record<string, string> = {};
|
||||||
|
|
||||||
folders.forEach((folder) => {
|
folders.forEach((folder) => {
|
||||||
foldersById[folder.id] = folder;
|
foldersById[folder.id] = folder;
|
||||||
@@ -131,13 +132,18 @@ export const PamAccountsTable = ({ accounts, folders, projectId }: Props) => {
|
|||||||
(tempFoldersByParentId[parentId || "null"] || []).forEach((folder) => {
|
(tempFoldersByParentId[parentId || "null"] || []).forEach((folder) => {
|
||||||
const newPath = `${currentPath}${folder.name}/`;
|
const newPath = `${currentPath}${folder.name}/`;
|
||||||
tempPathMap[newPath] = folder.id;
|
tempPathMap[newPath] = folder.id;
|
||||||
|
tempFolderPaths[folder.id] = newPath;
|
||||||
buildPaths(folder.id, newPath);
|
buildPaths(folder.id, newPath);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
buildPaths(null, "/");
|
buildPaths(null, "/");
|
||||||
|
|
||||||
return { foldersByParentId: tempFoldersByParentId, pathMap: tempPathMap };
|
return {
|
||||||
|
foldersByParentId: tempFoldersByParentId,
|
||||||
|
pathMap: tempPathMap,
|
||||||
|
folderPaths: tempFolderPaths
|
||||||
|
};
|
||||||
}, [folders]);
|
}, [folders]);
|
||||||
|
|
||||||
const effectiveFolderIdForFiltering = useMemo(() => {
|
const effectiveFolderIdForFiltering = useMemo(() => {
|
||||||
@@ -181,11 +187,13 @@ export const PamAccountsTable = ({ accounts, folders, projectId }: Props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const searchValue = search.trim().toLowerCase();
|
const searchValue = search.trim().toLowerCase();
|
||||||
|
const path = (account.folderId && folderPaths[account.folderId]) || "";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
name.toLowerCase().includes(searchValue) ||
|
name.toLowerCase().includes(searchValue) ||
|
||||||
resourceName.toLowerCase().includes(searchValue) ||
|
resourceName.toLowerCase().includes(searchValue) ||
|
||||||
(description || "").toLowerCase().includes(searchValue)
|
(description || "").toLowerCase().includes(searchValue) ||
|
||||||
|
path.toLowerCase().includes(searchValue)
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
.sort((a, b) => {
|
.sort((a, b) => {
|
||||||
@@ -197,7 +205,7 @@ export const PamAccountsTable = ({ accounts, folders, projectId }: Props) => {
|
|||||||
return accOne.name.toLowerCase().localeCompare(accTwo.name.toLowerCase());
|
return accOne.name.toLowerCase().localeCompare(accTwo.name.toLowerCase());
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
[accountsToProcess, orderDirection, search, orderBy, filters]
|
[accountsToProcess, orderDirection, search, orderBy, filters, folderPaths]
|
||||||
);
|
);
|
||||||
|
|
||||||
useResetPageHelper({
|
useResetPageHelper({
|
||||||
@@ -434,6 +442,10 @@ export const PamAccountsTable = ({ accounts, folders, projectId }: Props) => {
|
|||||||
key={account.id}
|
key={account.id}
|
||||||
account={account}
|
account={account}
|
||||||
search={search}
|
search={search}
|
||||||
|
isFlatView={accountView === AccountView.Flat}
|
||||||
|
accountPath={
|
||||||
|
account.folderId ? folderPaths[account.folderId]?.slice(0, -1) : undefined
|
||||||
|
}
|
||||||
onAccess={(e) => {
|
onAccess={(e) => {
|
||||||
handlePopUpOpen("accessAccount", e);
|
handlePopUpOpen("accessAccount", e);
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export const PamSessionLogsSection = ({ session }: Props) => {
|
|||||||
<div className="flex items-center border-b border-mineshaft-400 pb-4">
|
<div className="flex items-center border-b border-mineshaft-400 pb-4">
|
||||||
<h3 className="text-lg font-semibold text-mineshaft-100">Session Logs</h3>
|
<h3 className="text-lg font-semibold text-mineshaft-100">Session Logs</h3>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex grow flex-col gap-4 overflow-y-auto text-xs">
|
<div className="flex grow flex-col gap-8 overflow-y-auto text-xs">
|
||||||
{session.commandLogs.length > 0 ? (
|
{session.commandLogs.length > 0 ? (
|
||||||
session.commandLogs.map((log) => (
|
session.commandLogs.map((log) => (
|
||||||
<div key={log.timestamp} className="flex flex-col">
|
<div key={log.timestamp} className="flex flex-col">
|
||||||
|
|||||||
Reference in New Issue
Block a user