Clean up EditTableEntityPanel (#955)

This commit is contained in:
victor-meng 2021-07-22 16:18:48 -07:00 committed by GitHub
parent 39a67dbc98
commit dc21032d69
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 1901 additions and 2890 deletions

View File

@ -150,9 +150,6 @@
.backImageIcon { .backImageIcon {
margin-top: 8px; margin-top: 8px;
} }
.entityValueTextField {
margin: 24px;
}
.addEntityDatePicker { .addEntityDatePicker {
max-width: 145px; max-width: 145px;
} }

View File

@ -218,7 +218,7 @@ export const AddTableEntityPanel: FunctionComponent<AddTableEntityPanelProps> =
if (isEntityValuePanelOpen) { if (isEntityValuePanelOpen) {
return ( return (
<Stack style={{ margin: "20px 0", padding: "0 34px" }}> <Stack style={{ padding: "20px 34px" }}>
<Stack horizontal {...columnProps}> <Stack horizontal {...columnProps}>
<Image {...backImageProps} src={RevertBackIcon} alt="back" onClick={() => setIsEntityValuePanelFalse()} /> <Image {...backImageProps} src={RevertBackIcon} alt="back" onClick={() => setIsEntityValuePanelFalse()} />
<Label>{entityAttributeProperty}</Label> <Label>{entityAttributeProperty}</Label>

View File

@ -1,11 +1,11 @@
import { IDropdownOption, Image, IPanelProps, IRenderFunction, Label, Stack, Text, TextField } from "@fluentui/react"; import { IDropdownOption, Image, Label, Stack, Text, TextField } from "@fluentui/react";
import { useBoolean } from "@fluentui/react-hooks"; import { useBoolean } from "@fluentui/react-hooks";
import React, { FunctionComponent, useEffect, useState } from "react"; import React, { FunctionComponent, useEffect, useState } from "react";
import * as _ from "underscore"; import * as _ from "underscore";
import AddPropertyIcon from "../../../../images/Add-property.svg"; import AddPropertyIcon from "../../../../images/Add-property.svg";
import RevertBackIcon from "../../../../images/RevertBack.svg"; import RevertBackIcon from "../../../../images/RevertBack.svg";
import { getErrorMessage, handleError } from "../../../Common/ErrorHandlingUtils";
import { TableEntity } from "../../../Common/TableEntity"; import { TableEntity } from "../../../Common/TableEntity";
import { useSidePanel } from "../../../hooks/useSidePanel";
import { userContext } from "../../../UserContext"; import { userContext } from "../../../UserContext";
import * as TableConstants from "../../Tables/Constants"; import * as TableConstants from "../../Tables/Constants";
import * as DataTableUtilities from "../../Tables/DataTable/DataTableUtilities"; import * as DataTableUtilities from "../../Tables/DataTable/DataTableUtilities";
@ -14,7 +14,7 @@ import * as Entities from "../../Tables/Entities";
import { CassandraAPIDataClient, TableDataClient } from "../../Tables/TableDataClient"; import { CassandraAPIDataClient, TableDataClient } from "../../Tables/TableDataClient";
import * as TableEntityProcessor from "../../Tables/TableEntityProcessor"; import * as TableEntityProcessor from "../../Tables/TableEntityProcessor";
import QueryTablesTab from "../../Tabs/QueryTablesTab"; import QueryTablesTab from "../../Tabs/QueryTablesTab";
import { PanelContainerComponent } from "../PanelContainerComponent"; import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneForm";
import { import {
attributeNameLabel, attributeNameLabel,
attributeValueLabel, attributeValueLabel,
@ -29,7 +29,6 @@ import {
getEntityValuePlaceholder, getEntityValuePlaceholder,
getFormattedTime, getFormattedTime,
imageProps, imageProps,
isValidEntities,
options, options,
} from "./Validators/EntityTableHelper"; } from "./Validators/EntityTableHelper";
@ -59,12 +58,13 @@ export const EditTableEntityPanel: FunctionComponent<EditTableEntityPanelProps>
tableEntityListViewModel, tableEntityListViewModel,
cassandraApiClient, cassandraApiClient,
}: EditTableEntityPanelProps): JSX.Element => { }: EditTableEntityPanelProps): JSX.Element => {
const closeSidePanel = useSidePanel((state) => state.closeSidePanel);
const [entities, setEntities] = useState<EntityRowType[]>([]); const [entities, setEntities] = useState<EntityRowType[]>([]);
const [selectedRow, setSelectedRow] = useState<number>(0); const [selectedRow, setSelectedRow] = useState<number>(0);
const [entityAttributeValue, setEntityAttributeValue] = useState<string>(""); const [entityAttributeValue, setEntityAttributeValue] = useState<string>("");
const [originalDocument, setOriginalDocument] = useState<Entities.ITableEntity>({}); const [originalDocument, setOriginalDocument] = useState<Entities.ITableEntity>({});
const [entityAttributeProperty, setEntityAttributeProperty] = useState<string>(""); const [entityAttributeProperty, setEntityAttributeProperty] = useState<string>("");
const [formError, setFormError] = useState<string>("");
const [isExecuting, setIsExecuting] = useState<boolean>(false);
const [ const [
isEntityValuePanelOpen, isEntityValuePanelOpen,
@ -190,26 +190,44 @@ export const EditTableEntityPanel: FunctionComponent<EditTableEntityPanelProps>
return displayValue; return displayValue;
}; };
const submit = async (event: React.FormEvent<HTMLInputElement>): Promise<void> => { const onSubmit = async (): Promise<void> => {
if (!isValidEntities(entities)) { for (let i = 0; i < entities.length; i++) {
return undefined; const { property, type } = entities[i];
if (property === "" || property === undefined) {
setFormError(`Property name cannot be empty. Please enter a property name`);
return;
}
if (!type) {
setFormError(`Property type cannot be empty. Please select a type from the dropdown for property ${property}`);
return;
}
} }
event.preventDefault();
setIsExecuting(true);
const entity: Entities.ITableEntity = entityFromAttributes(entities); const entity: Entities.ITableEntity = entityFromAttributes(entities);
const newTableDataClient = userContext.apiType === "Cassandra" ? cassandraApiClient : tableDataClient; const newTableDataClient = userContext.apiType === "Cassandra" ? cassandraApiClient : tableDataClient;
const originalDocumentData = userContext.apiType === "Cassandra" ? originalDocument[0] : originalDocument; const originalDocumentData = userContext.apiType === "Cassandra" ? originalDocument[0] : originalDocument;
const newEntity: Entities.ITableEntity = await newTableDataClient.updateDocument(
queryTablesTab.collection, try {
originalDocumentData, const newEntity: Entities.ITableEntity = await newTableDataClient.updateDocument(
entity queryTablesTab.collection,
); originalDocumentData,
await tableEntityListViewModel.updateCachedEntity(newEntity); entity
if (!tryInsertNewHeaders(tableEntityListViewModel, newEntity)) { );
tableEntityListViewModel.redrawTableThrottled(); await tableEntityListViewModel.updateCachedEntity(newEntity);
if (!tryInsertNewHeaders(tableEntityListViewModel, newEntity)) {
tableEntityListViewModel.redrawTableThrottled();
}
tableEntityListViewModel.selected.removeAll();
tableEntityListViewModel.selected.push(newEntity);
} catch (error) {
const errorMessage = getErrorMessage(error);
handleError(errorMessage, "EditTableRow");
throw error;
} finally {
setIsExecuting(false);
} }
tableEntityListViewModel.selected.removeAll();
tableEntityListViewModel.selected.push(newEntity);
closeSidePanel();
}; };
const tryInsertNewHeaders = (viewModel: TableEntityListViewModel, newEntity: Entities.ITableEntity): boolean => { const tryInsertNewHeaders = (viewModel: TableEntityListViewModel, newEntity: Entities.ITableEntity): boolean => {
@ -299,109 +317,81 @@ export const EditTableEntityPanel: FunctionComponent<EditTableEntityPanelProps>
setIsEntityValuePanelTrue(); setIsEntityValuePanelTrue();
}; };
const renderPanelContent = (): JSX.Element => {
return (
<form className="panelFormWrapper">
<div className="panelFormWrapper">
<div className="panelMainContent">
{entities.map((entity, index) => {
return (
<TableEntity
key={"" + entity.id + index}
isDeleteOptionVisible={entity.isDeleteOptionVisible}
entityTypeLabel={index === 0 && dataTypeLabel}
entityPropertyLabel={index === 0 && attributeNameLabel}
entityValueLabel={index === 0 && attributeValueLabel}
options={userContext.apiType === "Cassandra" ? cassandraOptions : options}
isPropertyTypeDisable={entity.isPropertyTypeDisable}
entityProperty={entity.property}
selectedKey={entity.type}
entityPropertyPlaceHolder={detailedHelp}
entityValuePlaceholder={entity.entityValuePlaceholder}
entityValue={entity.value?.toString()}
isEntityTypeDate={entity.isEntityTypeDate}
entityTimeValue={entity.entityTimeValue}
isEntityValueDisable={entity.isEntityValueDisable}
onEditEntity={() => editEntity(index)}
onSelectDate={(date: Date) => {
entityChange(date, index, "value");
}}
onDeleteEntity={() => deleteEntityAtIndex(index)}
onEntityPropertyChange={(event, newInput?: string) => {
entityChange(newInput, index, "property");
}}
onEntityTypeChange={(event: React.FormEvent<HTMLDivElement>, selectedParam: IDropdownOption) => {
entityTypeChange(event, selectedParam, index);
}}
onEntityValueChange={(event, newInput?: string) => {
entityChange(newInput, index, "value");
}}
onEntityTimeValueChange={(event, newInput?: string) => {
entityChange(newInput, index, "time");
}}
/>
);
})}
{userContext.apiType !== "Cassandra" && (
<Stack horizontal onClick={addNewEntity} className="addButtonEntiy">
<Image {...imageProps} src={AddPropertyIcon} alt="Add Entity" />
<Text className="addNewParamStyle">{getAddButtonLabel(userContext.apiType)}</Text>
</Stack>
)}
</div>
{renderPanelFooter()}
</div>
</form>
);
};
const renderPanelFooter = (): JSX.Element => {
return (
<div className="paneFooter">
<div className="leftpanel-okbut">
<input type="submit" onClick={submit} className="genericPaneSubmitBtn" value="Update Entity" />
</div>
</div>
);
};
const onRenderNavigationContent: IRenderFunction<IPanelProps> = () => (
<Stack horizontal {...columnProps}>
<Image {...backImageProps} src={RevertBackIcon} alt="back" onClick={() => setIsEntityValuePanelFalse()} />
<Label>{entityAttributeProperty}</Label>
</Stack>
);
if (isEntityValuePanelOpen) { if (isEntityValuePanelOpen) {
return ( return (
<PanelContainerComponent <Stack style={{ padding: "20px 34px" }}>
headerText="" <Stack horizontal {...columnProps}>
onRenderNavigationContent={onRenderNavigationContent} <Image {...backImageProps} src={RevertBackIcon} alt="back" onClick={() => setIsEntityValuePanelFalse()} />
panelWidth="700px" <Label>{entityAttributeProperty}</Label>
isOpen={true} </Stack>
panelContent={ <TextField
<TextField multiline
multiline rows={5}
rows={5} value={entityAttributeValue}
className="entityValueTextField" onChange={(event, newInput?: string) => {
value={entityAttributeValue} setEntityAttributeValue(newInput);
onChange={(event, newInput?: string) => { entityChange(newInput, selectedRow, "value");
setEntityAttributeValue(newInput); }}
entityChange(newInput, selectedRow, "value"); />
}} </Stack>
/>
}
isConsoleExpanded={false}
/>
); );
} }
const props: RightPaneFormProps = {
formError,
isExecuting,
submitButtonText: "Update",
onSubmit,
};
return ( return (
<PanelContainerComponent <RightPaneForm {...props}>
headerText="Edit Table Entity" <div className="panelMainContent">
panelWidth="700px" {entities.map((entity, index) => {
isOpen={true} return (
panelContent={renderPanelContent()} <TableEntity
isConsoleExpanded={false} key={"" + entity.id + index}
/> isDeleteOptionVisible={entity.isDeleteOptionVisible}
entityTypeLabel={index === 0 && dataTypeLabel}
entityPropertyLabel={index === 0 && attributeNameLabel}
entityValueLabel={index === 0 && attributeValueLabel}
options={userContext.apiType === "Cassandra" ? cassandraOptions : options}
isPropertyTypeDisable={entity.isPropertyTypeDisable}
entityProperty={entity.property}
selectedKey={entity.type}
entityPropertyPlaceHolder={detailedHelp}
entityValuePlaceholder={entity.entityValuePlaceholder}
entityValue={entity.value?.toString()}
isEntityTypeDate={entity.isEntityTypeDate}
entityTimeValue={entity.entityTimeValue}
isEntityValueDisable={entity.isEntityValueDisable}
onEditEntity={() => editEntity(index)}
onSelectDate={(date: Date) => {
entityChange(date, index, "value");
}}
onDeleteEntity={() => deleteEntityAtIndex(index)}
onEntityPropertyChange={(event, newInput?: string) => {
entityChange(newInput, index, "property");
}}
onEntityTypeChange={(event: React.FormEvent<HTMLDivElement>, selectedParam: IDropdownOption) => {
entityTypeChange(event, selectedParam, index);
}}
onEntityValueChange={(event, newInput?: string) => {
entityChange(newInput, index, "value");
}}
onEntityTimeValueChange={(event, newInput?: string) => {
entityChange(newInput, index, "time");
}}
/>
);
})}
{userContext.apiType !== "Cassandra" && (
<Stack horizontal onClick={addNewEntity} className="addButtonEntiy">
<Image {...imageProps} src={AddPropertyIcon} alt="Add Entity" />
<Text className="addNewParamStyle">{getAddButtonLabel(userContext.apiType)}</Text>
</Stack>
)}
</div>
</RightPaneForm>
); );
}; };

View File

@ -80,7 +80,7 @@ export const int64Placeholder = "Enter a signed 64-bit integer, in the range (-2
export const columnProps: Partial<IStackProps> = { export const columnProps: Partial<IStackProps> = {
tokens: { childrenGap: 10 }, tokens: { childrenGap: 10 },
styles: { root: { width: 680, marginBottom: 8 } }, styles: { root: { marginBottom: 8 } },
}; };
// helper functions // helper functions

View File

@ -158,7 +158,8 @@ export default class QueryTablesTab extends TabsBase {
queryTablesTab={this} queryTablesTab={this}
tableEntityListViewModel={this.tableEntityListViewModel()} tableEntityListViewModel={this.tableEntityListViewModel()}
cassandraApiClient={new CassandraAPIDataClient()} cassandraApiClient={new CassandraAPIDataClient()}
/> />,
"700px"
); );
}; };