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 * @format
*/ */
import React, {useMemo} from 'react'; import React, {useMemo, useState, useEffect, useReducer} from 'react';
import { import {
Text, Text,
Input,
DetailSidebar, DetailSidebar,
Panel, Panel,
ManagedTable, ManagedTable,
@@ -17,14 +18,29 @@ import {
TableBodyRow, TableBodyRow,
ManagedDataInspector, ManagedDataInspector,
Value, Value,
valueToNullableString,
renderValue, renderValue,
Layout,
Button,
styled,
produce,
} from 'flipper'; } from 'flipper';
type DatabaseDetailSidebarProps = { type DatabaseDetailSidebarProps = {
columnLabels: Array<string>; columnLabels: Array<string>;
columnValues: Array<Value>; 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 { function sidebarRows(labels: Array<string>, values: Array<Value>): TableRows {
return labels.map((label, idx) => buildSidebarRow(label, values[idx])); 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 = { const cols = {
col: { col: {
value: 'Column', value: 'Column',
@@ -66,14 +132,41 @@ const colSizes = {
val: 'flex', 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( export default React.memo(function DatabaseDetailSidebar(
props: DatabaseDetailSidebarProps, props: DatabaseDetailSidebarProps,
) { ) {
const {columnLabels, columnValues} = props; const [editing, setEditing] = useState(false);
const rows = useMemo(() => sidebarRows(columnLabels, columnValues), [ const [rowState, rowDispatch] = useReducer(rowStateReducer, {
columnLabels, changes: {},
columnValues, 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 ( return (
<DetailSidebar> <DetailSidebar>
<Panel <Panel
@@ -81,6 +174,27 @@ export default React.memo(function DatabaseDetailSidebar(
floating={false} floating={false}
collapsable={true} collapsable={true}
padded={false}> padded={false}>
<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 <ManagedTable
highlightableRows={false} highlightableRows={false}
columnSizes={colSizes} columnSizes={colSizes}
@@ -91,6 +205,7 @@ export default React.memo(function DatabaseDetailSidebar(
zebra={false} zebra={false}
rows={rows} rows={rows}
/> />
</Layout.Top>
</Panel> </Panel>
</DetailSidebar> </DetailSidebar>
); );

View File

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