mirror of
https://github.com/fleetdm/fleet
synced 2026-05-23 08:58:41 +00:00
Fleet UI: Server side filtering for global, team, and inherited policies (#13479)
This commit is contained in:
parent
7d0a85bd0a
commit
8a796ff5bd
9 changed files with 373 additions and 96 deletions
|
|
@ -22,6 +22,10 @@ export interface IStoredPolicyResponse {
|
|||
policy: IPolicy;
|
||||
}
|
||||
|
||||
export interface IPoliciesCountResponse {
|
||||
count: number;
|
||||
}
|
||||
|
||||
export interface IPolicy {
|
||||
id: number;
|
||||
name: string;
|
||||
|
|
|
|||
|
|
@ -307,7 +307,7 @@ const DashboardPage = ({ router, location }: IDashboardProps): JSX.Element => {
|
|||
teamId: teamIdForApi,
|
||||
},
|
||||
],
|
||||
({ queryKey }) => softwareAPI.count(queryKey[0]),
|
||||
({ queryKey }) => softwareAPI.getCount(queryKey[0]),
|
||||
{
|
||||
enabled: isRouteOk && !software?.software,
|
||||
keepPreviousData: true,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import React, { useCallback, useContext, useEffect, useState } from "react";
|
|||
import { useQuery } from "react-query";
|
||||
import { InjectedRouter } from "react-router/lib/Router";
|
||||
import PATHS from "router/paths";
|
||||
import { noop, isEmpty } from "lodash";
|
||||
import { noop, isEqual } from "lodash";
|
||||
|
||||
import { getNextLocationPath } from "utilities/helpers";
|
||||
|
||||
|
|
@ -17,12 +17,19 @@ import {
|
|||
IPolicyStats,
|
||||
ILoadAllPoliciesResponse,
|
||||
ILoadTeamPoliciesResponse,
|
||||
IPoliciesCountResponse,
|
||||
} from "interfaces/policy";
|
||||
import { ITeamConfig } from "interfaces/team";
|
||||
|
||||
import configAPI from "services/entities/config";
|
||||
import globalPoliciesAPI from "services/entities/global_policies";
|
||||
import teamPoliciesAPI from "services/entities/team_policies";
|
||||
import globalPoliciesAPI, {
|
||||
IPoliciesCountQueryKey,
|
||||
IPoliciesQueryKey,
|
||||
} from "services/entities/global_policies";
|
||||
import teamPoliciesAPI, {
|
||||
ITeamPoliciesCountQueryKey,
|
||||
ITeamPoliciesQueryKey,
|
||||
} from "services/entities/team_policies";
|
||||
import teamsAPI, { ILoadTeamResponse } from "services/entities/teams";
|
||||
|
||||
import { ITableQueryData } from "components/TableContainer/TableContainer";
|
||||
|
|
@ -60,6 +67,10 @@ interface IManagePoliciesPageProps {
|
|||
};
|
||||
}
|
||||
|
||||
const DEFAULT_SORT_DIRECTION = "asc";
|
||||
const DEFAULT_PAGE_SIZE = 20;
|
||||
const DEFAULT_SORT_COLUMN = "name";
|
||||
|
||||
const baseClass = "manage-policies-page";
|
||||
|
||||
const ManagePolicyPage = ({
|
||||
|
|
@ -128,31 +139,41 @@ const ManagePolicyPage = ({
|
|||
// Functions to avoid race conditions
|
||||
const initialSearchQuery = (() => queryParams.query ?? "")();
|
||||
const initialSortHeader = (() =>
|
||||
(queryParams?.order_key as "name" | "failing_host_count") ?? "name")();
|
||||
(queryParams?.order_key as "name" | "failing_host_count") ??
|
||||
DEFAULT_SORT_COLUMN)();
|
||||
const initialSortDirection = (() =>
|
||||
(queryParams?.order_direction as "asc" | "desc") ?? "asc")();
|
||||
(queryParams?.order_direction as "asc" | "desc") ??
|
||||
DEFAULT_SORT_DIRECTION)();
|
||||
const initialPage = (() =>
|
||||
queryParams && queryParams.page ? parseInt(queryParams?.page, 10) : 0)();
|
||||
const initialShowInheritedTable = (() =>
|
||||
queryParams && queryParams.inherited_table === "true")();
|
||||
const initialInheritedSortHeader = (() =>
|
||||
(queryParams?.inherited_order_key as "name" | "failing_host_count") ??
|
||||
"name")();
|
||||
DEFAULT_SORT_COLUMN)();
|
||||
const initialInheritedSortDirection = (() =>
|
||||
(queryParams?.inherited_order_direction as "asc" | "desc") ?? "asc")();
|
||||
(queryParams?.inherited_order_direction as "asc" | "desc") ??
|
||||
DEFAULT_SORT_DIRECTION)();
|
||||
const initialInheritedPage = (() =>
|
||||
queryParams && queryParams.inherited_page
|
||||
? parseInt(queryParams?.inherited_page, 10)
|
||||
: 0)();
|
||||
|
||||
const page = initialPage;
|
||||
const showInheritedTable = initialShowInheritedTable;
|
||||
const inheritedPage = initialInheritedPage;
|
||||
const searchQuery = initialSearchQuery;
|
||||
|
||||
// Needs update on location change or table state might not match URL
|
||||
const [searchQuery, setSearchQuery] = useState(initialSearchQuery);
|
||||
const [page, setPage] = useState(initialPage);
|
||||
const [inheritedPage, setInheritedPage] = useState(initialInheritedPage);
|
||||
const [tableQueryData, setTableQueryData] = useState<ITableQueryData>();
|
||||
const [
|
||||
inheritedTableQueryData,
|
||||
setInheritedTableQueryData,
|
||||
] = useState<ITableQueryData>();
|
||||
const [sortHeader, setSortHeader] = useState(initialSortHeader);
|
||||
const [sortDirection, setSortDirection] = useState(initialSortDirection);
|
||||
const [sortDirection, setSortDirection] = useState<
|
||||
"asc" | "desc" | undefined
|
||||
>(initialSortDirection);
|
||||
const [inheritedSortDirection, setInheritedSortDirection] = useState(
|
||||
initialInheritedSortDirection
|
||||
);
|
||||
|
|
@ -168,8 +189,11 @@ const ManagePolicyPage = ({
|
|||
if (!isRouteOk) {
|
||||
return;
|
||||
}
|
||||
setPage(initialPage);
|
||||
setSearchQuery(initialSearchQuery);
|
||||
setSortHeader(initialSortHeader);
|
||||
setSortDirection(initialSortDirection);
|
||||
setInheritedPage(initialInheritedPage);
|
||||
setInheritedSortHeader(initialInheritedSortHeader);
|
||||
setInheritedSortDirection(initialInheritedSortDirection);
|
||||
}, [location, isRouteOk]);
|
||||
|
|
@ -195,10 +219,24 @@ const ManagePolicyPage = ({
|
|||
error: globalPoliciesError,
|
||||
isFetching: isFetchingGlobalPolicies,
|
||||
refetch: refetchGlobalPolicies,
|
||||
} = useQuery<ILoadAllPoliciesResponse, Error, IPolicyStats[]>(
|
||||
["globalPolicies", teamIdForApi],
|
||||
() => {
|
||||
return globalPoliciesAPI.loadAll();
|
||||
} = useQuery<
|
||||
ILoadAllPoliciesResponse,
|
||||
Error,
|
||||
IPolicyStats[],
|
||||
IPoliciesQueryKey[]
|
||||
>(
|
||||
[
|
||||
{
|
||||
scope: "globalPolicies",
|
||||
page: tableQueryData?.pageIndex,
|
||||
perPage: DEFAULT_PAGE_SIZE,
|
||||
query: searchQuery,
|
||||
orderDirection: sortDirection,
|
||||
orderKey: sortHeader,
|
||||
},
|
||||
],
|
||||
({ queryKey }) => {
|
||||
return globalPoliciesAPI.loadAllNew(queryKey[0]);
|
||||
},
|
||||
{
|
||||
enabled: isRouteOk,
|
||||
|
|
@ -207,13 +245,55 @@ const ManagePolicyPage = ({
|
|||
}
|
||||
);
|
||||
|
||||
const {
|
||||
data: globalPoliciesCount,
|
||||
|
||||
isFetching: isFetchingGlobalCount,
|
||||
} = useQuery<IPoliciesCountResponse, Error, number, IPoliciesCountQueryKey[]>(
|
||||
[
|
||||
{
|
||||
scope: "policiesCount",
|
||||
query: isAnyTeamSelected ? "" : searchQuery, // Search query not used for inherited count
|
||||
},
|
||||
],
|
||||
({ queryKey }) => globalPoliciesAPI.getCount(queryKey[0]),
|
||||
{
|
||||
enabled: isRouteOk,
|
||||
keepPreviousData: true,
|
||||
refetchOnWindowFocus: false,
|
||||
retry: 1,
|
||||
select: (data) => data.count,
|
||||
}
|
||||
);
|
||||
|
||||
const {
|
||||
error: teamPoliciesError,
|
||||
isFetching: isFetchingTeamPolicies,
|
||||
refetch: refetchTeamPolicies,
|
||||
} = useQuery<ILoadTeamPoliciesResponse, Error, ILoadTeamPoliciesResponse>(
|
||||
["teamPolicies", teamIdForApi],
|
||||
() => teamPoliciesAPI.loadAll(teamIdForApi),
|
||||
} = useQuery<
|
||||
ILoadTeamPoliciesResponse,
|
||||
Error,
|
||||
ILoadTeamPoliciesResponse,
|
||||
ITeamPoliciesQueryKey[]
|
||||
>(
|
||||
[
|
||||
{
|
||||
scope: "teamPolicies",
|
||||
page: tableQueryData?.pageIndex,
|
||||
perPage: DEFAULT_PAGE_SIZE,
|
||||
query: searchQuery,
|
||||
orderDirection: sortDirection,
|
||||
orderKey: sortHeader,
|
||||
inheritedPage: inheritedTableQueryData?.pageIndex,
|
||||
inheritedPerPage: DEFAULT_PAGE_SIZE,
|
||||
inheritedOrderDirection: inheritedSortDirection,
|
||||
inheritedOrderKey: inheritedSortHeader,
|
||||
teamId: teamIdForApi || 0,
|
||||
},
|
||||
],
|
||||
({ queryKey }) => {
|
||||
return teamPoliciesAPI.loadAllNew(queryKey[0]);
|
||||
},
|
||||
{
|
||||
enabled: isRouteOk && isPremiumTier && !!teamIdForApi,
|
||||
onSuccess: (data) => {
|
||||
|
|
@ -223,9 +303,32 @@ const ManagePolicyPage = ({
|
|||
}
|
||||
);
|
||||
|
||||
const canAddOrDeletePolicy =
|
||||
const { data: teamPoliciesCount, isFetching: isFetchingTeamCount } = useQuery<
|
||||
IPoliciesCountResponse,
|
||||
Error,
|
||||
number,
|
||||
ITeamPoliciesCountQueryKey[]
|
||||
>(
|
||||
[
|
||||
{
|
||||
scope: "teamPoliciesCount",
|
||||
query: searchQuery,
|
||||
teamId: teamIdForApi || 0, // TODO: Fix number/undefined type
|
||||
},
|
||||
],
|
||||
({ queryKey }) => teamPoliciesAPI.getCount(queryKey[0]),
|
||||
{
|
||||
enabled: isRouteOk && !!teamIdForApi,
|
||||
keepPreviousData: true,
|
||||
refetchOnWindowFocus: false,
|
||||
retry: 1,
|
||||
select: (data) => data.count,
|
||||
}
|
||||
);
|
||||
|
||||
const canAddOrDeletePolicy: boolean =
|
||||
isGlobalAdmin || isGlobalMaintainer || isTeamMaintainer || isTeamAdmin;
|
||||
const canManageAutomations = isGlobalAdmin || isTeamAdmin;
|
||||
const canManageAutomations: boolean = isGlobalAdmin || isTeamAdmin;
|
||||
|
||||
const {
|
||||
data: config,
|
||||
|
|
@ -281,6 +384,14 @@ const ManagePolicyPage = ({
|
|||
// Inherited table uses the same onQueryChange function but routes to different URL params
|
||||
const onQueryChange = useCallback(
|
||||
async (newTableQuery: ITableQueryData) => {
|
||||
if (!isRouteOk || isEqual(newTableQuery, tableQueryData)) {
|
||||
return;
|
||||
}
|
||||
|
||||
newTableQuery.editingInheritedTable
|
||||
? setInheritedTableQueryData({ ...newTableQuery })
|
||||
: setTableQueryData({ ...newTableQuery });
|
||||
|
||||
const {
|
||||
pageIndex: newPageIndex,
|
||||
searchQuery: newSearchQuery,
|
||||
|
|
@ -359,48 +470,6 @@ const ManagePolicyPage = ({
|
|||
] // Other dependencies can cause infinite re-renders as URL is source of truth
|
||||
);
|
||||
|
||||
const onClientSidePaginationChange = useCallback(
|
||||
(pageIndex: number) => {
|
||||
const locationPath = getNextLocationPath({
|
||||
pathPrefix: PATHS.MANAGE_POLICIES,
|
||||
queryParams: {
|
||||
...queryParams,
|
||||
page: pageIndex,
|
||||
query: searchQuery,
|
||||
order_direction: sortDirection,
|
||||
order_key: sortHeader,
|
||||
inherited_order_direction: inheritedSortDirection,
|
||||
inherited_order_key: inheritedSortHeader,
|
||||
inherited_page: inheritedPage,
|
||||
},
|
||||
});
|
||||
|
||||
router?.replace(locationPath);
|
||||
},
|
||||
[searchQuery, queryParams, sortHeader, sortDirection] // Dependencies required for correct variable state
|
||||
);
|
||||
|
||||
const onClientSideInheritedPaginationChange = useCallback(
|
||||
(pageIndex: number) => {
|
||||
const locationPath = getNextLocationPath({
|
||||
pathPrefix: PATHS.MANAGE_POLICIES,
|
||||
queryParams: {
|
||||
...queryParams,
|
||||
inherited_table: "true",
|
||||
inherited_page: pageIndex,
|
||||
query: searchQuery,
|
||||
page,
|
||||
order_direction: sortDirection,
|
||||
order_key: sortHeader,
|
||||
inherited_order_direction: inheritedSortDirection,
|
||||
inherited_order_key: inheritedSortHeader,
|
||||
},
|
||||
});
|
||||
router?.replace(locationPath);
|
||||
},
|
||||
[queryParams, inheritedSortHeader, inheritedSortDirection] // Dependencies required for correct variable state
|
||||
);
|
||||
|
||||
const toggleManageAutomationsModal = () =>
|
||||
setShowManageAutomationsModal(!showManageAutomationsModal);
|
||||
|
||||
|
|
@ -541,6 +610,16 @@ const ManagePolicyPage = ({
|
|||
}
|
||||
}
|
||||
|
||||
const renderPoliciesCount = (count?: number) => {
|
||||
return (
|
||||
<div className={`${baseClass}__count`}>
|
||||
{count !== undefined && (
|
||||
<span>{`${count} polic${count === 1 ? "y" : "ies"}`}</span>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
return !isRouteOk || (isPremiumTier && !userTeams) ? (
|
||||
<Spinner />
|
||||
) : (
|
||||
|
|
@ -628,6 +707,9 @@ const ManagePolicyPage = ({
|
|||
canAddOrDeletePolicy={canAddOrDeletePolicy}
|
||||
currentTeam={currentTeamSummary}
|
||||
currentAutomatedPolicies={currentAutomatedPolicies}
|
||||
renderPoliciesCount={() =>
|
||||
!isFetchingTeamCount && renderPoliciesCount(teamPoliciesCount)
|
||||
}
|
||||
isPremiumTier={isPremiumTier}
|
||||
isSandboxMode={isSandboxMode}
|
||||
searchQuery={searchQuery}
|
||||
|
|
@ -653,7 +735,11 @@ const ManagePolicyPage = ({
|
|||
currentAutomatedPolicies={currentAutomatedPolicies}
|
||||
isPremiumTier={isPremiumTier}
|
||||
isSandboxMode={isSandboxMode}
|
||||
onClientSidePaginationChange={onClientSidePaginationChange}
|
||||
// onClientSidePaginationChange={onClientSidePaginationChange}
|
||||
renderPoliciesCount={() =>
|
||||
!isFetchingGlobalCount &&
|
||||
renderPoliciesCount(globalPoliciesCount)
|
||||
}
|
||||
searchQuery={searchQuery}
|
||||
sortHeader={sortHeader}
|
||||
sortDirection={sortDirection}
|
||||
|
|
@ -662,25 +748,27 @@ const ManagePolicyPage = ({
|
|||
/>
|
||||
))}
|
||||
</div>
|
||||
{showInheritedPoliciesButton && globalPolicies && (
|
||||
<RevealButton
|
||||
isShowing={showInheritedTable}
|
||||
className={baseClass}
|
||||
hideText={inheritedPoliciesButtonText(
|
||||
showInheritedTable,
|
||||
globalPolicies.length
|
||||
)}
|
||||
showText={inheritedPoliciesButtonText(
|
||||
showInheritedTable,
|
||||
globalPolicies.length
|
||||
)}
|
||||
caretPosition={"before"}
|
||||
tooltipHtml={
|
||||
'"All teams" policies are checked <br/> for this team’s hosts.'
|
||||
}
|
||||
onClick={toggleShowInheritedPolicies}
|
||||
/>
|
||||
)}
|
||||
{showInheritedPoliciesButton &&
|
||||
globalPolicies &&
|
||||
globalPoliciesCount && (
|
||||
<RevealButton
|
||||
isShowing={showInheritedTable}
|
||||
className={baseClass}
|
||||
hideText={inheritedPoliciesButtonText(
|
||||
showInheritedTable,
|
||||
globalPoliciesCount
|
||||
)}
|
||||
showText={inheritedPoliciesButtonText(
|
||||
showInheritedTable,
|
||||
globalPoliciesCount
|
||||
)}
|
||||
caretPosition={"before"}
|
||||
tooltipHtml={
|
||||
'"All teams" policies are checked <br/> for this team’s hosts.'
|
||||
}
|
||||
onClick={toggleShowInheritedPolicies}
|
||||
/>
|
||||
)}
|
||||
{showInheritedPoliciesButton && showInheritedTable && (
|
||||
<div className={`${baseClass}__inherited-policies-table`}>
|
||||
{globalPoliciesError && <TableDataError />}
|
||||
|
|
@ -696,8 +784,11 @@ const ManagePolicyPage = ({
|
|||
tableType="inheritedPolicies"
|
||||
currentTeam={currentTeamSummary}
|
||||
searchQuery=""
|
||||
onClientSidePaginationChange={
|
||||
onClientSideInheritedPaginationChange
|
||||
// onClientSidePaginationChange={
|
||||
// onClientSideInheritedPaginationChange
|
||||
// }
|
||||
renderPoliciesCount={() =>
|
||||
renderPoliciesCount(teamPoliciesCount)
|
||||
}
|
||||
sortHeader={inheritedSortHeader}
|
||||
sortDirection={inheritedSortDirection}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ describe("Policies table", () => {
|
|||
searchQuery=""
|
||||
page={0}
|
||||
onQueryChange={noop}
|
||||
renderPoliciesCount={noop}
|
||||
/>
|
||||
);
|
||||
|
||||
|
|
@ -47,6 +48,7 @@ describe("Policies table", () => {
|
|||
searchQuery=""
|
||||
page={0}
|
||||
onQueryChange={noop}
|
||||
renderPoliciesCount={noop}
|
||||
/>
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,8 @@ interface IPoliciesTableProps {
|
|||
currentAutomatedPolicies?: number[];
|
||||
isPremiumTier?: boolean;
|
||||
isSandboxMode?: boolean;
|
||||
onClientSidePaginationChange?: (pageIndex: number) => void;
|
||||
// onClientSidePaginationChange?: (pageIndex: number) => void;
|
||||
renderPoliciesCount: any; // TODO: typing
|
||||
onQueryChange: (newTableQuery: ITableQueryData) => void;
|
||||
searchQuery: string;
|
||||
sortHeader?: "name" | "failing_host_count";
|
||||
|
|
@ -55,7 +56,8 @@ const PoliciesTable = ({
|
|||
isPremiumTier,
|
||||
isSandboxMode,
|
||||
onQueryChange,
|
||||
onClientSidePaginationChange,
|
||||
// onClientSidePaginationChange,
|
||||
renderPoliciesCount,
|
||||
searchQuery,
|
||||
sortHeader,
|
||||
sortDirection,
|
||||
|
|
@ -154,7 +156,7 @@ const PoliciesTable = ({
|
|||
currentAutomatedPolicies,
|
||||
config?.update_interval.osquery_policy
|
||||
)}
|
||||
filters={{ global: searchQuery }}
|
||||
// filters={{ global: searchQuery }}
|
||||
isLoading={isLoading}
|
||||
defaultSortHeader={sortHeader || DEFAULT_SORT_HEADER}
|
||||
defaultSortDirection={sortDirection || DEFAULT_SORT_DIRECTION}
|
||||
|
|
@ -179,10 +181,11 @@ const PoliciesTable = ({
|
|||
})
|
||||
}
|
||||
disableCount={tableType === "inheritedPolicies"}
|
||||
isClientSidePagination
|
||||
onClientSidePaginationChange={onClientSidePaginationChange}
|
||||
isClientSideFilter
|
||||
searchQueryColumn="name"
|
||||
renderCount={renderPoliciesCount}
|
||||
// isClientSidePagination
|
||||
// onClientSidePaginationChange={onClientSidePaginationChange}
|
||||
// isClientSideFilter
|
||||
// searchQueryColumn="name"
|
||||
onQueryChange={onTableQueryChange}
|
||||
inputPlaceHolder="Search by name"
|
||||
searchable={searchable}
|
||||
|
|
|
|||
|
|
@ -327,7 +327,7 @@ const ManageSoftwarePage = ({
|
|||
teamId: teamIdForApi,
|
||||
},
|
||||
],
|
||||
({ queryKey }) => softwareAPI.count(queryKey[0]),
|
||||
({ queryKey }) => softwareAPI.getCount(queryKey[0]),
|
||||
{
|
||||
enabled: isRouteOk && isSoftwareConfigLoaded,
|
||||
keepPreviousData: true,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,45 @@
|
|||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import { snakeCase, reduce } from "lodash";
|
||||
|
||||
import sendRequest from "services";
|
||||
import endpoints from "utilities/endpoints";
|
||||
import { IPolicyFormData, ILoadAllPoliciesResponse } from "interfaces/policy";
|
||||
import {
|
||||
IPolicyFormData,
|
||||
ILoadAllPoliciesResponse,
|
||||
IPoliciesCountResponse,
|
||||
} from "interfaces/policy";
|
||||
import { buildQueryStringFromParams, QueryParams } from "utilities/url";
|
||||
|
||||
interface IPoliciesApiParams {
|
||||
page?: number;
|
||||
perPage?: number;
|
||||
orderKey?: string;
|
||||
orderDirection?: "asc" | "desc";
|
||||
query?: string;
|
||||
}
|
||||
|
||||
export interface IPoliciesQueryKey extends IPoliciesApiParams {
|
||||
scope: "globalPolicies";
|
||||
}
|
||||
|
||||
export interface IPoliciesCountQueryKey
|
||||
extends Pick<IPoliciesApiParams, "query"> {
|
||||
scope: "policiesCount";
|
||||
}
|
||||
|
||||
const ORDER_KEY = "name";
|
||||
const ORDER_DIRECTION = "asc";
|
||||
|
||||
const convertParamsToSnakeCase = (params: IPoliciesApiParams) => {
|
||||
return reduce<typeof params, QueryParams>(
|
||||
params,
|
||||
(result, val, key) => {
|
||||
result[snakeCase(key)] = val;
|
||||
return result;
|
||||
},
|
||||
{}
|
||||
);
|
||||
};
|
||||
|
||||
export default {
|
||||
// TODO: How does the frontend need to support legacy policies?
|
||||
|
|
@ -33,4 +71,40 @@ export default {
|
|||
|
||||
return sendRequest("GET", GLOBAL_POLICIES);
|
||||
},
|
||||
loadAllNew: async ({
|
||||
page,
|
||||
perPage,
|
||||
orderKey = ORDER_KEY,
|
||||
orderDirection: orderDir = ORDER_DIRECTION,
|
||||
query,
|
||||
}: IPoliciesApiParams): Promise<ILoadAllPoliciesResponse> => {
|
||||
const { GLOBAL_POLICIES } = endpoints;
|
||||
|
||||
const queryParams = {
|
||||
page,
|
||||
perPage,
|
||||
orderKey,
|
||||
orderDirection: orderDir,
|
||||
query,
|
||||
};
|
||||
|
||||
const snakeCaseParams = convertParamsToSnakeCase(queryParams);
|
||||
const queryString = buildQueryStringFromParams(snakeCaseParams);
|
||||
const path = `${GLOBAL_POLICIES}?${queryString}`;
|
||||
|
||||
return sendRequest("GET", path);
|
||||
},
|
||||
getCount: async ({
|
||||
query,
|
||||
}: Pick<IPoliciesApiParams, "query">): Promise<IPoliciesCountResponse> => {
|
||||
const { GLOBAL_POLICIES } = endpoints;
|
||||
const path = `${GLOBAL_POLICIES}/count`;
|
||||
const queryParams = {
|
||||
query,
|
||||
};
|
||||
const snakeCaseParams = convertParamsToSnakeCase(queryParams);
|
||||
const queryString = buildQueryStringFromParams(snakeCaseParams);
|
||||
|
||||
return sendRequest("GET", path.concat(`?${queryString}`));
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ export default {
|
|||
}
|
||||
},
|
||||
|
||||
count: async ({
|
||||
getCount: async ({
|
||||
query,
|
||||
teamId,
|
||||
vulnerable,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,59 @@
|
|||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import { snakeCase, reduce } from "lodash";
|
||||
|
||||
import sendRequest from "services";
|
||||
import endpoints from "utilities/endpoints";
|
||||
import { ILoadTeamPoliciesResponse, IPolicyFormData } from "interfaces/policy";
|
||||
import {
|
||||
ILoadTeamPoliciesResponse,
|
||||
IPolicyFormData,
|
||||
IPoliciesCountResponse,
|
||||
} from "interfaces/policy";
|
||||
import { API_NO_TEAM_ID } from "interfaces/team";
|
||||
import { buildQueryStringFromParams, QueryParams } from "utilities/url";
|
||||
|
||||
interface IPoliciesApiQueryParams {
|
||||
page?: number;
|
||||
perPage?: number;
|
||||
orderKey?: string;
|
||||
orderDirection?: "asc" | "desc";
|
||||
query?: string;
|
||||
inheritedPage?: number;
|
||||
inheritedPerPage?: number;
|
||||
inheritedOrderKey?: string;
|
||||
inheritedOrderDirection?: "asc" | "desc";
|
||||
}
|
||||
|
||||
export interface IPoliciesApiParams extends IPoliciesApiQueryParams {
|
||||
teamId: number;
|
||||
}
|
||||
|
||||
export interface ITeamPoliciesQueryKey extends IPoliciesApiParams {
|
||||
scope: "teamPolicies";
|
||||
}
|
||||
|
||||
export interface ITeamPoliciesCountQueryKey
|
||||
extends Pick<IPoliciesApiParams, "query" | "teamId"> {
|
||||
scope: "teamPoliciesCount";
|
||||
}
|
||||
|
||||
interface IPoliciesCountApiParams {
|
||||
teamId: number;
|
||||
query?: string;
|
||||
}
|
||||
|
||||
const ORDER_KEY = "name";
|
||||
const ORDER_DIRECTION = "asc";
|
||||
|
||||
const convertParamsToSnakeCase = (params: IPoliciesApiQueryParams) => {
|
||||
return reduce<typeof params, QueryParams>(
|
||||
params,
|
||||
(result, val, key) => {
|
||||
result[snakeCase(key)] = val;
|
||||
return result;
|
||||
},
|
||||
{}
|
||||
);
|
||||
};
|
||||
|
||||
export default {
|
||||
create: (data: IPolicyFormData) => {
|
||||
|
|
@ -77,4 +128,56 @@ export default {
|
|||
|
||||
return sendRequest("GET", path);
|
||||
},
|
||||
loadAllNew: async ({
|
||||
teamId,
|
||||
page,
|
||||
perPage,
|
||||
orderKey = ORDER_KEY,
|
||||
orderDirection: orderDir = ORDER_DIRECTION,
|
||||
query,
|
||||
inheritedPage,
|
||||
inheritedPerPage,
|
||||
inheritedOrderKey = ORDER_KEY,
|
||||
inheritedOrderDirection: inheritedOrderDir = ORDER_DIRECTION,
|
||||
}: IPoliciesApiParams): Promise<ILoadTeamPoliciesResponse> => {
|
||||
const { TEAMS } = endpoints;
|
||||
|
||||
const queryParams = {
|
||||
page,
|
||||
perPage,
|
||||
orderKey,
|
||||
orderDirection: orderDir,
|
||||
query,
|
||||
inheritedPage,
|
||||
inheritedPerPage,
|
||||
inheritedOrderKey,
|
||||
inheritedOrderDirection: inheritedOrderDir,
|
||||
};
|
||||
|
||||
const snakeCaseParams = convertParamsToSnakeCase(queryParams);
|
||||
const queryString = buildQueryStringFromParams(snakeCaseParams);
|
||||
const path = `${TEAMS}/${teamId}/policies?${queryString}`;
|
||||
if (!teamId) {
|
||||
throw new Error("Invalid team id");
|
||||
}
|
||||
|
||||
return sendRequest("GET", path);
|
||||
},
|
||||
getCount: async ({
|
||||
query,
|
||||
teamId,
|
||||
}: Pick<
|
||||
IPoliciesCountApiParams,
|
||||
"query" | "teamId"
|
||||
>): Promise<IPoliciesCountResponse> => {
|
||||
const { TEAM_POLICIES } = endpoints;
|
||||
const path = `${TEAM_POLICIES(teamId)}/count`;
|
||||
const queryParams = {
|
||||
query,
|
||||
};
|
||||
const snakeCaseParams = convertParamsToSnakeCase(queryParams);
|
||||
const queryString = buildQueryStringFromParams(snakeCaseParams);
|
||||
|
||||
return sendRequest("GET", path.concat(`?${queryString}`));
|
||||
},
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue