Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dataset field column picker #717

Merged
merged 11 commits into from
Jun 1, 2022
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ The types of changes are:
* Datasets
* Systems
* Initial dataset collection UI view
* Add column picker
* Okta, aws and database credentials can now come from `fidesctl.toml` config [#694](https://github.com/ethyca/fides/pull/694)

### Changed
Expand Down
99 changes: 99 additions & 0 deletions clients/admin-ui/src/features/dataset/ColumnDropdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import {
Box,
Button,
Checkbox,
CheckboxGroup,
Menu,
MenuButton,
MenuList,
Stack,
} from "@fidesui/react";
import { useState } from "react";

import { ArrowDownLineIcon } from "~/features/common/Icon";

import { ColumnMetadata } from "./types";

interface Props {
allColumns: ColumnMetadata[];
selectedColumns: ColumnMetadata[];
onChange: (columns: ColumnMetadata[]) => void;
}
const ColumnDropdown = ({ allColumns, selectedColumns, onChange }: Props) => {
// this component keeps internal column state as well, since the user can select fields
// and then click the "Done" button to propagate to the rest of the UI
const [columns, setColumns] = useState(selectedColumns);

const handleClear = () => {
setColumns([]);
};

const handleSubmit = () => {
// we want to keep the sort order the same based off of all columns, so that the
// table columns don't go jumping around
const allColumnNames = allColumns.map((c) => c.name);
const sortedSelected = columns
.slice()
.sort(
(a, b) =>
allColumnNames.indexOf(a.name) - allColumnNames.indexOf(b.name)
);
onChange(sortedSelected);
};

const handleChange = (column: ColumnMetadata) => {
if (columns.filter((col) => col.name === column.name).length > 0) {
// remove from selected columns
setColumns(columns.filter((col) => col.name !== column.name));
} else {
setColumns([...columns, column]);
}
};

return (
<Menu>
<MenuButton
as={Button}
rightIcon={<ArrowDownLineIcon />}
variant="outline"
fontWeight="normal"
>
Columns
</MenuButton>
<MenuList>
<Box px={2}>
<Box display="flex" justifyContent="space-between" mb={2}>
<Button variant="outline" size="xs" onClick={handleClear}>
Clear
</Button>
<Button size="xs" colorScheme="primary" onClick={handleSubmit}>
Done
</Button>
</Box>
<CheckboxGroup colorScheme="complimentary">
<Stack>
{allColumns.map((column) => {
allisonking marked this conversation as resolved.
Show resolved Hide resolved
const isChecked =
columns.filter((selected) => selected.name === column.name)
allisonking marked this conversation as resolved.
Show resolved Hide resolved
.length > 0;
return (
<Checkbox
id={column.name}
key={column.name}
_hover={{ bg: "gray.100" }}
isChecked={isChecked}
onChange={() => handleChange(column)}
>
{column.name}
</Checkbox>
);
})}
</Stack>
</CheckboxGroup>
</Box>
</MenuList>
</Menu>
);
};

export default ColumnDropdown;
23 changes: 20 additions & 3 deletions clients/admin-ui/src/features/dataset/DatasetCollectionView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,17 @@ import { Box, Select, Spinner } from "@fidesui/react";
import { ChangeEvent, useEffect, useState } from "react";

import { FidesKey } from "../common/fides-types";
import ColumnDropdown from "./ColumnDropdown";
import { useGetDatasetByKeyQuery } from "./dataset.slice";
import DatasetFieldsTable from "./DatasetFieldsTable";
import { DatasetCollection } from "./types";
import { ColumnMetadata, DatasetCollection } from "./types";

const ALL_COLUMNS: ColumnMetadata[] = [
{ name: "Field Name", attribute: "name" },
{ name: "Description", attribute: "description" },
{ name: "Personal Data Categories", attribute: "data_categories" },
{ name: "Identifiability", attribute: "data_qualifier" },
];

const useDataset = (key: FidesKey) => {
const { data, isLoading } = useGetDatasetByKeyQuery(key);
Expand All @@ -24,6 +32,7 @@ const DatasetCollectionView = ({ fidesKey }: Props) => {
const [activeCollection, setActiveCollection] = useState<
DatasetCollection | undefined
>();
const [columns, setColumns] = useState<ColumnMetadata[]>(ALL_COLUMNS);

useEffect(() => {
if (dataset) {
Expand Down Expand Up @@ -52,17 +61,25 @@ const DatasetCollectionView = ({ fidesKey }: Props) => {

return (
<Box>
<Box mb={4} display="flex">
<Box mb={4} display="flex" justifyContent="space-between">
<Select onChange={handleChangeCollection} mr={2} width="auto">
{collections.map((collection) => (
<option key={collection.name} value={collection.name}>
{collection.name}
</option>
))}
</Select>
<ColumnDropdown
allColumns={ALL_COLUMNS}
selectedColumns={columns}
onChange={setColumns}
/>
</Box>
{activeCollection && (
<DatasetFieldsTable fields={activeCollection.fields} />
<DatasetFieldsTable
fields={activeCollection.fields}
columns={columns}
/>
)}
</Box>
);
Expand Down
21 changes: 13 additions & 8 deletions clients/admin-ui/src/features/dataset/DatasetFieldsTable.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,31 @@
import { Table, Tbody, Td, Th, Thead, Tr } from "@fidesui/react";

import { DatasetField } from "./types";
import { ColumnMetadata, DatasetField } from "./types";

interface Props {
fields: DatasetField[];
columns: ColumnMetadata[];
}

const DatasetFieldsTable = ({ fields }: Props) => (
const DatasetFieldsTable = ({ fields, columns }: Props) => (
<Table size="sm">
<Thead>
<Tr>
<Th pl={0}>Field Name</Th>
<Th pl={0}>Description</Th>
<Th pl={0}>Identifiability</Th>
{columns.map((c) => (
allisonking marked this conversation as resolved.
Show resolved Hide resolved
<Th key={c.name} pl={0}>
{c.name}
</Th>
))}
</Tr>
</Thead>
<Tbody>
{fields.map((field) => (
allisonking marked this conversation as resolved.
Show resolved Hide resolved
<Tr key={field.name}>
<Td pl={0}>{field.name}</Td>
<Td pl={0}>{field.description}</Td>
<Td pl={0}>{field.data_qualifier}</Td>
{columns.map((c) => (
<Td key={`${field.name}-${field[c.attribute]}`} pl={0}>
{field[c.attribute]}
</Td>
))}
</Tr>
))}
</Tbody>
Expand Down
5 changes: 5 additions & 0 deletions clients/admin-ui/src/features/dataset/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,8 @@ export interface DatasetCollection {
retention?: string;
fields: DatasetField[];
}

export interface ColumnMetadata {
name: string;
attribute: keyof DatasetField;
}