-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add view for permission based on resource/team/person
Fixes #2246
- Loading branch information
1 parent
f8de4a8
commit 47f39ac
Showing
6 changed files
with
285 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
import { AVATAR_INFO } from "@flanksource-ui/constants"; | ||
import { IncidentCommander } from "../axios"; | ||
import { resolvePostGrestRequestWithPagination } from "../resolve"; | ||
import { PermissionAPIResponse } from "../types/permissions"; | ||
|
||
export type FetchPermissionsInput = { | ||
componentId?: string; | ||
personId?: string; | ||
teamId?: string; | ||
configId?: string; | ||
checkId?: string; | ||
canaryId?: string; | ||
playbookId?: string; | ||
}; | ||
|
||
function composeQueryParamForFetchPermissions({ | ||
componentId, | ||
personId, | ||
teamId, | ||
configId, | ||
checkId, | ||
canaryId, | ||
playbookId | ||
}: FetchPermissionsInput) { | ||
if (componentId) { | ||
return `component_id=eq.${componentId}`; | ||
} | ||
if (personId) { | ||
return `person_id=eq.${personId}`; | ||
} | ||
if (teamId) { | ||
return `team_id=eq.${teamId}`; | ||
} | ||
if (configId) { | ||
return `config_id=eq.${configId}`; | ||
} | ||
if (checkId) { | ||
return `check_id=eq.${checkId}`; | ||
} | ||
if (canaryId) { | ||
return `canary_id=eq.${canaryId}`; | ||
} | ||
if (playbookId) { | ||
return `playbook_id=eq.${playbookId}`; | ||
} | ||
return undefined; | ||
} | ||
|
||
export function fetchPermissions( | ||
input: FetchPermissionsInput, | ||
pagination: { | ||
pageSize: number; | ||
pageIndex: number; | ||
} | ||
) { | ||
const queryParam = composeQueryParamForFetchPermissions(input); | ||
const selectFields = [ | ||
"*", | ||
"checks:check_id(id, name, status, type)", | ||
"catalog:config_id(id, name, type, config_class)", | ||
"component:component_id(id, name, icon)", | ||
"canary:canary_id(id, name, icon)", | ||
"playbook:playbook_id(id, title, name, icon)", | ||
"team:team_id(id, name, icon)", | ||
`person:person_id(${AVATAR_INFO})`, | ||
`createdBy:created_by(${AVATAR_INFO})` | ||
]; | ||
|
||
const { pageSize, pageIndex } = pagination; | ||
|
||
const url = `/permissions?${queryParam}&select=${selectFields.join(",")}&limit=${pageSize}&offset=${pageIndex * pageSize}`; | ||
return resolvePostGrestRequestWithPagination( | ||
IncidentCommander.get<PermissionAPIResponse[]>(url) | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import { ConfigItem } from "./configs"; | ||
import { HealthCheck } from "./health"; | ||
import { PlaybookSpec } from "./playbooks"; | ||
import { Topology } from "./topology"; | ||
import { Team, User } from "./users"; | ||
|
||
export type PermissionTable = { | ||
id: string; | ||
description: string; | ||
action: string; | ||
deny?: boolean; | ||
component_id?: string; | ||
config_id?: string; | ||
canary_id?: string; | ||
playbook_id?: string; | ||
created_by: string; | ||
person_id?: string; | ||
team_id?: string; | ||
updated_by: string; | ||
created_at: string; | ||
updated_at: string; | ||
until?: string; | ||
}; | ||
|
||
export type PermissionAPIResponse = PermissionTable & { | ||
checks: Pick<HealthCheck, "id" | "name" | "type" | "status">; | ||
catalog: Pick<ConfigItem, "id" | "name" | "type" | "config_class">; | ||
component: Pick<Topology, "id" | "name" | "icon">; | ||
canary: Pick<Topology, "id" | "name" | "icon">; | ||
playbook: Pick<PlaybookSpec, "id" | "name" | "icon" | "title">; | ||
team: Pick<Team, "id" | "name" | "icon">; | ||
person: User; | ||
createdBy: User; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { Icon } from "@flanksource-ui/ui/Icons/Icon"; | ||
import { Link } from "react-router-dom"; | ||
|
||
type CanaryLinkProps = { | ||
canary: { | ||
id: string; | ||
name: string; | ||
icon?: string; | ||
}; | ||
}; | ||
|
||
export default function CanaryLink({ canary }: CanaryLinkProps) { | ||
return ( | ||
<Link | ||
className="flex flex-row items-center gap-1" | ||
to={{ | ||
pathname: `/settings/canaries/${canary.id}` | ||
}} | ||
> | ||
{canary.icon && <Icon name={canary.icon} className="h-5" />} | ||
<span>{canary.name}</span> | ||
</Link> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
import { PermissionAPIResponse } from "@flanksource-ui/api/types/permissions"; | ||
import { Avatar } from "@flanksource-ui/ui/Avatar"; | ||
import { Badge } from "@flanksource-ui/ui/Badge/Badge"; | ||
import { MRTDateCell } from "@flanksource-ui/ui/MRTDataTable/Cells/MRTDateCells"; | ||
import MRTDataTable from "@flanksource-ui/ui/MRTDataTable/MRTDataTable"; | ||
import { MRT_ColumnDef } from "mantine-react-table"; | ||
import CanaryLink from "../Canary/CanaryLink"; | ||
import { CheckLink } from "../Canary/HealthChecks/CheckLink"; | ||
import ConfigLink from "../Configs/ConfigLink/ConfigLink"; | ||
import PlaybookSpecIcon from "../Playbooks/Settings/PlaybookSpecIcon"; | ||
import { TopologyLink } from "../Topology/TopologyLink"; | ||
|
||
const permissionsTableColumns: MRT_ColumnDef<PermissionAPIResponse>[] = [ | ||
{ | ||
id: "Resource", | ||
header: "Resource", | ||
Cell: ({ row }) => { | ||
const config = row.original.catalog; | ||
const check = row.original.checks; | ||
const playbook = row.original.playbook; | ||
const canary = row.original.canary; | ||
const component = row.original.component; | ||
|
||
return ( | ||
<div className="flex flex-col"> | ||
{config && <ConfigLink config={config} />} | ||
{check && <CheckLink check={check} />} | ||
{playbook && <PlaybookSpecIcon playbook={playbook} showLabel />} | ||
{canary && <CanaryLink canary={canary} />} | ||
{component && <TopologyLink topology={component} />} | ||
</div> | ||
); | ||
} | ||
}, | ||
{ | ||
id: "action", | ||
header: "Action", | ||
Cell: ({ row }) => { | ||
const action = row.original.action; | ||
const deny = row.original.deny; | ||
|
||
return ( | ||
<div> | ||
<span>{action}</span> | ||
{deny && <Badge text="deny" />} | ||
</div> | ||
); | ||
} | ||
}, | ||
{ | ||
id: "updated", | ||
header: "Updated", | ||
accessorFn: (row) => row.updated_at, | ||
Cell: MRTDateCell | ||
}, | ||
{ | ||
id: "created", | ||
header: "Created", | ||
accessorFn: (row) => row.created_at | ||
}, | ||
{ | ||
id: "createdBy", | ||
header: "Created By", | ||
Cell: ({ row }) => { | ||
const createdBy = row.original.createdBy; | ||
return <Avatar user={createdBy} />; | ||
} | ||
} | ||
]; | ||
|
||
type PermissionsTableProps = { | ||
permissions: PermissionAPIResponse[]; | ||
isLoading: boolean; | ||
pageCount: number; | ||
totalEntries: number; | ||
}; | ||
|
||
export default function PermissionsTable({ | ||
permissions, | ||
isLoading, | ||
pageCount, | ||
totalEntries | ||
}: PermissionsTableProps) { | ||
return ( | ||
<MRTDataTable<PermissionAPIResponse> | ||
columns={permissionsTableColumns} | ||
data={permissions} | ||
isLoading={isLoading} | ||
manualPageCount={pageCount} | ||
totalRowCount={totalEntries} | ||
enableServerSidePagination | ||
/> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import { | ||
fetchPermissions, | ||
FetchPermissionsInput | ||
} from "@flanksource-ui/api/services/permissions"; | ||
import useReactTablePaginationState from "@flanksource-ui/ui/DataTable/Hooks/useReactTablePaginationState"; | ||
import { useQuery } from "@tanstack/react-query"; | ||
import { useMemo } from "react"; | ||
import PermissionsTable from "./PermissionsTable"; | ||
|
||
type PermissionsViewProps = { | ||
permissionRequest: FetchPermissionsInput; | ||
}; | ||
|
||
export default function PermissionsView({ | ||
permissionRequest | ||
}: PermissionsViewProps) { | ||
const { pageSize, pageIndex } = useReactTablePaginationState(); | ||
|
||
const isEnabled = useMemo(() => { | ||
return Object.values(permissionRequest).some( | ||
(value) => value !== undefined | ||
); | ||
}, [permissionRequest]); | ||
|
||
const { isLoading, data } = useQuery({ | ||
queryKey: [ | ||
"permissions", | ||
permissionRequest, | ||
{ | ||
pageIndex, | ||
pageSize | ||
} | ||
], | ||
queryFn: () => | ||
fetchPermissions(permissionRequest, { | ||
pageIndex, | ||
pageSize | ||
}), | ||
enabled: isEnabled | ||
}); | ||
|
||
const totalEntries = data?.totalEntries || 0; | ||
const pageCount = totalEntries ? Math.ceil(totalEntries / pageSize) : -1; | ||
const permissions = data?.data || []; | ||
|
||
return ( | ||
<PermissionsTable | ||
permissions={permissions} | ||
isLoading={isLoading} | ||
pageCount={pageCount} | ||
totalEntries={totalEntries} | ||
/> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters