feat: added no secret access views

This commit is contained in:
=
2024-10-18 00:33:36 +05:30
parent a9e6c229d0
commit 0f10874f80
9 changed files with 110 additions and 17 deletions
@@ -1,5 +1,5 @@
/* eslint-disable no-await-in-loop */ /* eslint-disable no-await-in-loop */
import { unpackRules } from "@casl/ability/extra"; import { packRules, unpackRules } from "@casl/ability/extra";
import { Knex } from "knex"; import { Knex } from "knex";
import { import {
@@ -764,7 +764,7 @@ export const backfillPermissionV1SchemaToV2Schema = (data: z.infer<typeof Projec
const secretFolderPolicies = secretSubjects.map(({ subject, ...el }) => ({ const secretFolderPolicies = secretSubjects.map(({ subject, ...el }) => ({
...el, ...el,
subject: ProjectPermissionSub.DynamicSecrets subject: ProjectPermissionSub.SecretFolders
})); }));
const dynamicSecretPolicies = secretSubjects.map(({ subject, ...el }) => ({ const dynamicSecretPolicies = secretSubjects.map(({ subject, ...el }) => ({
@@ -38,7 +38,7 @@ import { ActionBar } from "./components/ActionBar";
import { CreateSecretForm } from "./components/CreateSecretForm"; import { CreateSecretForm } from "./components/CreateSecretForm";
import { PitDrawer } from "./components/PitDrawer"; import { PitDrawer } from "./components/PitDrawer";
import { SecretDropzone } from "./components/SecretDropzone"; import { SecretDropzone } from "./components/SecretDropzone";
import { SecretListView } from "./components/SecretListView"; import { SecretListView, SecretNoAccessListView } from "./components/SecretListView";
import { SnapshotView } from "./components/SnapshotView"; import { SnapshotView } from "./components/SnapshotView";
import { StoreProvider } from "./SecretMainPage.store"; import { StoreProvider } from "./SecretMainPage.store";
import { Filter, RowType } from "./SecretMainPage.types"; import { Filter, RowType } from "./SecretMainPage.types";
@@ -315,7 +315,6 @@ export const SecretMainPage = () => {
setFilter(defaultFilterState); setFilter(defaultFilterState);
setDebouncedSearchFilter(""); setDebouncedSearchFilter("");
}; };
return ( return (
<StoreProvider> <StoreProvider>
<div className="container mx-auto flex flex-col px-6 text-mineshaft-50 dark:[color-scheme:dark]"> <div className="container mx-auto flex flex-col px-6 text-mineshaft-50 dark:[color-scheme:dark]">
@@ -418,6 +417,17 @@ export const SecretMainPage = () => {
isProtectedBranch={isProtectedBranch} isProtectedBranch={isProtectedBranch}
/> />
)} )}
{canReadSecret && (
<SecretNoAccessListView
count={Math.max(
(page * perPage > totalCount ? totalCount % perPage : perPage) -
(folders?.length || 0) -
(secrets?.length || 0) -
(dynamicSecrets?.length || 0),
0
)}
/>
)}
{!canReadSecret && {!canReadSecret &&
!canReadDynamicSecret && !canReadDynamicSecret &&
!canReadSecretImports && !canReadSecretImports &&
@@ -16,7 +16,6 @@ import { WsTag } from "@app/hooks/api/types";
import { AddShareSecretModal } from "@app/views/ShareSecretPage/components/AddShareSecretModal"; import { AddShareSecretModal } from "@app/views/ShareSecretPage/components/AddShareSecretModal";
import { useSelectedSecretActions, useSelectedSecrets } from "../../SecretMainPage.store"; import { useSelectedSecretActions, useSelectedSecrets } from "../../SecretMainPage.store";
import { Filter } from "../../SecretMainPage.types";
import { SecretDetailSidebar } from "./SecretDetaiSidebar"; import { SecretDetailSidebar } from "./SecretDetaiSidebar";
import { SecretItem } from "./SecretItem"; import { SecretItem } from "./SecretItem";
import { FontAwesomeSpriteSymbols } from "./SecretListView.utils"; import { FontAwesomeSpriteSymbols } from "./SecretListView.utils";
@@ -31,16 +30,6 @@ type Props = {
isProtectedBranch?: boolean; isProtectedBranch?: boolean;
}; };
export const filterSecrets = (secrets: SecretV3RawSanitized[], filter: Filter) =>
secrets.filter(({ key, value, tags }) => {
const isTagFilterActive = Boolean(Object.keys(filter.tags).length);
const searchTerm = filter.searchFilter.toLowerCase();
return (
(!isTagFilterActive || tags?.some(({ id }) => filter.tags?.[id])) &&
(key.toLowerCase().includes(searchTerm) || value?.toLowerCase().includes(searchTerm))
);
});
export const SecretListView = ({ export const SecretListView = ({
secrets = [], secrets = [],
environment, environment,
@@ -10,6 +10,7 @@ import {
faCopy, faCopy,
faEllipsis, faEllipsis,
faKey, faKey,
faLock,
faShare, faShare,
faTags faTags
} from "@fortawesome/free-solid-svg-icons"; } from "@fortawesome/free-solid-svg-icons";
@@ -71,7 +72,8 @@ export enum FontAwesomeSpriteName {
Close = "close", Close = "close",
CheckedCircle = "check-circle", CheckedCircle = "check-circle",
ReplicatedSecretKey = "secret-replicated", ReplicatedSecretKey = "secret-replicated",
ShareSecret = "share-secret" ShareSecret = "share-secret",
KeyLock = "key-lock"
} }
// this is an optimization technique // this is an optimization technique
@@ -88,5 +90,6 @@ export const FontAwesomeSpriteSymbols = [
{ icon: faClose, symbol: FontAwesomeSpriteName.Close }, { icon: faClose, symbol: FontAwesomeSpriteName.Close },
{ icon: faCheckCircle, symbol: FontAwesomeSpriteName.CheckedCircle }, { icon: faCheckCircle, symbol: FontAwesomeSpriteName.CheckedCircle },
{ icon: faClone, symbol: FontAwesomeSpriteName.ReplicatedSecretKey }, { icon: faClone, symbol: FontAwesomeSpriteName.ReplicatedSecretKey },
{ icon: faShare, symbol: FontAwesomeSpriteName.ShareSecret } { icon: faShare, symbol: FontAwesomeSpriteName.ShareSecret },
{ icon: faLock, symbol: FontAwesomeSpriteName.KeyLock }
]; ];
@@ -0,0 +1,44 @@
import { FontAwesomeSymbol, Input } from "@app/components/v2";
import { FontAwesomeSpriteName } from "./SecretListView.utils";
type Props = {
count: number;
};
export const SecretNoAccessListView = ({ count }: Props) => {
return (
<>
{Array.from(Array(count)).map((_, i) => (
<div
className="flex border-b border-mineshaft-600 bg-mineshaft-800 shadow-none hover:bg-mineshaft-700"
key={`no-access-secret-${i + 1}`}
>
<div className="flex h-11 w-11 items-center justify-center px-4 py-3">
<FontAwesomeSymbol
className="ml-3 block h-3.5 w-3.5"
symbolName={FontAwesomeSpriteName.KeyLock}
/>
</div>
<div className="flex h-11 w-80 flex-shrink-0 items-center px-4 py-2">
<Input
autoComplete="off"
isReadOnly
variant="plain"
value="NO ACCESS"
isDisabled
className="w-full px-0 blur-sm placeholder:text-red-500 focus:text-bunker-100 focus:ring-transparent"
/>
</div>
<div
className="flex w-80 flex-grow items-center border-x border-mineshaft-600 py-1 pl-4 pr-2"
tabIndex={0}
role="button"
>
<span className="blur">********</span>
</div>
</div>
))}
</>
);
};
@@ -1 +1,2 @@
export { SecretListView } from "./SecretListView"; export { SecretListView } from "./SecretListView";
export { SecretNoAccessListView } from "./SecretNoAccessListView";
@@ -0,0 +1,45 @@
import { faCircle } from "@fortawesome/free-regular-svg-icons";
import { faLock } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Td, Tr } from "@app/components/v2";
type Props = {
environments: { name: string; slug: string }[];
count: number;
};
export const SecretNoAccessOverviewTableRow = ({ environments = [], count }: Props) => {
return (
<>
{Array.from(Array(count)).map((_, j) => (
<Tr key={`no-access-secret-overview-${j + 1}`} isHoverable isSelectable className="group">
<Td className="sticky left-0 z-10 bg-mineshaft-800 bg-clip-padding py-0 px-0 group-hover:bg-mineshaft-700">
<div className="h-full w-full border-r border-mineshaft-600 py-2.5 px-5">
<div className="flex items-center space-x-5">
<div className="text-bunker-300">
<FontAwesomeIcon className="block" icon={faLock} />
</div>
<div className="blur-sm">NO ACCESS</div>
</div>
</div>
</Td>
{environments.map(({ slug }, i) => {
return (
<Td
key={`sec-overview-${slug}-${i + 1}-value`}
className="py-0 px-0 group-hover:bg-mineshaft-700"
>
<div className="h-full w-full border-r border-mineshaft-600 py-[0.85rem] px-5">
<div className="flex justify-center">
<FontAwesomeIcon icon={faCircle} />
</div>
</div>
</Td>
);
})}
</Tr>
))}
</>
);
};
@@ -1 +1,2 @@
export { SecretNoAccessOverviewTableRow } from "./SecretNoAccessOverviewTableRow";
export { SecretOverviewTableRow } from "./SecretOverviewTableRow"; export { SecretOverviewTableRow } from "./SecretOverviewTableRow";