components#Paginator TypeScript Examples

The following examples show how to use components#Paginator. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: Domains.tsx    From crossfeed with Creative Commons Zero v1.0 Universal 5 votes vote down vote up
Domains: React.FC = () => {
  const { showAllOrganizations } = useAuthContext();
  const tableRef = useRef<TableInstance<Domain>>(null);
  const columns = useMemo(() => createColumns(), []);
  const [domains, setDomains] = useState<Domain[]>([]);
  const [totalResults, setTotalResults] = useState(0);

  const { listDomains } = useDomainApi(showAllOrganizations);

  const fetchDomains = useCallback(
    async (q: Query<Domain>) => {
      try {
        const { domains, count } = await listDomains(q);
        setDomains(domains);
        setTotalResults(count);
      } catch (e) {
        console.error(e);
      }
    },
    [listDomains]
  );

  const fetchDomainsExport = async (): Promise<string> => {
    const { sortBy, filters } = tableRef.current?.state ?? {};
    try {
      const { url } = await listDomains(
        {
          sort: sortBy ?? [],
          page: 1,
          pageSize: -1,
          filters: filters ?? []
        },
        true
      );
      return url!;
    } catch (e) {
      console.error(e);
      return '';
    }
  };

  const renderPagination = (table: TableInstance<Domain>) => (
    <Paginator
      table={table}
      totalResults={totalResults}
      export={{
        name: 'domains',
        getDataToExport: fetchDomainsExport
      }}
    />
  );

  return (
    <div className={classes.root}>
      <Subnav
        items={[
          { title: 'Search Results', path: '/inventory', exact: true },
          { title: 'All Domains', path: '/inventory/domains' },
          { title: 'All Vulnerabilities', path: '/inventory/vulnerabilities' }
        ]}
      ></Subnav>
      <br></br>
      <Table<Domain>
        renderPagination={renderPagination}
        tableRef={tableRef}
        columns={columns}
        data={domains}
        pageCount={Math.ceil(totalResults / PAGE_SIZE)}
        fetchData={fetchDomains}
        pageSize={PAGE_SIZE}
      />
    </div>
  );
}
Example #2
Source File: ConfirmationOfReceiptPage.tsx    From solo with MIT License 5 votes vote down vote up
ConfirmationOfReceiptPage: React.FC = () => {
  const [bulkReceivedBy, setBulkReceivedBy] = useState("");
  const {
    docs,
    updateDocuments,
    pageCount,
    submitCOR,
    submitBulkCOR,
    bulkSubmitStatus,
    resetBulkSubmitStatus
  } = useCORDocuments();
  const columns = useMemo(
    () =>
      createColumns({
        onSubmitCOR: submitCOR
      }),
    [submitCOR]
  );

  const onSelectedRowsChange = useCallback(
    ({ toggleHideColumn, selectedFlatRows }: TableInstance<Document>) => {
      // show individual row submit forms only when no rows are selected
      resetBulkSubmitStatus();
      toggleHideColumn("submitCOR", selectedFlatRows.length > 0);
    },
    [resetBulkSubmitStatus]
  );

  const renderPagination = (table: TableInstance<Document>) => (
    <>{table.selectedFlatRows.length === 0 && <Paginator table={table} />}</>
  );

  const renderFilterControls = (table: TableInstance<Document>) => {
    const { setGlobalFilter, selectedFlatRows } = table;
    return selectedFlatRows.length > 0 ? (
      <CORInputForm
        value={bulkReceivedBy}
        onReceivedByChange={setBulkReceivedBy}
        onSubmitCOR={() =>
          submitBulkCOR(
            selectedFlatRows.map(({ original }) => original.sdn),
            bulkReceivedBy
          )
        }
        actionText={`Submit ${selectedFlatRows.length} Cors`}
        className="margin-left-2 padding-y-2 flex-justify-center"
        {...bulkSubmitStatus}
      />
    ) : (
      <SelectFilterControls options={filterable} onSubmit={setGlobalFilter} />
    );
  };

  return (
    <div className="tablet:margin-x-8 overflow-x-auto">
      <Title>Confirmation of Receipt</Title>
      <Table<Document>
        columns={columns}
        data={docs}
        onSelectedRowsChange={onSelectedRowsChange}
        renderFilterControls={renderFilterControls}
        renderPagination={renderPagination}
        pageCount={pageCount}
        fetchData={updateDocuments}
      />
    </div>
  );
}
Example #3
Source File: StatusPage.tsx    From solo with MIT License 5 votes vote down vote up
StatusPage: React.FC = () => {
  const { docs, updateDocuments, pageCount } = useDocumentSet();
  const tableColumns = useMemo(createColumns, []);

  const renderSubComponent = ({
    original: { shipTo, holder, part, statuses }
  }: Row<Document>) => (
    <>
      <DocumentStepper statuses={statuses} />
      <DocumentDetails
        shipper={holder}
        receiver={shipTo}
        part={part}
        statuses={statuses}
      />
    </>
  );

  const renderPagination = (table: TableInstance<Document>) => (
    <Paginator table={table} />
  );
  const renderFilterControls = ({
    setGlobalFilter
  }: TableInstance<Document>) => (
    <SelectFilterControls options={filterable} onSubmit={setGlobalFilter} />
  );

  return (
    <div className="tablet:margin-x-8 overflow-x-auto">
      <Title>Status</Title>
      <Table<Document>
        columns={tableColumns}
        data={docs}
        renderSubComponent={renderSubComponent}
        renderPagination={renderPagination}
        renderFilterControls={renderFilterControls}
        fetchData={updateDocuments}
        pageCount={pageCount}
      />
    </div>
  );
}
Example #4
Source File: ScanTasksView.tsx    From crossfeed with Creative Commons Zero v1.0 Universal 4 votes vote down vote up
ScanTasksView: React.FC = () => {
  const { apiPost, token } = useAuthContext();
  const [scanTasks, setScanTasks] = useState<ScanTask[]>([]);
  const [totalResults, setTotalResults] = useState(0);
  const [errors, setErrors] = useState<Errors>({});

  const killScanTask = async (index: number) => {
    try {
      const row = scanTasks[index];
      await apiPost(`/scan-tasks/${row.id}/kill`, { body: {} });
      setScanTasks(
        Object.assign([], scanTasks, {
          [index]: {
            ...row,
            status: 'failed'
          }
        })
      );
    } catch (e) {
      setErrors({
        global:
          e.status === 422 ? 'Unable to kill scan' : e.message ?? e.toString()
      });
      console.log(e);
    }
  };

  const renderExpanded = (row: Row<ScanTask>) => {
    const { original } = row;
    return (
      <div className={classes.expandedRoot}>
        {original.fargateTaskArn && (
          <>
            <h4>
              Logs
              {original.fargateTaskArn?.match('.*/(.*)') && (
                <a
                  target="_blank"
                  rel="noopener noreferrer"
                  href={`https://us-east-1.console.aws.amazon.com/cloudwatch/home?region=us-east-1#logsV2:log-groups/log-group/${process
                    .env
                    .REACT_APP_FARGATE_LOG_GROUP!}/log-events/worker$252Fmain$252F${
                    (original.fargateTaskArn.match('.*/(.*)') || [])[1]
                  }`}
                >
                  {' '}
                  (View all on CloudWatch)
                </a>
              )}
            </h4>

            <Log
              token={token ?? ''}
              url={`${process.env.REACT_APP_API_URL}/scan-tasks/${original.id}/logs`}
            />
          </>
        )}

        <h4>Input</h4>
        <small>
          <pre>{JSON.stringify(JSON.parse(original.input), null, 2)}</pre>
        </small>
        <h4>Output</h4>
        <small>
          <pre>{original.output || 'None'}</pre>
        </small>

        {row.original.status !== 'finished' &&
          row.original.status !== 'failed' && (
            <>
              <h4>Actions</h4>
              <a
                href="# "
                onClick={(e) => {
                  e.preventDefault();
                  killScanTask(row.index);
                }}
              >
                Kill
              </a>
            </>
          )}
      </div>
    );
  };

  const columns: Column<ScanTask>[] = [
    {
      Header: 'ID',
      accessor: 'id',
      Filter: ColumnFilter,
      disableSortBy: true,
      disableFilters: true
    },
    {
      Header: 'Status',
      accessor: 'status',
      Filter: selectFilter([
        'created',
        'queued',
        'requested',
        'started',
        'finished',
        'failed'
      ]),
      disableSortBy: true
    },
    {
      Header: 'Name',
      id: 'name',
      accessor: ({ scan }) => scan?.name,
      Filter: selectFilter([
        // TODO: sync this with the SCAN_SCHEMA
        'censys',
        'amass',
        'findomain',
        'portscanner',
        'wappalyzer',
        'censysIpv4',
        'censysCertificates',
        'sslyze',
        'searchSync',
        'cve',
        'dotgov',
        'webscraper',
        'intrigueIdent',
        'shodan',
        'hibp',
        'lookingGlass',
        'dnstwist',
        'peCybersixgill',
        'peHibpSync',
        'peShodan',
        'peDomMasq',
        'rootDomainSync'
      ]),
      disableSortBy: true
    },
    {
      Header: 'Created At',
      id: 'createdAt',
      accessor: ({ createdAt }) => dateAccessor(createdAt),
      disableFilters: true
    },
    {
      Header: 'Finished At',
      id: 'finishedAt',
      accessor: ({ finishedAt }) => dateAccessor(finishedAt),
      disableFilters: true
    },
    {
      Header: 'Details',
      Cell: ({ row }: CellProps<ScanTask>) => (
        <span
          {...row.getToggleRowExpandedProps()}
          className="text-center display-block"
        >
          {row.isExpanded ? <FaMinus /> : <FaPlus />}
        </span>
      ),
      disableFilters: true
    }
  ];
  const PAGE_SIZE = 25;

  const fetchScanTasks = useCallback(
    async (query: Query<ScanTask>) => {
      const { page, sort, filters } = query;
      try {
        const { result, count } = await apiPost<ApiResponse>(
          '/scan-tasks/search',
          {
            body: {
              page,
              sort: sort[0]?.id ?? 'createdAt',
              order: sort[0]?.desc ? 'DESC' : 'ASC',
              filters: filters
                .filter((f) => Boolean(f.value))
                .reduce(
                  (accum, next) => ({
                    ...accum,
                    [next.id]: next.value
                  }),
                  {}
                )
            }
          }
        );
        setScanTasks(result);
        setTotalResults(count);
      } catch (e) {
        console.error(e);
      }
    },
    [apiPost]
  );

  const renderPagination = (table: TableInstance<ScanTask>) => (
    <Paginator table={table} totalResults={totalResults} />
  );

  return (
    <>
      {errors.global && <p className={classes.error}>{errors.global}</p>}
      <Table<ScanTask>
        renderPagination={renderPagination}
        columns={columns}
        data={scanTasks}
        pageCount={Math.ceil(totalResults / PAGE_SIZE)}
        fetchData={fetchScanTasks}
        pageSize={PAGE_SIZE}
        initialSortBy={[
          {
            id: 'createdAt',
            desc: true
          }
        ]}
        renderExpanded={renderExpanded}
      />
    </>
  );
}
Example #5
Source File: Vulnerabilities.tsx    From crossfeed with Creative Commons Zero v1.0 Universal 4 votes vote down vote up
Vulnerabilities: React.FC<{ groupBy?: string }> = ({
  groupBy = undefined
}: {
  children?: React.ReactNode;
  groupBy?: string;
}) => {
  const {
    currentOrganization,
    apiPost,
    apiPut,
    showAllOrganizations
  } = useAuthContext();
  const [vulnerabilities, setVulnerabilities] = useState<Vulnerability[]>([]);
  const [totalResults, setTotalResults] = useState(0);
  const tableRef = useRef<TableInstance<Vulnerability>>(null);
  const listClasses = useStyles();
  const [noResults, setNoResults] = useState(false);

  const updateVulnerability = useCallback(
    async (index: number, body: { [key: string]: string }) => {
      try {
        const res = await apiPut<Vulnerability>(
          '/vulnerabilities/' + vulnerabilities[index].id,
          {
            body: body
          }
        );
        const vulnCopy = [...vulnerabilities];
        vulnCopy[index].state = res.state;
        vulnCopy[index].substate = res.substate;
        vulnCopy[index].actions = res.actions;
        setVulnerabilities(vulnCopy);
      } catch (e) {
        console.error(e);
      }
    },
    [setVulnerabilities, apiPut, vulnerabilities]
  );
  const columns = useMemo(() => createColumns(updateVulnerability), [
    updateVulnerability
  ]);
  const groupedColumns = useMemo(() => createGroupedColumns(), []);

  const vulnerabilitiesSearch = useCallback(
    async ({
      filters,
      sort,
      page,
      pageSize = PAGE_SIZE,
      doExport = false,
      groupBy = undefined
    }: {
      filters: Filters<Vulnerability>;
      sort: SortingRule<Vulnerability>[];
      page: number;
      pageSize?: number;
      doExport?: boolean;
      groupBy?: string;
    }): Promise<ApiResponse | undefined> => {
      try {
        const tableFilters: {
          [key: string]: string | boolean | undefined;
        } = filters
          .filter((f) => Boolean(f.value))
          .reduce(
            (accum, next) => ({
              ...accum,
              [next.id]: next.value
            }),
            {}
          );
        // If not open or closed, substitute for appropriate substate
        if (
          tableFilters['state'] &&
          !['open', 'closed'].includes(tableFilters['state'] as string)
        ) {
          const substate = (tableFilters['state'] as string)
            .match(/\((.*)\)/)
            ?.pop();
          if (substate)
            tableFilters['substate'] = substate.toLowerCase().replace(' ', '-');
          delete tableFilters['state'];
        }
        if (!showAllOrganizations && currentOrganization) {
          if ('rootDomains' in currentOrganization)
            tableFilters['organization'] = currentOrganization.id;
          else tableFilters['tag'] = currentOrganization.id;
        }
        if (tableFilters['isKev']) {
          // Convert string to boolean filter.
          tableFilters['isKev'] = tableFilters['isKev'] === 'true';
        }
        return await apiPost<ApiResponse>(
          doExport ? '/vulnerabilities/export' : '/vulnerabilities/search',
          {
            body: {
              page,
              sort: sort[0]?.id ?? 'createdAt',
              order: sort[0]?.desc ? 'DESC' : 'ASC',
              filters: tableFilters,
              pageSize,
              groupBy
            }
          }
        );
      } catch (e) {
        console.error(e);
        return;
      }
    },
    [apiPost, currentOrganization, showAllOrganizations]
  );

  const fetchVulnerabilities = useCallback(
    async (query: Query<Vulnerability>) => {
      const resp = await vulnerabilitiesSearch({
        filters: query.filters,
        sort: query.sort,
        page: query.page,
        groupBy
      });
      if (!resp) return;
      const { result, count } = resp;
      setVulnerabilities(result);
      setTotalResults(count);
      setNoResults(count === 0);
    },
    [vulnerabilitiesSearch, groupBy]
  );

  const fetchVulnerabilitiesExport = async (): Promise<string> => {
    const { sortBy, filters } = tableRef.current?.state ?? {};
    const { url } = (await vulnerabilitiesSearch({
      filters: filters!,
      sort: sortBy!,
      page: 1,
      pageSize: -1,
      doExport: true
    })) as ApiResponse;
    return url!;
  };

  const renderPagination = (table: TableInstance<Vulnerability>) => (
    <Paginator
      table={table}
      totalResults={totalResults}
      export={{
        name: 'vulnerabilities',
        getDataToExport: fetchVulnerabilitiesExport
      }}
    />
  );

  const initialFilterBy: Filters<Vulnerability> = [];
  let initialSortBy: SortingRule<Vulnerability>[] = [];
  const params = parse(window.location.search);
  if (!('state' in params)) params['state'] = 'open';
  for (const param of Object.keys(params)) {
    if (param === 'sort') {
      initialSortBy = [
        {
          id: params[param] as string,
          desc: 'desc' in params ? params['desc'] === 'true' : true
        }
      ];
    } else if (param !== 'desc') {
      initialFilterBy.push({
        id: param,
        value: params[param] as string
      });
    }
  }

  return (
    <div>
      <div className={listClasses.contentWrapper}>
        <Subnav
          items={[
            { title: 'Search Results', path: '/inventory', exact: true },
            { title: 'All Domains', path: '/inventory/domains' },
            { title: 'All Vulnerabilities', path: '/inventory/vulnerabilities' }
          ]}
        ></Subnav>
        <br></br>
        <div className={classes.root}>
          <Table<Vulnerability>
            renderPagination={renderPagination}
            columns={groupBy ? groupedColumns : columns}
            data={vulnerabilities}
            pageCount={Math.ceil(totalResults / PAGE_SIZE)}
            fetchData={fetchVulnerabilities}
            tableRef={tableRef}
            initialFilterBy={initialFilterBy}
            initialSortBy={initialSortBy}
            noResults={noResults}
            pageSize={PAGE_SIZE}
            noResultsMessage={
              "We don't see any vulnerabilities that match your criteria."
            }
          />
        </div>
      </div>
    </div>
  );
}