mirror of
https://github.com/fleetdm/fleet
synced 2026-05-23 17:08:53 +00:00
fix single row click issue and pagination (#26644)
For #25464 quick fix for clicking rows and adding errors and pagination to UI
This commit is contained in:
parent
ecaea6104d
commit
7af26ea140
4 changed files with 126 additions and 40 deletions
|
|
@ -6,7 +6,9 @@ import { Tab, Tabs, TabList, TabPanel } from "react-tabs";
|
|||
import { pick, findIndex } from "lodash";
|
||||
|
||||
import { NotificationContext } from "context/notification";
|
||||
import deviceUserAPI from "services/entities/device_user";
|
||||
import deviceUserAPI, {
|
||||
IGetDeviceCertificatesResponse,
|
||||
} from "services/entities/device_user";
|
||||
import diskEncryptionAPI from "services/entities/disk_encryption";
|
||||
import {
|
||||
IDeviceMappingResponse,
|
||||
|
|
@ -75,7 +77,7 @@ const FREE_TAB_PATHS = [
|
|||
PATHS.DEVICE_USER_DETAILS_SOFTWARE,
|
||||
] as const;
|
||||
|
||||
const DEFAULT_CERTIFICATES_PAGE_SIZE = 500;
|
||||
const DEFAULT_CERTIFICATES_PAGE_SIZE = 10;
|
||||
const DEFAULT_CERTIFICATES_PAGE = 0;
|
||||
|
||||
interface IDeviceUserPageProps {
|
||||
|
|
@ -125,10 +127,15 @@ const DeviceUserPage = ({
|
|||
selectedSoftwareDetails,
|
||||
setSelectedSoftwareDetails,
|
||||
] = useState<IHostSoftware | null>(null);
|
||||
|
||||
// certificates states
|
||||
const [
|
||||
selectedCertificate,
|
||||
setSelectedCertificate,
|
||||
] = useState<IHostCertificate | null>(null);
|
||||
const [certificatePage, setCertificatePage] = useState(
|
||||
DEFAULT_CERTIFICATES_PAGE
|
||||
);
|
||||
|
||||
const { data: deviceMapping, refetch: refetchDeviceMapping } = useQuery(
|
||||
["deviceMapping", deviceAuthToken],
|
||||
|
|
@ -162,14 +169,22 @@ const DeviceUserPage = ({
|
|||
isLoading: isLoadingDeviceCertificates,
|
||||
isError: isErrorDeviceCertificates,
|
||||
refetch: refetchDeviceCertificates,
|
||||
} = useQuery(
|
||||
["hostCertificates", deviceAuthToken],
|
||||
() =>
|
||||
deviceUserAPI.getDeviceCertificates(
|
||||
deviceAuthToken,
|
||||
DEFAULT_CERTIFICATES_PAGE,
|
||||
DEFAULT_CERTIFICATES_PAGE_SIZE
|
||||
),
|
||||
} = useQuery<
|
||||
IGetDeviceCertificatesResponse,
|
||||
Error,
|
||||
IGetDeviceCertificatesResponse,
|
||||
Array<{ scope: string; token: string; page: number; perPage: number }>
|
||||
>(
|
||||
[
|
||||
{
|
||||
scope: "device-certificates",
|
||||
token: deviceAuthToken,
|
||||
page: certificatePage,
|
||||
perPage: DEFAULT_CERTIFICATES_PAGE_SIZE,
|
||||
},
|
||||
],
|
||||
({ queryKey: [{ token, page, perPage }] }) =>
|
||||
deviceUserAPI.getDeviceCertificates(token, page, perPage),
|
||||
{
|
||||
...DEFAULT_USE_QUERY_OPTIONS,
|
||||
// FIXME: is it worth disabling for unsupported platforms? we'd have to workaround the a
|
||||
|
|
@ -462,8 +477,15 @@ const DeviceUserPage = ({
|
|||
<CertificatesCard
|
||||
isMyDevicePage
|
||||
data={deviceCertificates}
|
||||
isError={isErrorDeviceCertificates}
|
||||
page={certificatePage}
|
||||
pageSize={DEFAULT_CERTIFICATES_PAGE_SIZE}
|
||||
hostPlatform={host.platform}
|
||||
onSelectCertificate={onSelectCertificate}
|
||||
onNextPage={() => setCertificatePage(certificatePage + 1)}
|
||||
onPreviousPage={() =>
|
||||
setCertificatePage(certificatePage - 1)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</TabPanel>
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ interface IHostDetailsSubNavItem {
|
|||
}
|
||||
|
||||
const DEFAULT_ACTIVITY_PAGE_SIZE = 8;
|
||||
const DEFAULT_CERTIFICATES_PAGE_SIZE = 500;
|
||||
const DEFAULT_CERTIFICATES_PAGE_SIZE = 10;
|
||||
const DEFAULT_CERTIFICATES_PAGE = 0;
|
||||
|
||||
const HostDetailsPage = ({
|
||||
|
|
@ -208,10 +208,6 @@ const HostDetailsPage = ({
|
|||
selectedCancelActivity,
|
||||
setSelectedCancelActivity,
|
||||
] = useState<IHostUpcomingActivity | null>(null);
|
||||
const [
|
||||
selectedCertificate,
|
||||
setSelectedCertificate,
|
||||
] = useState<IHostCertificate | null>(null);
|
||||
|
||||
// activity states
|
||||
const [activeActivityTab, setActiveActivityTab] = useState<
|
||||
|
|
@ -219,6 +215,15 @@ const HostDetailsPage = ({
|
|||
>("past");
|
||||
const [activityPage, setActivityPage] = useState(0);
|
||||
|
||||
// certificates states
|
||||
const [
|
||||
selectedCertificate,
|
||||
setSelectedCertificate,
|
||||
] = useState<IHostCertificate | null>(null);
|
||||
const [certificatePage, setCertificatePage] = useState(
|
||||
DEFAULT_CERTIFICATES_PAGE
|
||||
);
|
||||
|
||||
const { data: teams } = useQuery<ILoadTeamsResponse, Error, ITeam[]>(
|
||||
"teams",
|
||||
() => teamAPI.loadAll(),
|
||||
|
|
@ -282,20 +287,19 @@ const HostDetailsPage = ({
|
|||
} = useQuery<
|
||||
IGetHostCertificatesResponse,
|
||||
Error,
|
||||
IGetHostCertificatesResponse
|
||||
IGetHostCertificatesResponse,
|
||||
Array<{ scope: string; hostId: number; page: number; perPage: number }>
|
||||
>(
|
||||
[
|
||||
"host-certificates",
|
||||
host_id,
|
||||
DEFAULT_CERTIFICATES_PAGE,
|
||||
DEFAULT_CERTIFICATES_PAGE_SIZE,
|
||||
{
|
||||
scope: "host-certificates",
|
||||
hostId: hostIdFromURL,
|
||||
page: certificatePage,
|
||||
perPage: DEFAULT_CERTIFICATES_PAGE_SIZE,
|
||||
},
|
||||
],
|
||||
() =>
|
||||
hostAPI.getHostCertificates(
|
||||
hostIdFromURL,
|
||||
DEFAULT_CERTIFICATES_PAGE,
|
||||
DEFAULT_CERTIFICATES_PAGE_SIZE
|
||||
),
|
||||
({ queryKey: [{ hostId, page, perPage }] }) =>
|
||||
hostAPI.getHostCertificates(hostId, page, perPage),
|
||||
{
|
||||
...DEFAULT_USE_QUERY_OPTIONS,
|
||||
// FIXME: is it worth disabling for unsupported platforms? we'd have to workaround the a
|
||||
|
|
@ -963,6 +967,13 @@ const HostDetailsPage = ({
|
|||
data={hostCertificates}
|
||||
hostPlatform={host.platform}
|
||||
onSelectCertificate={onSelectCertificate}
|
||||
isError={isErrorHostCertificates}
|
||||
page={certificatePage}
|
||||
pageSize={DEFAULT_CERTIFICATES_PAGE_SIZE}
|
||||
onNextPage={() => setCertificatePage(certificatePage + 1)}
|
||||
onPreviousPage={() =>
|
||||
setCertificatePage(certificatePage - 1)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</TabPanel>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { HostPlatform } from "interfaces/platform";
|
|||
import { IGetHostCertificatesResponse } from "services/entities/hosts";
|
||||
|
||||
import Card from "components/Card";
|
||||
import DataError from "components/DataError";
|
||||
|
||||
import CertificatesTable from "./CertificatesTable";
|
||||
|
||||
|
|
@ -13,16 +14,42 @@ const baseClass = "certificates-card";
|
|||
interface ICertificatesProps {
|
||||
data: IGetHostCertificatesResponse;
|
||||
hostPlatform: HostPlatform;
|
||||
page: number;
|
||||
pageSize: number;
|
||||
isError: boolean;
|
||||
isMyDevicePage?: boolean;
|
||||
onSelectCertificate: (certificate: IHostCertificate) => void;
|
||||
onNextPage: () => void;
|
||||
onPreviousPage: () => void;
|
||||
}
|
||||
|
||||
const CertificatesCard = ({
|
||||
data,
|
||||
hostPlatform,
|
||||
isError,
|
||||
page,
|
||||
pageSize,
|
||||
isMyDevicePage = false,
|
||||
onSelectCertificate,
|
||||
onNextPage,
|
||||
onPreviousPage,
|
||||
}: ICertificatesProps) => {
|
||||
const renderContent = () => {
|
||||
if (isError) return <DataError />;
|
||||
|
||||
return (
|
||||
<CertificatesTable
|
||||
data={data}
|
||||
showHelpText={!isMyDevicePage && hostPlatform === "darwin"}
|
||||
page={page}
|
||||
pageSize={pageSize}
|
||||
onSelectCertificate={onSelectCertificate}
|
||||
onNextPage={onNextPage}
|
||||
onPreviousPage={onPreviousPage}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Card
|
||||
className={baseClass}
|
||||
|
|
@ -31,11 +58,7 @@ const CertificatesCard = ({
|
|||
paddingSize="xxlarge"
|
||||
>
|
||||
<h2>Certificates</h2>
|
||||
<CertificatesTable
|
||||
data={data.certificates}
|
||||
showHelpText={!isMyDevicePage && hostPlatform === "darwin"}
|
||||
onSelectCertificate={onSelectCertificate}
|
||||
/>
|
||||
{renderContent()}
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,33 +1,57 @@
|
|||
import React from "react";
|
||||
import { Row } from "react-table";
|
||||
import React, { useCallback } from "react";
|
||||
|
||||
import { IHostCertificate } from "interfaces/certificates";
|
||||
import { IGetHostCertificatesResponse } from "services/entities/hosts";
|
||||
|
||||
import TableContainer from "components/TableContainer";
|
||||
import CustomLink from "components/CustomLink";
|
||||
import TableCount from "components/TableContainer/TableCount";
|
||||
import { ITableQueryData } from "components/TableContainer/TableContainer";
|
||||
|
||||
import generateTableConfig from "./CertificatesTableConfig";
|
||||
|
||||
const baseClass = "certificates-table";
|
||||
|
||||
interface ICertificatesTableProps {
|
||||
data: IHostCertificate[];
|
||||
data: IGetHostCertificatesResponse;
|
||||
showHelpText: boolean;
|
||||
page: number;
|
||||
pageSize: number;
|
||||
onSelectCertificate: (certificate: IHostCertificate) => void;
|
||||
onNextPage: () => void;
|
||||
onPreviousPage: () => void;
|
||||
}
|
||||
|
||||
const CertificatesTable = ({
|
||||
data,
|
||||
showHelpText,
|
||||
page,
|
||||
pageSize,
|
||||
onSelectCertificate,
|
||||
onNextPage,
|
||||
onPreviousPage,
|
||||
}: ICertificatesTableProps) => {
|
||||
const tableConfig = generateTableConfig();
|
||||
|
||||
const onClickTableRow = (row: Row<IHostCertificate>) => {
|
||||
const onClickTableRow = (row: any) => {
|
||||
onSelectCertificate(row.original);
|
||||
};
|
||||
|
||||
const onQueryChange = useCallback(
|
||||
async (newTableQuery: ITableQueryData) => {
|
||||
console.log(newTableQuery);
|
||||
|
||||
if (page === newTableQuery.pageIndex) return;
|
||||
|
||||
if (newTableQuery.pageIndex > page) {
|
||||
onNextPage();
|
||||
} else {
|
||||
onPreviousPage();
|
||||
}
|
||||
},
|
||||
[onNextPage, onPreviousPage, page]
|
||||
);
|
||||
|
||||
const helpText = showHelpText ? (
|
||||
<p>
|
||||
Showing certificates in the system keychain. To get all certificates, you
|
||||
|
|
@ -41,18 +65,24 @@ const CertificatesTable = ({
|
|||
) : null;
|
||||
|
||||
return (
|
||||
<TableContainer<Row<IHostCertificate>>
|
||||
<TableContainer
|
||||
className={baseClass}
|
||||
columnConfigs={tableConfig}
|
||||
data={data}
|
||||
data={data.certificates}
|
||||
emptyComponent={() => null}
|
||||
isAllPagesSelected={false}
|
||||
showMarkAllPages={false}
|
||||
isLoading={false}
|
||||
onClickRow={onClickTableRow}
|
||||
disableMultiRowSelect
|
||||
onSelectSingleRow={onClickTableRow}
|
||||
renderTableHelpText={() => helpText}
|
||||
renderCount={() => <TableCount name="certificates" count={data.length} />}
|
||||
disablePagination
|
||||
renderCount={() => (
|
||||
<TableCount name="certificates" count={data.certificates.length} />
|
||||
)}
|
||||
pageSize={pageSize}
|
||||
defaultPageIndex={page}
|
||||
onQueryChange={onQueryChange}
|
||||
disableNextPage={data?.meta.has_next_results === false}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue