Skip to content

Commit

Permalink
Merge pull request #270 from bento-platform/features/table-removal
Browse files Browse the repository at this point in the history
refact!: table removal
  • Loading branch information
v-rocheleau authored Aug 30, 2023
2 parents 558dc08 + af90344 commit f9eb659
Show file tree
Hide file tree
Showing 54 changed files with 1,071 additions and 1,680 deletions.
15 changes: 15 additions & 0 deletions src/components/ConfirmationModal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Modal } from "antd";

const { confirm } = Modal;

const genericConfirm = ({title, content, onOk, onCancel, ...rest}) => {
confirm({
title: title,
content: content,
onOk: onOk,
onCancel,
...rest,
});
};

export default genericConfirm;
1 change: 0 additions & 1 deletion src/components/ServiceContent.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ const ServiceContent = () => {
/>
</Spin>
</Col>
{/* TODO: Tables */}
</Row>
<Typography.Title level={3}>Services</Typography.Title>
<ServiceList />
Expand Down
23 changes: 13 additions & 10 deletions src/components/ServiceList.js
Original file line number Diff line number Diff line change
Expand Up @@ -215,16 +215,19 @@ const ServiceList = () => {
const [requestModalService, setRequestModalService] = useState(null);

const dataSource = useSelector((state) =>
Object.entries(state.bentoServices.itemsByKind).map(([kind, service]) => ({
...service,
key: kind,
serviceInfo: state.services.itemsByKind[kind] ?? null,
status: {
status: kind in state.services.itemsByKind,
dataService: service.data_service,
},
loading: state.services.isFetching,
})),
Object.entries(state.bentoServices.itemsByKind).map(([kind, service]) => {
const serviceInfo = state.services.itemsByKind[kind] ?? null;
return {
...service,
key: kind,
serviceInfo,
status: {
status: kind in state.services.itemsByKind,
dataService: serviceInfo?.bento?.dataService,
},
loading: state.services.isFetching,
};
}),
);

const isAuthenticated = useSelector(
Expand Down
44 changes: 26 additions & 18 deletions src/components/datasets/Dataset.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,24 @@ import {
deleteDatasetLinkedFieldSetIfPossible,
} from "../../modules/metadata/actions";

import {
fetchDatasetDataTypesSummaryIfPossible,
fetchDatasetSummaryIfPossible,
} from "../../modules/datasets/actions";

import {INITIAL_DATA_USE_VALUE} from "../../duo";
import {simpleDeepCopy, nop} from "../../utils/misc";
import LinkedFieldSetTable from "./linked_field_set/LinkedFieldSetTable";
import LinkedFieldSetModal from "./linked_field_set/LinkedFieldSetModal";
import DatasetOverview from "./DatasetOverview";
import DatasetTables from "./DatasetTables";
import {FORM_MODE_ADD, FORM_MODE_EDIT} from "../../constants";
import {datasetPropTypesShape, projectPropTypesShape} from "../../propTypes";
import DatasetDataTypes from "./DatasetDataTypes";


const DATASET_CARD_TABS = [
{key: "overview", tab: "Overview"},
{key: "tables", tab: "Data Tables"},
{key: "data_types", tab: "Data Types"},
{key: "linked_field_sets", tab: "Linked Field Sets"},
{key: "data_use", tab: "Consent Codes and Data Use"},
];
Expand Down Expand Up @@ -71,7 +76,6 @@ class Dataset extends Component {
contact_info: value.contact_info || "",
data_use: simpleDeepCopy(value.data_use || INITIAL_DATA_USE_VALUE),
linked_field_sets: value.linked_field_sets || [],
tables: value.tables || [],

fieldSetAdditionModalVisible: false,

Expand All @@ -82,13 +86,20 @@ class Dataset extends Component {
},

selectedTab: "overview",
selectedTable: null,
};

this.handleFieldSetDeletion = this.handleFieldSetDeletion.bind(this);
}


componentDidMount() {
if (this.state.identifier) {
this.props.fetchDatasetSummary(this.state.identifier);
this.props.fetchDatasetDataTypesSummary(this.state.identifier);
}
}


handleFieldSetDeletion(fieldSet, index) {
const deleteModal = Modal.confirm({
title: `Are you sure you want to delete the "${fieldSet.name}" linked field set?`,
Expand Down Expand Up @@ -123,13 +134,11 @@ class Dataset extends Component {
const tabContents = {
overview: <DatasetOverview dataset={this.state}
project={this.props.project}
isPrivate={isPrivate}
isFetchingTables={this.props.isFetchingTables} />,
tables: <DatasetTables dataset={this.state}
project={this.props.project}
isPrivate={isPrivate}
isFetchingTables={this.props.isFetchingTables}
onTableIngest={this.props.onTableIngest || nop} />,
isPrivate={isPrivate} />,
data_types: <DatasetDataTypes dataset={this.state}
project={this.props.project}
isPrivate={isPrivate}
onDatasetIngest={this.props.onDatasetIngest}/>,
linked_field_sets: (
<>
<Typography.Title level={4}>
Expand Down Expand Up @@ -281,24 +290,21 @@ Dataset.propTypes = {
mode: PropTypes.oneOf(["public", "private"]),

project: projectPropTypesShape,
strayTables: PropTypes.arrayOf(PropTypes.object),

value: datasetPropTypesShape,

isFetchingTables: PropTypes.bool,

onEdit: PropTypes.func,
onTableIngest: PropTypes.func,
onDatasetIngest: PropTypes.func,

addLinkedFieldSet: PropTypes.func,
deleteProjectDataset: PropTypes.func,
deleteLinkedFieldSet: PropTypes.func,

fetchDatasetSummary: PropTypes.func,
fetchDatasetDataTypesSummary: PropTypes.func,
};

const mapStateToProps = state => ({
isFetchingTables: state.services.isFetchingAll
|| state.projectTables.isFetching
|| state.projects.isFetchingWithTables, // TODO: Hiccup
isSavingDataset: state.projects.isSavingDataset,
isDeletingDataset: state.projects.isDeletingDataset,
});
Expand All @@ -309,6 +315,8 @@ const mapDispatchToProps = (dispatch, ownProps) => ({
deleteProjectDataset: dataset => dispatch(deleteProjectDatasetIfPossible(ownProps.project, dataset)),
deleteLinkedFieldSet: (dataset, linkedFieldSet, linkedFieldSetIndex) =>
dispatch(deleteDatasetLinkedFieldSetIfPossible(dataset, linkedFieldSet, linkedFieldSetIndex)),
fetchDatasetSummary: (datasetId) => dispatch(fetchDatasetSummaryIfPossible(datasetId)),
fetchDatasetDataTypesSummary: (datasetId) => dispatch(fetchDatasetDataTypesSummaryIfPossible(datasetId)),
});

export default connect(mapStateToProps, mapDispatchToProps)(Dataset);
132 changes: 132 additions & 0 deletions src/components/datasets/DatasetDataTypes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import React, {useCallback, useMemo, useState} from "react";
import { useSelector, useDispatch } from "react-redux";
import { Button, Col, Row, Table, Typography } from "antd";

import PropTypes from "prop-types";
import { datasetPropTypesShape, projectPropTypesShape } from "../../propTypes";
import { clearDatasetDataType } from "../../modules/metadata/actions";
import { fetchDatasetDataTypesSummaryIfPossible } from "../../modules/datasets/actions";
import genericConfirm from "../ConfirmationModal";
import DataTypeSummaryModal from "./datatype/DataTypeSummaryModal";
import { nop } from "../../utils/misc";

const NA_TEXT = <span style={{ color: "#999", fontStyle: "italic" }}>N/A</span>;

const DatasetDataTypes = React.memo(
({isPrivate, project, dataset, onDatasetIngest}) => {
const dispatch = useDispatch();
const datasetDataTypes = useSelector((state) => Object.values(
state.datasetDataTypes.itemsById[dataset.identifier]?.itemsById));
const datasetSummaries = useSelector((state) => state.datasetSummaries.itemsById[dataset.identifier]);
const isFetchingDataset = useSelector(
(state) => state.datasetDataTypes.itemsById[dataset.identifier]?.isFetching);

const [datatypeSummaryVisible, setDatatypeSummaryVisible] = useState(false);
const [selectedDataType, setSelectedDataType] = useState(null);

const selectedSummary = (selectedDataType !== null && datasetSummaries)
? datasetSummaries[selectedDataType.id]
: {};

const handleClearDataType = useCallback((dataType) => {
genericConfirm({
title: `Are you sure you want to delete the "${dataType.label || dataType.id}" data type?`,
content: "Deleting this means all instances of this data type contained in the dataset " +
"will be deleted permanently, and will no longer be available for exploration.",
onOk: async () => {
await dispatch(clearDatasetDataType(dataset.identifier, dataType.id));
await dispatch(fetchDatasetDataTypesSummaryIfPossible(dataset.identifier));
},
});
}, [dispatch, dataset]);

const showDatatypeSummary = useCallback((dataType) => {
setSelectedDataType(dataType);
setDatatypeSummaryVisible(true);
}, []);

const dataTypesColumns = useMemo(() => [
{
title: "Name",
key: "label",
render: (dt) =>
isPrivate ? (
<a onClick={() => showDatatypeSummary(dt)}>
{dt.label ?? NA_TEXT}
</a>
) : dt.label ?? NA_TEXT,
defaultSortOrder: "ascend",
sorter: (a, b) => a.label.localeCompare(b.label),
},
{
title: "Count",
dataIndex: "count",
render: (c) => (c ?? NA_TEXT),
},
...(isPrivate ? [
{
title: "Actions",
key: "actions",
width: 230,
render: (dt) => (
<Row gutter={10}>
<Col span={12}>
<Button
icon="import"
style={{ width: "100%" }}
onClick={() => (onDatasetIngest || nop)(project, dataset, dt)}
>
Ingest
</Button>
</Col>
<Col span={12}>
<Button
type="danger"
icon="delete"
disabled={ !dt.count || dt.count && dt.count === 0}
onClick={() => handleClearDataType(dt)}
style={{ width: "100%" }}
>
Clear
</Button>
</Col>
</Row>
),
},
] : null),
], [isPrivate, project, dataset, onDatasetIngest]);

const onDataTypeSummaryModalCancel = useCallback(() => setDatatypeSummaryVisible(false), []);

return (
<>
<DataTypeSummaryModal
dataType={selectedDataType}
summary={selectedSummary}
visible={datatypeSummaryVisible}
onCancel={onDataTypeSummaryModalCancel}
/>

<Typography.Title level={4}>
Data Types
</Typography.Title>

<Table
bordered
dataSource={datasetDataTypes}
rowKey="id"
columns={dataTypesColumns}
loading={isFetchingDataset}
/>
</>
);
});

DatasetDataTypes.propTypes = {
isPrivate: PropTypes.bool,
project: projectPropTypesShape,
dataset: datasetPropTypesShape,
onDatasetIngest: PropTypes.func,
};

export default DatasetDataTypes;
8 changes: 4 additions & 4 deletions src/components/datasets/DatasetFormModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import DatasetForm from "./DatasetForm";
import {
addProjectDataset,
saveProjectDataset,
fetchProjectsWithDatasetsAndTables,
fetchProjectsWithDatasets,
} from "../../modules/metadata/actions";

import {nop} from "../../utils/misc";
Expand Down Expand Up @@ -53,7 +53,7 @@ class DatasetFormModal extends Component {
}

async handleSuccess(values) {
await this.props.fetchProjectsWithDatasetsAndTables(); // TODO: If needed / only this project...
await this.props.fetchProjectsWithDatasets(); // TODO: If needed / only this project...
await (this.props.onOk || nop)({...(this.props.initialValue || {}), values});
if ((this.props.mode || FORM_MODE_ADD) === FORM_MODE_ADD) this.form.resetFields();
}
Expand Down Expand Up @@ -107,7 +107,7 @@ DatasetFormModal.propTypes = {

addProjectDataset: PropTypes.func,
saveProjectDataset: PropTypes.func,
fetchProjectsWithDatasetsAndTables: PropTypes.func,
fetchProjectsWithDatasets: PropTypes.func,
};

const mapStateToProps = state => ({
Expand All @@ -120,5 +120,5 @@ const mapStateToProps = state => ({
export default connect(mapStateToProps, {
addProjectDataset,
saveProjectDataset,
fetchProjectsWithDatasetsAndTables,
fetchProjectsWithDatasets,
})(DatasetFormModal);
Loading

0 comments on commit f9eb659

Please sign in to comment.