mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-17 12:56:29 +00:00
Revert "Permission phase 2"
This commit is contained in:
@@ -12,7 +12,6 @@ import { PermissionDeniedBanner } from "@app/components/permissions";
|
||||
import { ContentLoader, Pagination } from "@app/components/v2";
|
||||
import {
|
||||
ProjectPermissionActions,
|
||||
ProjectPermissionDynamicSecretActions,
|
||||
ProjectPermissionSub,
|
||||
useProjectPermission,
|
||||
useWorkspace
|
||||
@@ -38,7 +37,7 @@ import { ActionBar } from "./components/ActionBar";
|
||||
import { CreateSecretForm } from "./components/CreateSecretForm";
|
||||
import { PitDrawer } from "./components/PitDrawer";
|
||||
import { SecretDropzone } from "./components/SecretDropzone";
|
||||
import { SecretListView, SecretNoAccessListView } from "./components/SecretListView";
|
||||
import { SecretListView } from "./components/SecretListView";
|
||||
import { SnapshotView } from "./components/SnapshotView";
|
||||
import { StoreProvider } from "./SecretMainPage.store";
|
||||
import { Filter, RowType } from "./SecretMainPage.types";
|
||||
@@ -80,24 +79,8 @@ export const SecretMainPage = () => {
|
||||
const secretPath = (router.query.secretPath as string) || "/";
|
||||
const canReadSecret = permission.can(
|
||||
ProjectPermissionActions.Read,
|
||||
subject(ProjectPermissionSub.Secrets, {
|
||||
environment,
|
||||
secretPath,
|
||||
secretName: "*",
|
||||
secretTags: ["*"]
|
||||
})
|
||||
subject(ProjectPermissionSub.Secrets, { environment, secretPath })
|
||||
);
|
||||
|
||||
const canReadSecretImports = permission.can(
|
||||
ProjectPermissionActions.Read,
|
||||
subject(ProjectPermissionSub.SecretImports, { environment, secretPath })
|
||||
);
|
||||
|
||||
const canReadDynamicSecret = permission.can(
|
||||
ProjectPermissionDynamicSecretActions.ReadRootCredential,
|
||||
subject(ProjectPermissionSub.DynamicSecrets, { environment, secretPath })
|
||||
);
|
||||
|
||||
const canDoReadRollback = permission.can(
|
||||
ProjectPermissionActions.Read,
|
||||
ProjectPermissionSub.SecretRollback
|
||||
@@ -106,12 +89,11 @@ export const SecretMainPage = () => {
|
||||
const defaultFilterState = {
|
||||
tags: {},
|
||||
searchFilter: (router.query.searchFilter as string) || "",
|
||||
// these should always be on by default for the UI, they will be disabled for the query below based off permissions
|
||||
include: {
|
||||
[RowType.Folder]: true,
|
||||
[RowType.Import]: true,
|
||||
[RowType.DynamicSecret]: true,
|
||||
[RowType.Secret]: true
|
||||
[RowType.Import]: canReadSecret,
|
||||
[RowType.DynamicSecret]: canReadSecret,
|
||||
[RowType.Secret]: canReadSecret
|
||||
}
|
||||
};
|
||||
|
||||
@@ -119,6 +101,19 @@ export const SecretMainPage = () => {
|
||||
const [debouncedSearchFilter, setDebouncedSearchFilter] = useDebounce(filter.searchFilter);
|
||||
const [filterHistory, setFilterHistory] = useState<Map<string, Filter>>(new Map());
|
||||
|
||||
// change filters if permissions change at different paths/env
|
||||
useEffect(() => {
|
||||
setFilter((prev) => ({
|
||||
...prev,
|
||||
include: {
|
||||
[RowType.Folder]: true,
|
||||
[RowType.Import]: canReadSecret,
|
||||
[RowType.DynamicSecret]: canReadSecret,
|
||||
[RowType.Secret]: canReadSecret
|
||||
}
|
||||
}));
|
||||
}, [canReadSecret]);
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
!isWorkspaceLoading &&
|
||||
@@ -146,9 +141,9 @@ export const SecretMainPage = () => {
|
||||
orderBy,
|
||||
search: debouncedSearchFilter,
|
||||
orderDirection,
|
||||
includeImports: canReadSecretImports && filter.include.import,
|
||||
includeImports: canReadSecret && filter.include.import,
|
||||
includeFolders: filter.include.folder,
|
||||
includeDynamicSecrets: canReadDynamicSecret && filter.include.dynamic,
|
||||
includeDynamicSecrets: canReadSecret && filter.include.dynamic,
|
||||
includeSecrets: canReadSecret && filter.include.secret,
|
||||
tags: filter.tags
|
||||
});
|
||||
@@ -210,20 +205,8 @@ export const SecretMainPage = () => {
|
||||
isPaused: !canDoReadRollback
|
||||
});
|
||||
|
||||
const noAccessSecretCount = Math.max(
|
||||
(page * perPage > totalCount ? totalCount % perPage : perPage) -
|
||||
(imports?.length || 0) -
|
||||
(folders?.length || 0) -
|
||||
(secrets?.length || 0) -
|
||||
(dynamicSecrets?.length || 0),
|
||||
0
|
||||
);
|
||||
const isNotEmpty = Boolean(
|
||||
secrets?.length ||
|
||||
folders?.length ||
|
||||
imports?.length ||
|
||||
dynamicSecrets?.length ||
|
||||
noAccessSecretCount
|
||||
secrets?.length || folders?.length || imports?.length || dynamicSecrets?.length
|
||||
);
|
||||
|
||||
const handleSortToggle = () =>
|
||||
@@ -315,6 +298,7 @@ export const SecretMainPage = () => {
|
||||
setFilter(defaultFilterState);
|
||||
setDebouncedSearchFilter("");
|
||||
};
|
||||
|
||||
return (
|
||||
<StoreProvider>
|
||||
<div className="container mx-auto flex flex-col px-6 text-mineshaft-50 dark:[color-scheme:dark]">
|
||||
@@ -378,7 +362,7 @@ export const SecretMainPage = () => {
|
||||
<div className="flex-grow px-4 py-2">Value</div>
|
||||
</div>
|
||||
)}
|
||||
{canReadSecretImports && Boolean(imports?.length) && (
|
||||
{canReadSecret && imports?.length && (
|
||||
<SecretImportListView
|
||||
searchTerm={debouncedSearchFilter}
|
||||
secretImports={imports}
|
||||
@@ -389,7 +373,7 @@ export const SecretMainPage = () => {
|
||||
importedSecrets={importedSecrets}
|
||||
/>
|
||||
)}
|
||||
{Boolean(folders?.length) && (
|
||||
{folders?.length && (
|
||||
<FolderListView
|
||||
folders={folders}
|
||||
environment={environment}
|
||||
@@ -398,7 +382,7 @@ export const SecretMainPage = () => {
|
||||
onNavigateToFolder={handleResetFilter}
|
||||
/>
|
||||
)}
|
||||
{canReadDynamicSecret && Boolean(dynamicSecrets?.length) && (
|
||||
{canReadSecret && dynamicSecrets?.length && (
|
||||
<DynamicSecretListView
|
||||
environment={environment}
|
||||
projectSlug={projectSlug}
|
||||
@@ -406,7 +390,7 @@ export const SecretMainPage = () => {
|
||||
dynamicSecrets={dynamicSecrets}
|
||||
/>
|
||||
)}
|
||||
{canReadSecret && Boolean(secrets?.length) && (
|
||||
{canReadSecret && secrets?.length && (
|
||||
<SecretListView
|
||||
secrets={secrets}
|
||||
tags={tags}
|
||||
@@ -417,11 +401,7 @@ export const SecretMainPage = () => {
|
||||
isProtectedBranch={isProtectedBranch}
|
||||
/>
|
||||
)}
|
||||
{canReadSecret && <SecretNoAccessListView count={noAccessSecretCount} />}
|
||||
{!canReadSecret &&
|
||||
!canReadDynamicSecret &&
|
||||
!canReadSecretImports &&
|
||||
folders?.length === 0 && <PermissionDeniedBanner />}
|
||||
{!canReadSecret && folders?.length === 0 && <PermissionDeniedBanner />}
|
||||
</div>
|
||||
</div>
|
||||
{!isDetailsLoading && totalCount > 0 && (
|
||||
|
||||
@@ -47,8 +47,8 @@ import {
|
||||
} from "@app/components/v2";
|
||||
import {
|
||||
ProjectPermissionActions,
|
||||
ProjectPermissionDynamicSecretActions,
|
||||
ProjectPermissionSub,
|
||||
useProjectPermission,
|
||||
useSubscription
|
||||
} from "@app/context";
|
||||
import { usePopUp } from "@app/hooks";
|
||||
@@ -125,6 +125,12 @@ export const ActionBar = ({
|
||||
const { reset: resetSelectedSecret } = useSelectedSecretActions();
|
||||
const isMultiSelectActive = Boolean(Object.keys(selectedSecrets).length);
|
||||
|
||||
const { permission } = useProjectPermission();
|
||||
|
||||
const shouldCheckFolderPermission = permission.rules.some((rule) =>
|
||||
(rule.subject as ProjectPermissionSub[]).includes(ProjectPermissionSub.SecretFolders)
|
||||
);
|
||||
|
||||
const handleFolderCreate = async (folderName: string) => {
|
||||
try {
|
||||
await createFolder({
|
||||
@@ -432,12 +438,7 @@ export const ActionBar = ({
|
||||
<div className="flex items-center">
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionActions.Create}
|
||||
a={subject(ProjectPermissionSub.Secrets, {
|
||||
environment,
|
||||
secretPath,
|
||||
secretName: "*",
|
||||
secretTags: ["*"]
|
||||
})}
|
||||
a={subject(ProjectPermissionSub.Secrets, { environment, secretPath })}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<Button
|
||||
@@ -468,7 +469,12 @@ export const ActionBar = ({
|
||||
<div className="flex flex-col space-y-1 p-1.5">
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionActions.Create}
|
||||
a={subject(ProjectPermissionSub.SecretFolders, { environment, secretPath })}
|
||||
a={subject(
|
||||
shouldCheckFolderPermission
|
||||
? ProjectPermissionSub.SecretFolders
|
||||
: ProjectPermissionSub.Secrets,
|
||||
{ environment, secretPath }
|
||||
)}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<Button
|
||||
@@ -487,13 +493,8 @@ export const ActionBar = ({
|
||||
)}
|
||||
</ProjectPermissionCan>
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionDynamicSecretActions.CreateRootCredential}
|
||||
a={subject(ProjectPermissionSub.DynamicSecrets, {
|
||||
environment,
|
||||
secretPath,
|
||||
secretName: "*",
|
||||
secretTags: ["*"]
|
||||
})}
|
||||
I={ProjectPermissionActions.Create}
|
||||
a={subject(ProjectPermissionSub.Secrets, { environment, secretPath })}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<Button
|
||||
@@ -517,10 +518,7 @@ export const ActionBar = ({
|
||||
</ProjectPermissionCan>
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionActions.Create}
|
||||
a={subject(ProjectPermissionSub.SecretImports, {
|
||||
environment,
|
||||
secretPath
|
||||
})}
|
||||
a={subject(ProjectPermissionSub.Secrets, { environment, secretPath })}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<Button
|
||||
@@ -560,12 +558,7 @@ export const ActionBar = ({
|
||||
</div>
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionActions.Delete}
|
||||
a={subject(ProjectPermissionSub.Secrets, {
|
||||
environment,
|
||||
secretPath,
|
||||
secretName: "*",
|
||||
secretTags: ["*"]
|
||||
})}
|
||||
a={subject(ProjectPermissionSub.Secrets, { environment, secretPath })}
|
||||
renderTooltip
|
||||
allowedLabel="Move"
|
||||
>
|
||||
@@ -584,12 +577,7 @@ export const ActionBar = ({
|
||||
</ProjectPermissionCan>
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionActions.Delete}
|
||||
a={subject(ProjectPermissionSub.Secrets, {
|
||||
environment,
|
||||
secretPath,
|
||||
secretName: "*",
|
||||
secretTags: ["*"]
|
||||
})}
|
||||
a={subject(ProjectPermissionSub.Secrets, { environment, secretPath })}
|
||||
renderTooltip
|
||||
allowedLabel="Delete"
|
||||
>
|
||||
|
||||
+11
-23
@@ -26,7 +26,7 @@ import {
|
||||
Tooltip,
|
||||
Tr
|
||||
} from "@app/components/v2";
|
||||
import { ProjectPermissionDynamicSecretActions, ProjectPermissionSub } from "@app/context";
|
||||
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/context";
|
||||
import { usePopUp } from "@app/hooks";
|
||||
import { useGetDynamicSecretLeases, useRevokeDynamicSecretLease } from "@app/hooks/api";
|
||||
import { DynamicSecretLeaseStatus } from "@app/hooks/api/dynamicSecretLease/types";
|
||||
@@ -60,6 +60,7 @@ export const DynamicSecretLease = ({
|
||||
path: secretPath,
|
||||
dynamicSecretName
|
||||
});
|
||||
|
||||
|
||||
const deleteDynamicSecretLease = useRevokeDynamicSecretLease();
|
||||
|
||||
@@ -139,8 +140,8 @@ export const DynamicSecretLease = ({
|
||||
<Td>
|
||||
<div className="flex items-center space-x-4">
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionDynamicSecretActions.Lease}
|
||||
a={subject(ProjectPermissionSub.DynamicSecrets, { environment, secretPath })}
|
||||
I={ProjectPermissionActions.Edit}
|
||||
a={subject(ProjectPermissionSub.Secrets, { environment, secretPath })}
|
||||
renderTooltip
|
||||
allowedLabel="Renew"
|
||||
>
|
||||
@@ -158,8 +159,8 @@ export const DynamicSecretLease = ({
|
||||
)}
|
||||
</ProjectPermissionCan>
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionDynamicSecretActions.Lease}
|
||||
a={subject(ProjectPermissionSub.DynamicSecrets, { environment, secretPath })}
|
||||
I={ProjectPermissionActions.Delete}
|
||||
a={subject(ProjectPermissionSub.Secrets, { environment, secretPath })}
|
||||
renderTooltip
|
||||
allowedLabel="Delete"
|
||||
>
|
||||
@@ -178,11 +179,8 @@ export const DynamicSecretLease = ({
|
||||
</ProjectPermissionCan>
|
||||
{status === DynamicSecretLeaseStatus.FailedDeletion && (
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionDynamicSecretActions.Lease}
|
||||
a={subject(ProjectPermissionSub.DynamicSecrets, {
|
||||
environment,
|
||||
secretPath
|
||||
})}
|
||||
I={ProjectPermissionActions.Delete}
|
||||
a={subject(ProjectPermissionSub.Secrets, { environment, secretPath })}
|
||||
renderTooltip
|
||||
allowedLabel="Force Delete. This action will remove the secret from internal storage, but it will remain in external systems."
|
||||
>
|
||||
@@ -211,19 +209,9 @@ export const DynamicSecretLease = ({
|
||||
</TableContainer>
|
||||
{!isLeaseLoading && Boolean(leases?.length) && (
|
||||
<div className="mt-6 flex items-center space-x-4">
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionDynamicSecretActions.Lease}
|
||||
a={subject(ProjectPermissionSub.DynamicSecrets, {
|
||||
environment,
|
||||
secretPath
|
||||
})}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<Button onClick={onClickNewLease} size="xs" isDisabled={!isAllowed}>
|
||||
New Lease
|
||||
</Button>
|
||||
)}
|
||||
</ProjectPermissionCan>
|
||||
<Button onClick={onClickNewLease} size="xs">
|
||||
New Lease
|
||||
</Button>
|
||||
<Button onClick={onClose} variant="plain" colorSchema="secondary" size="xs">
|
||||
Close
|
||||
</Button>
|
||||
|
||||
+15
-25
@@ -18,7 +18,7 @@ import {
|
||||
Tag,
|
||||
Tooltip
|
||||
} from "@app/components/v2";
|
||||
import { ProjectPermissionDynamicSecretActions, ProjectPermissionSub } from "@app/context";
|
||||
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/context";
|
||||
import { usePopUp } from "@app/hooks";
|
||||
import { useDeleteDynamicSecret } from "@app/hooks/api";
|
||||
import {
|
||||
@@ -132,27 +132,17 @@ export const DynamicSecretListView = ({
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center space-x-2 px-4 py-2">
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionDynamicSecretActions.Lease}
|
||||
a={subject(ProjectPermissionSub.DynamicSecrets, { environment, secretPath })}
|
||||
renderTooltip
|
||||
allowedLabel="Edit"
|
||||
<Button
|
||||
size="xs"
|
||||
className="m-0 py-0.5 px-2 opacity-0 group-hover:opacity-100"
|
||||
isDisabled={isRevoking}
|
||||
onClick={(evt) => {
|
||||
evt.stopPropagation();
|
||||
handlePopUpOpen("createDynamicSecretLease", secret);
|
||||
}}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<Button
|
||||
size="xs"
|
||||
className="m-0 py-0.5 px-2 opacity-0 group-hover:opacity-100"
|
||||
isDisabled={isRevoking || !isAllowed}
|
||||
onClick={(evt) => {
|
||||
evt.stopPropagation();
|
||||
handlePopUpOpen("createDynamicSecretLease", secret);
|
||||
}}
|
||||
>
|
||||
Generate
|
||||
</Button>
|
||||
)}
|
||||
</ProjectPermissionCan>
|
||||
|
||||
Generate
|
||||
</Button>
|
||||
{secret.status === DynamicSecretStatus.FailedDeletion && (
|
||||
<Tooltip content="This action will remove the secret from internal storage, but it will remain in external systems. Use this option only after you've confirmed that your external leases are handled.">
|
||||
<Button
|
||||
@@ -175,8 +165,8 @@ export const DynamicSecretListView = ({
|
||||
</div>
|
||||
<div className="flex items-center space-x-4 border-l border-mineshaft-600 px-3 py-3">
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionDynamicSecretActions.EditRootCredential}
|
||||
a={subject(ProjectPermissionSub.DynamicSecrets, { environment, secretPath })}
|
||||
I={ProjectPermissionActions.Edit}
|
||||
a={subject(ProjectPermissionSub.Secrets, { environment, secretPath })}
|
||||
renderTooltip
|
||||
allowedLabel="Edit"
|
||||
>
|
||||
@@ -197,8 +187,8 @@ export const DynamicSecretListView = ({
|
||||
)}
|
||||
</ProjectPermissionCan>
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionDynamicSecretActions.DeleteRootCredential}
|
||||
a={subject(ProjectPermissionSub.DynamicSecrets, { environment, secretPath })}
|
||||
I={ProjectPermissionActions.Delete}
|
||||
a={subject(ProjectPermissionSub.Secrets, { environment, secretPath })}
|
||||
renderTooltip
|
||||
allowedLabel="Delete"
|
||||
>
|
||||
|
||||
@@ -6,7 +6,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
import { ProjectPermissionCan } from "@app/components/permissions";
|
||||
import { DeleteActionModal, IconButton, Modal, ModalContent } from "@app/components/v2";
|
||||
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/context";
|
||||
import { ProjectPermissionActions, ProjectPermissionSub, useProjectPermission } from "@app/context";
|
||||
import { usePopUp } from "@app/hooks";
|
||||
import { useDeleteFolder, useUpdateFolder } from "@app/hooks/api";
|
||||
import { TSecretFolder } from "@app/hooks/api/secretFolders/types";
|
||||
@@ -33,6 +33,11 @@ export const FolderListView = ({
|
||||
"deleteFolder"
|
||||
] as const);
|
||||
const router = useRouter();
|
||||
const { permission } = useProjectPermission();
|
||||
|
||||
const shouldCheckFolderPermission = permission.rules.some((rule) =>
|
||||
(rule.subject as ProjectPermissionSub[]).includes(ProjectPermissionSub.SecretFolders)
|
||||
);
|
||||
|
||||
const { mutateAsync: updateFolder } = useUpdateFolder();
|
||||
const { mutateAsync: deleteFolder } = useDeleteFolder();
|
||||
@@ -121,7 +126,12 @@ export const FolderListView = ({
|
||||
<div className="flex items-center space-x-4 border-l border-mineshaft-600 px-3 py-3">
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionActions.Edit}
|
||||
a={subject(ProjectPermissionSub.SecretFolders, { environment, secretPath })}
|
||||
a={subject(
|
||||
shouldCheckFolderPermission
|
||||
? ProjectPermissionSub.SecretFolders
|
||||
: ProjectPermissionSub.Secrets,
|
||||
{ environment, secretPath }
|
||||
)}
|
||||
renderTooltip
|
||||
allowedLabel="Edit"
|
||||
>
|
||||
@@ -140,7 +150,12 @@ export const FolderListView = ({
|
||||
</ProjectPermissionCan>
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionActions.Delete}
|
||||
a={subject(ProjectPermissionSub.SecretFolders, { environment, secretPath })}
|
||||
a={subject(
|
||||
shouldCheckFolderPermission
|
||||
? ProjectPermissionSub.SecretFolders
|
||||
: ProjectPermissionSub.Secrets,
|
||||
{ environment, secretPath }
|
||||
)}
|
||||
renderTooltip
|
||||
allowedLabel="Delete"
|
||||
>
|
||||
|
||||
+1
-6
@@ -142,12 +142,7 @@ export const CopySecretsFromBoard = ({
|
||||
<div>
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionActions.Create}
|
||||
a={subject(ProjectPermissionSub.Secrets, {
|
||||
environment,
|
||||
secretPath,
|
||||
secretName: "*",
|
||||
secretTags: ["*"]
|
||||
})}
|
||||
a={subject(ProjectPermissionSub.Secrets, { environment, secretPath })}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<Button
|
||||
|
||||
@@ -250,12 +250,7 @@ export const SecretDropzone = ({
|
||||
</div>
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionActions.Create}
|
||||
a={subject(ProjectPermissionSub.Secrets, {
|
||||
environment,
|
||||
secretPath,
|
||||
secretName: "*",
|
||||
secretTags: ["*"]
|
||||
})}
|
||||
a={subject(ProjectPermissionSub.Secrets, { environment, secretPath })}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<input
|
||||
@@ -292,12 +287,7 @@ export const SecretDropzone = ({
|
||||
{!isSmaller && (
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionActions.Create}
|
||||
a={subject(ProjectPermissionSub.Secrets, {
|
||||
environment,
|
||||
secretPath,
|
||||
secretName: "*",
|
||||
secretTags: ["*"]
|
||||
})}
|
||||
a={subject(ProjectPermissionSub.Secrets, { environment, secretPath })}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<Button
|
||||
|
||||
+4
-7
@@ -67,7 +67,7 @@ export const SecretImportItem = ({
|
||||
isReplicationExpand,
|
||||
importedSecrets = [],
|
||||
searchTerm = "",
|
||||
secretPath = "/",
|
||||
secretPath,
|
||||
environment,
|
||||
secretImport,
|
||||
onExpandReplicateSecrets: onExpandReplicate
|
||||
@@ -209,7 +209,7 @@ export const SecretImportItem = ({
|
||||
{isReplication && (
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionActions.Edit}
|
||||
a={subject(ProjectPermissionSub.SecretImports, { environment, secretPath })}
|
||||
a={subject(ProjectPermissionSub.Secrets, { environment, secretPath })}
|
||||
renderTooltip
|
||||
allowedLabel="Resync replicated secrets"
|
||||
>
|
||||
@@ -235,10 +235,7 @@ export const SecretImportItem = ({
|
||||
<div className="flex items-center space-x-4 border-l border-mineshaft-600 px-4 py-2">
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionActions.Edit}
|
||||
a={subject(ProjectPermissionSub.SecretImports, {
|
||||
environment,
|
||||
secretPath: secretPath || "/"
|
||||
})}
|
||||
a={subject(ProjectPermissionSub.Secrets, { environment, secretPath })}
|
||||
renderTooltip
|
||||
allowedLabel="Change order"
|
||||
>
|
||||
@@ -259,7 +256,7 @@ export const SecretImportItem = ({
|
||||
</ProjectPermissionCan>
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionActions.Delete}
|
||||
a={subject(ProjectPermissionSub.SecretImports, { environment, secretPath })}
|
||||
a={subject(ProjectPermissionSub.Secrets, { environment, secretPath })}
|
||||
renderTooltip
|
||||
allowedLabel="Delete"
|
||||
>
|
||||
|
||||
+15
-61
@@ -84,41 +84,26 @@ export const SecretDetailSidebar = ({
|
||||
resolver: zodResolver(formSchema),
|
||||
values: secret
|
||||
});
|
||||
|
||||
const { permission } = useProjectPermission();
|
||||
const cannotEditSecret = permission.cannot(
|
||||
ProjectPermissionActions.Edit,
|
||||
subject(ProjectPermissionSub.Secrets, { environment, secretPath })
|
||||
);
|
||||
const isReadOnly =
|
||||
permission.can(
|
||||
ProjectPermissionActions.Read,
|
||||
subject(ProjectPermissionSub.Secrets, { environment, secretPath })
|
||||
) && cannotEditSecret;
|
||||
|
||||
const { fields, append, remove } = useFieldArray({
|
||||
control,
|
||||
name: "tags"
|
||||
});
|
||||
|
||||
const secretKey = secret?.key || "";
|
||||
const selectedTags = watch("tags", []) || [];
|
||||
const selectedTagsGroupById = selectedTags.reduce<Record<string, boolean>>(
|
||||
(prev, curr) => ({ ...prev, [curr.id]: true }),
|
||||
{}
|
||||
);
|
||||
const selectTagSlugs = selectedTags.map((i) => i.slug);
|
||||
|
||||
const cannotEditSecret = permission.cannot(
|
||||
ProjectPermissionActions.Edit,
|
||||
subject(ProjectPermissionSub.Secrets, {
|
||||
environment,
|
||||
secretPath,
|
||||
secretName: secretKey,
|
||||
secretTags: selectTagSlugs
|
||||
})
|
||||
);
|
||||
const isReadOnly =
|
||||
permission.can(
|
||||
ProjectPermissionActions.Read,
|
||||
subject(ProjectPermissionSub.Secrets, {
|
||||
environment,
|
||||
secretPath,
|
||||
secretName: secretKey,
|
||||
secretTags: selectTagSlugs
|
||||
})
|
||||
) && cannotEditSecret;
|
||||
|
||||
const overrideAction = watch("overrideAction");
|
||||
const isOverridden =
|
||||
@@ -209,12 +194,7 @@ export const SecretDetailSidebar = ({
|
||||
</FormControl>
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionActions.Edit}
|
||||
a={subject(ProjectPermissionSub.Secrets, {
|
||||
environment,
|
||||
secretPath,
|
||||
secretName: secretKey,
|
||||
secretTags: selectTagSlugs
|
||||
})}
|
||||
a={subject(ProjectPermissionSub.Secrets, { environment, secretPath })}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<Controller
|
||||
@@ -241,12 +221,7 @@ export const SecretDetailSidebar = ({
|
||||
<div className="mb-2 border-b border-mineshaft-600 pb-4">
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionActions.Edit}
|
||||
a={subject(ProjectPermissionSub.Secrets, {
|
||||
environment,
|
||||
secretPath,
|
||||
secretName: secretKey,
|
||||
secretTags: selectTagSlugs
|
||||
})}
|
||||
a={subject(ProjectPermissionSub.Secrets, { environment, secretPath })}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<Switch
|
||||
@@ -302,12 +277,7 @@ export const SecretDetailSidebar = ({
|
||||
<DropdownMenu>
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionActions.Edit}
|
||||
a={subject(ProjectPermissionSub.Secrets, {
|
||||
environment,
|
||||
secretPath,
|
||||
secretName: secretKey,
|
||||
secretTags: selectTagSlugs
|
||||
})}
|
||||
a={subject(ProjectPermissionSub.Secrets, { environment, secretPath })}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<DropdownMenuTrigger asChild>
|
||||
@@ -397,7 +367,6 @@ export const SecretDetailSidebar = ({
|
||||
variant="outline_bg"
|
||||
leftIcon={<FontAwesomeIcon icon={faClock} />}
|
||||
onClick={() => setCreateReminderFormOpen.on()}
|
||||
isDisabled={cannotEditSecret}
|
||||
>
|
||||
Create Reminder
|
||||
</Button>
|
||||
@@ -419,12 +388,7 @@ export const SecretDetailSidebar = ({
|
||||
render={({ field: { value, onChange, onBlur } }) => (
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionActions.Edit}
|
||||
a={subject(ProjectPermissionSub.Secrets, {
|
||||
environment,
|
||||
secretPath,
|
||||
secretName: secretKey,
|
||||
secretTags: selectTagSlugs
|
||||
})}
|
||||
a={subject(ProjectPermissionSub.Secrets, { environment, secretPath })}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<Switch
|
||||
@@ -486,12 +450,7 @@ export const SecretDetailSidebar = ({
|
||||
<div className="flex items-center space-x-4">
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionActions.Edit}
|
||||
a={subject(ProjectPermissionSub.Secrets, {
|
||||
environment,
|
||||
secretPath,
|
||||
secretName: secretKey,
|
||||
secretTags: selectTagSlugs
|
||||
})}
|
||||
a={subject(ProjectPermissionSub.Secrets, { environment, secretPath })}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<Button
|
||||
@@ -506,12 +465,7 @@ export const SecretDetailSidebar = ({
|
||||
</ProjectPermissionCan>
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionActions.Delete}
|
||||
a={subject(ProjectPermissionSub.Secrets, {
|
||||
environment,
|
||||
secretPath,
|
||||
secretName: secretKey,
|
||||
secretTags: selectTagSlugs
|
||||
})}
|
||||
a={subject(ProjectPermissionSub.Secrets, { environment, secretPath })}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<Button colorSchema="danger" isDisabled={!isAllowed} onClick={onDeleteSecret}>
|
||||
|
||||
@@ -81,6 +81,15 @@ export const SecretItem = memo(
|
||||
}: Props) => {
|
||||
const { currentWorkspace } = useWorkspace();
|
||||
const { permission } = useProjectPermission();
|
||||
const isReadOnly =
|
||||
permission.can(
|
||||
ProjectPermissionActions.Read,
|
||||
subject(ProjectPermissionSub.Secrets, { environment, secretPath })
|
||||
) &&
|
||||
permission.cannot(
|
||||
ProjectPermissionActions.Edit,
|
||||
subject(ProjectPermissionSub.Secrets, { environment, secretPath })
|
||||
);
|
||||
|
||||
const {
|
||||
handleSubmit,
|
||||
@@ -98,8 +107,6 @@ export const SecretItem = memo(
|
||||
resolver: zodResolver(formSchema)
|
||||
});
|
||||
|
||||
const secretName = watch("key");
|
||||
|
||||
const secretReminderRepeatDays = watch("reminderRepeatDays");
|
||||
const secretReminderNote = watch("reminderNote");
|
||||
|
||||
@@ -111,33 +118,11 @@ export const SecretItem = memo(
|
||||
(prev, curr) => ({ ...prev, [curr.id]: true }),
|
||||
{}
|
||||
);
|
||||
const selectedTagSlugs = selectedTags.map((i) => i.slug);
|
||||
|
||||
const { fields, append, remove } = useFieldArray({
|
||||
control,
|
||||
name: "tags"
|
||||
});
|
||||
|
||||
const isReadOnly =
|
||||
permission.can(
|
||||
ProjectPermissionActions.Read,
|
||||
subject(ProjectPermissionSub.Secrets, {
|
||||
environment,
|
||||
secretPath,
|
||||
secretName,
|
||||
secretTags: selectedTagSlugs
|
||||
})
|
||||
) &&
|
||||
permission.cannot(
|
||||
ProjectPermissionActions.Edit,
|
||||
subject(ProjectPermissionSub.Secrets, {
|
||||
environment,
|
||||
secretPath,
|
||||
secretName,
|
||||
secretTags: selectedTagSlugs
|
||||
})
|
||||
);
|
||||
|
||||
const [isSecValueCopied, setIsSecValueCopied] = useToggle(false);
|
||||
const [createReminderFormOpen, setCreateReminderFormOpen] = useToggle(false);
|
||||
useEffect(() => {
|
||||
@@ -324,12 +309,7 @@ export const SecretItem = memo(
|
||||
<DropdownMenu>
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionActions.Edit}
|
||||
a={subject(ProjectPermissionSub.Secrets, {
|
||||
environment,
|
||||
secretPath,
|
||||
secretName,
|
||||
secretTags: selectedTagSlugs
|
||||
})}
|
||||
a={subject(ProjectPermissionSub.Secrets, { environment, secretPath })}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<DropdownMenuTrigger asChild disabled={!isAllowed}>
|
||||
@@ -404,12 +384,7 @@ export const SecretItem = memo(
|
||||
</DropdownMenu>
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionActions.Edit}
|
||||
a={subject(ProjectPermissionSub.Secrets, {
|
||||
environment,
|
||||
secretPath,
|
||||
secretName,
|
||||
secretTags: selectedTagSlugs
|
||||
})}
|
||||
a={subject(ProjectPermissionSub.Secrets, { environment, secretPath })}
|
||||
renderTooltip
|
||||
allowedLabel="Override"
|
||||
>
|
||||
@@ -465,12 +440,7 @@ export const SecretItem = memo(
|
||||
<Popover>
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionActions.Edit}
|
||||
a={subject(ProjectPermissionSub.Secrets, {
|
||||
environment,
|
||||
secretPath,
|
||||
secretName,
|
||||
secretTags: selectedTagSlugs
|
||||
})}
|
||||
a={subject(ProjectPermissionSub.Secrets, { environment, secretPath })}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<PopoverTrigger asChild disabled={!isAllowed}>
|
||||
@@ -549,12 +519,7 @@ export const SecretItem = memo(
|
||||
</Tooltip>
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionActions.Delete}
|
||||
a={subject(ProjectPermissionSub.Secrets, {
|
||||
environment,
|
||||
secretPath,
|
||||
secretName,
|
||||
secretTags: selectedTagSlugs
|
||||
})}
|
||||
a={subject(ProjectPermissionSub.Secrets, { environment, secretPath })}
|
||||
renderTooltip
|
||||
allowedLabel="Delete"
|
||||
>
|
||||
|
||||
@@ -16,6 +16,7 @@ import { WsTag } from "@app/hooks/api/types";
|
||||
import { AddShareSecretModal } from "@app/views/ShareSecretPage/components/AddShareSecretModal";
|
||||
|
||||
import { useSelectedSecretActions, useSelectedSecrets } from "../../SecretMainPage.store";
|
||||
import { Filter } from "../../SecretMainPage.types";
|
||||
import { SecretDetailSidebar } from "./SecretDetaiSidebar";
|
||||
import { SecretItem } from "./SecretItem";
|
||||
import { FontAwesomeSpriteSymbols } from "./SecretListView.utils";
|
||||
@@ -30,6 +31,16 @@ type Props = {
|
||||
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 = ({
|
||||
secrets = [],
|
||||
environment,
|
||||
|
||||
@@ -10,7 +10,6 @@ import {
|
||||
faCopy,
|
||||
faEllipsis,
|
||||
faKey,
|
||||
faLock,
|
||||
faShare,
|
||||
faTags
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
@@ -72,8 +71,7 @@ export enum FontAwesomeSpriteName {
|
||||
Close = "close",
|
||||
CheckedCircle = "check-circle",
|
||||
ReplicatedSecretKey = "secret-replicated",
|
||||
ShareSecret = "share-secret",
|
||||
KeyLock = "key-lock"
|
||||
ShareSecret = "share-secret"
|
||||
}
|
||||
|
||||
// this is an optimization technique
|
||||
@@ -90,6 +88,5 @@ export const FontAwesomeSpriteSymbols = [
|
||||
{ icon: faClose, symbol: FontAwesomeSpriteName.Close },
|
||||
{ icon: faCheckCircle, symbol: FontAwesomeSpriteName.CheckedCircle },
|
||||
{ icon: faClone, symbol: FontAwesomeSpriteName.ReplicatedSecretKey },
|
||||
{ icon: faShare, symbol: FontAwesomeSpriteName.ShareSecret },
|
||||
{ icon: faLock, symbol: FontAwesomeSpriteName.KeyLock }
|
||||
{ icon: faShare, symbol: FontAwesomeSpriteName.ShareSecret }
|
||||
];
|
||||
|
||||
-49
@@ -1,49 +0,0 @@
|
||||
import { FontAwesomeSymbol, Input, Tooltip } 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) => (
|
||||
<Tooltip
|
||||
className="max-w-sm"
|
||||
asChild
|
||||
content="You do not have permission to view this secret"
|
||||
key={`no-access-secret-${i + 1}`}
|
||||
>
|
||||
<div className="flex border-b border-mineshaft-600 bg-mineshaft-800 shadow-none hover:bg-mineshaft-700">
|
||||
<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>
|
||||
</Tooltip>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -1,2 +1 @@
|
||||
export { SecretListView } from "./SecretListView";
|
||||
export { SecretNoAccessListView } from "./SecretNoAccessListView";
|
||||
|
||||
Reference in New Issue
Block a user