Allow to Edit Cell in Detail Sidebar

Summary: This diff adds edit button to detail sidebar to allow user to edit column he/she wants to

Reviewed By: jknoxville

Differential Revision: D21788243

fbshipit-source-id: 4bdcef62114d5a6282ba85bc2bd1b5d039322e50
This commit is contained in:
Chaiwat Ekkaewnumchai
2020-06-02 01:44:21 -07:00
committed by Facebook GitHub Bot
parent 5a2221e6cd
commit b57612a116
2 changed files with 132 additions and 16 deletions

View File

@@ -7,9 +7,10 @@
* @format
*/
import React, {useMemo} from 'react';
import React, {useMemo, useState, useEffect, useReducer} from 'react';
import {
Text,
Input,
DetailSidebar,
Panel,
ManagedTable,
@@ -17,14 +18,29 @@ import {
TableBodyRow,
ManagedDataInspector,
Value,
valueToNullableString,
renderValue,
Layout,
Button,
styled,
produce,
} from 'flipper';
type DatabaseDetailSidebarProps = {
columnLabels: Array<string>;
columnValues: Array<Value>;
onSave?: ((changes: {[key: string]: string | null}) => void) | undefined;
};
const EditTriggerSection = styled.div({
display: 'flex',
justifyContent: 'flex-end',
width: '100%',
paddingTop: '3px',
paddingBottom: '3px',
paddingRight: '10px',
});
function sidebarRows(labels: Array<string>, values: Array<Value>): TableRows {
return labels.map((label, idx) => buildSidebarRow(label, values[idx]));
}
@@ -51,6 +67,56 @@ function buildSidebarRow(key: string, val: Value): TableBodyRow {
};
}
function sidebarEditableRows(
labels: Array<string>,
values: Array<Value>,
rowDispatch: (action: RowAction) => void,
): TableRows {
return labels.map((label, idx) =>
buildSidebarEditableRow(
label,
valueToNullableString(values[idx]),
(value: string | null) => rowDispatch({type: 'set', key: label, value}),
),
);
}
function buildSidebarEditableRow(
key: string,
value: string | null,
onUpdateValue: (value: string | null) => void,
): TableBodyRow {
return {
columns: {
col: {value: <Text>{key}</Text>},
val: {
value: <EditField initialValue={value} onUpdateValue={onUpdateValue} />,
},
},
key: key,
};
}
const EditField = React.memo(
(props: {
initialValue: string | null;
onUpdateValue: (value: string | null) => void;
}) => {
const {initialValue, onUpdateValue} = props;
const [value, setValue] = useState<string | null>(initialValue);
useEffect(() => setValue(initialValue), [initialValue]);
return (
<Input
value={value || ''}
onChange={(e) => {
setValue(e.target.value);
onUpdateValue(e.target.value);
}}
placeholder={value === null ? 'NULL' : undefined}
/>
);
},
);
const cols = {
col: {
value: 'Column',
@@ -66,14 +132,41 @@ const colSizes = {
val: 'flex',
};
type RowState = {changes: {[key: string]: string | null}; updated: boolean};
type RowAction =
| {type: 'set'; key: string; value: string | null}
| {type: 'reset'};
const rowStateReducer = produce((draftState: RowState, action: RowAction) => {
switch (action.type) {
case 'set':
draftState.changes[action.key] = action.value;
draftState.updated = true;
return;
case 'reset':
draftState.changes = {};
draftState.updated = false;
return;
}
});
export default React.memo(function DatabaseDetailSidebar(
props: DatabaseDetailSidebarProps,
) {
const {columnLabels, columnValues} = props;
const rows = useMemo(() => sidebarRows(columnLabels, columnValues), [
columnLabels,
columnValues,
]);
const [editing, setEditing] = useState(false);
const [rowState, rowDispatch] = useReducer(rowStateReducer, {
changes: {},
updated: false,
});
const {columnLabels, columnValues, onSave} = props;
useEffect(() => rowDispatch({type: 'reset'}), [columnLabels, columnValues]);
const rows = useMemo(
() =>
editing
? sidebarEditableRows(columnLabels, columnValues, rowDispatch)
: sidebarRows(columnLabels, columnValues),
[columnLabels, columnValues, editing],
);
return (
<DetailSidebar>
<Panel
@@ -81,16 +174,38 @@ export default React.memo(function DatabaseDetailSidebar(
floating={false}
collapsable={true}
padded={false}>
<ManagedTable
highlightableRows={false}
columnSizes={colSizes}
multiline={true}
columns={cols}
autoHeight={true}
floating={false}
zebra={false}
rows={rows}
/>
<Layout.Top>
{onSave && (
<EditTriggerSection>
{editing ? (
<>
<Button
disabled={!rowState.updated}
onClick={() => {
console.log(rowState);
onSave(rowState.changes);
setEditing(false);
}}>
Save
</Button>
<Button onClick={() => setEditing(false)}>Close</Button>
</>
) : (
<Button onClick={() => setEditing(true)}>Edit</Button>
)}
</EditTriggerSection>
)}
<ManagedTable
highlightableRows={false}
columnSizes={colSizes}
multiline={true}
columns={cols}
autoHeight={true}
floating={false}
zebra={false}
rows={rows}
/>
</Layout.Top>
</Panel>
</DetailSidebar>
);

View File

@@ -1127,6 +1127,7 @@ export default class DatabasesPlugin extends FlipperPlugin<
<DatabaseDetailSidebar
columnLabels={page.columns}
columnValues={page.rows[page.highlightedRows[0]]}
onSave={this.onRowEdited.bind(this)}
/>
)}
</FlexRow>