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:
committed by
Facebook GitHub Bot
parent
5a2221e6cd
commit
b57612a116
@@ -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>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user