Added dynamic column support in table widget (#5792)

* Created dynamic column in table widget

* Added column data field in table inspector

* Fixed generating previous dynamic column when dynamic column toggle is turned off

* Updated logic to display dynamic column

* Fixed issues on editable & updated logic

* Fixed issue on displaying dynamic column in viewer
This commit is contained in:
Kavin Venkatachalam 2023-03-28 16:25:23 +05:30 committed by GitHub
parent 233f47630c
commit 0c6419464a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 145 additions and 85 deletions

View file

@ -122,6 +122,7 @@ export function Table({
const [tableDetails, dispatch] = useReducer(reducer, initialState());
const [hoverAdded, setHoverAdded] = useState(false);
const [generatedColumn, setGeneratedColumn] = useState([]);
const mergeToTableDetails = (payload) => dispatch(reducerActions.mergeToTableDetails(payload));
const mergeToFilterDetails = (payload) => dispatch(reducerActions.mergeToFilterDetails(payload));
const mounted = useMounted();
@ -194,7 +195,6 @@ export function Table({
const changesToBeSavedAndExposed = { dataUpdates: newDataUpdates, changeSet: newChangeset };
mergeToTableDetails(changesToBeSavedAndExposed);
fireEvent('onCellValueChanged');
return setExposedVariables({ ...changesToBeSavedAndExposed, updatedData: clonedTableData });
}
@ -284,9 +284,15 @@ export function Table({
}
}, [color, darkMode]);
let tableData = [];
let tableData = [],
dynamicColumn = [];
const useDynamicColumn = resolveReferences(component.definition.properties?.useDynamicColumn?.value);
if (currentState) {
tableData = resolveReferences(component.definition.properties.data.value, currentState, []);
dynamicColumn = useDynamicColumn
? resolveReferences(component.definition.properties?.columnData?.value, currentState, []) ?? []
: [];
if (!Array.isArray(tableData)) tableData = [];
}
@ -295,7 +301,7 @@ export function Table({
const tableRef = useRef();
const columnData = generateColumnsData({
columnProperties: component.definition.properties.columns.value,
columnProperties: useDynamicColumn ? generatedColumn : component.definition.properties.columns.value,
columnSizes,
currentState,
handleCellValueChange,
@ -349,8 +355,6 @@ export function Table({
] // Hack: need to fix
);
console.log('columns--- ', columns);
const data = useMemo(
() => tableData,
[
@ -362,15 +366,23 @@ export function Table({
);
useEffect(() => {
if (tableData.length != 0 && component.definition.properties.autogenerateColumns?.value && mode === 'edit') {
autogenerateColumns(
if (
tableData.length != 0 &&
component.definition.properties.autogenerateColumns?.value &&
(useDynamicColumn || mode === 'edit')
) {
const generatedColumnFromData = autogenerateColumns(
tableData,
component.definition.properties.columns.value,
component.definition.properties?.columnDeletionHistory?.value ?? [],
useDynamicColumn,
dynamicColumn,
setProperty
);
useDynamicColumn && setGeneratedColumn(generatedColumnFromData);
}
}, [JSON.stringify(tableData)]);
}, [JSON.stringify(tableData), JSON.stringify(dynamicColumn)]);
const computedStyles = {
// width: `${width}px`,

View file

@ -1,7 +1,30 @@
import _ from 'lodash';
import { v4 as uuidv4 } from 'uuid';
export default function autogenerateColumns(tableData, existingColumns, columnDeletionHistory, setProperty) {
export default function autogenerateColumns(
tableData,
existingColumns,
columnDeletionHistory,
useDynamicColumn,
dynamicColumn = [],
setProperty
) {
if (useDynamicColumn) {
if (dynamicColumn.length > 0 && dynamicColumn[0].name) {
const generatedColumns = dynamicColumn.map((item) => {
return {
...item,
id: uuidv4(),
name: item?.name,
key: item?.key || item?.name,
autogenerated: true,
};
});
return generatedColumns;
}
return [];
}
const firstRow = tableData?.[0] ?? {};
const firstRowWithoutNestedElements = Object.fromEntries(

View file

@ -75,7 +75,8 @@ export default function generateColumnsData({
customRule: column?.customRule,
Cell: function ({ cell, isEditable }) {
const rowChangeSet = changeSet ? changeSet[cell.row.index] : null;
let cellValue = rowChangeSet ? rowChangeSet[column.name] ?? cell.value : cell.value;
let cellValue = rowChangeSet ? rowChangeSet[column.key || column.name] ?? cell.value : cell.value;
const rowData = tableData[cell.row.index];
if (
cell.row.index === 0 &&

View file

@ -920,6 +920,9 @@ class TableComponent extends React.Component {
const enabledSort = component.component.definition.properties.enabledSort?.value
? resolveReferences(component.component.definition.properties.enabledSort?.value, currentState)
: true;
const useDynamicColumn = component.component.definition.properties.useDynamicColumn?.value
? resolveReferences(component.component.definition.properties.useDynamicColumn?.value, currentState) ?? false
: false;
const renderCustomElement = (param, paramType = 'properties') => {
return renderElement(component, componentMeta, paramUpdated, dataQueries, param, paramType, currentState);
@ -946,84 +949,90 @@ class TableComponent extends React.Component {
title: 'Columns',
children: (
<div>
<div className="col-auto text-right mb-3">
<button
data-cy={`button-add-column`}
onClick={this.addNewColumn}
className="btn btn-sm border-0 font-weight-normal padding-2 col-auto color-primary inspector-add-button"
>
{this.props.t('widget.Table.addColumn', '+ Add column')}
</button>
</div>
<DragDropContext
onDragEnd={(result) => {
this.onDragEnd(result);
}}
>
<Droppable droppableId="droppable">
{({ innerRef, droppableProps, placeholder }) => (
<div className="w-100" {...droppableProps} ref={innerRef}>
{columns.value.map((item, index) => {
const resolvedItemName = resolveReferences(item.name, this.state.currentState);
return (
<Draggable key={item.id} draggableId={item.id} index={index}>
{(provided, snapshot) => (
<div
className={`card p-2 column-sort-row mb-1 ${this.props.darkMode ? '' : 'bg-light'}`}
key={index}
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
style={this.getItemStyle(snapshot.isDragging, provided.draggableProps.style)}
>
<OverlayTrigger
trigger="click"
placement="left"
rootClose={this.state.popOverRootCloseBlockers.length === 0}
overlay={this.columnPopover(item, index)}
>
<div key={resolvedItemName}>
<div className={`row ${this.props.darkMode ? '' : 'bg-light'}`} role="button">
<div className="col-auto">
<img
data-cy={`draggable-handle-column-${resolvedItemName}`}
src="../../assets/images/icons/dragicon.svg"
/>
</div>
<div className="col">
<div className="text" data-cy={`column-${resolvedItemName}`}>
{resolvedItemName}
{!useDynamicColumn && (
<>
<div className="col-auto text-right mb-3">
<button
data-cy={`button-add-column`}
onClick={this.addNewColumn}
className="btn btn-sm border-0 font-weight-normal padding-2 col-auto color-primary inspector-add-button"
>
{this.props.t('widget.Table.addColumn', '+ Add column')}
</button>
</div>
<DragDropContext
onDragEnd={(result) => {
this.onDragEnd(result);
}}
>
<Droppable droppableId="droppable">
{({ innerRef, droppableProps, placeholder }) => (
<div className="w-100" {...droppableProps} ref={innerRef}>
{columns.value.map((item, index) => {
const resolvedItemName = resolveReferences(item.name, this.state.currentState);
return (
<Draggable key={item.id} draggableId={item.id} index={index}>
{(provided, snapshot) => (
<div
className={`card p-2 column-sort-row mb-1 ${this.props.darkMode ? '' : 'bg-light'}`}
key={index}
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
style={this.getItemStyle(snapshot.isDragging, provided.draggableProps.style)}
>
<OverlayTrigger
trigger="click"
placement="left"
rootClose={this.state.popOverRootCloseBlockers.length === 0}
overlay={this.columnPopover(item, index)}
>
<div key={resolvedItemName}>
<div className={`row ${this.props.darkMode ? '' : 'bg-light'}`} role="button">
<div className="col-auto">
<img
data-cy={`draggable-handle-column-${resolvedItemName}`}
src="../../assets/images/icons/dragicon.svg"
/>
</div>
<div className="col">
<div className="text" data-cy={`column-${resolvedItemName}`}>
{resolvedItemName}
</div>
</div>
<div className="col-auto">
<svg
data-cy={`button-delete-${resolvedItemName}`}
onClick={() => this.removeColumn(index)}
width="10"
height="16"
viewBox="0 0 10 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M0 13.8333C0 14.75 0.75 15.5 1.66667 15.5H8.33333C9.25 15.5 10 14.75 10 13.8333V3.83333H0V13.8333ZM1.66667 5.5H8.33333V13.8333H1.66667V5.5ZM7.91667 1.33333L7.08333 0.5H2.91667L2.08333 1.33333H0V3H10V1.33333H7.91667Z"
fill="#8092AC"
/>
</svg>
</div>
</div>
</div>
<div className="col-auto">
<svg
data-cy={`button-delete-${resolvedItemName}`}
onClick={() => this.removeColumn(index)}
width="10"
height="16"
viewBox="0 0 10 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M0 13.8333C0 14.75 0.75 15.5 1.66667 15.5H8.33333C9.25 15.5 10 14.75 10 13.8333V3.83333H0V13.8333ZM1.66667 5.5H8.33333V13.8333H1.66667V5.5ZM7.91667 1.33333L7.08333 0.5H2.91667L2.08333 1.33333H0V3H10V1.33333H7.91667Z"
fill="#8092AC"
/>
</svg>
</div>
</div>
</OverlayTrigger>
</div>
</OverlayTrigger>
</div>
)}
</Draggable>
);
})}
{placeholder}
</div>
)}
</Droppable>
</DragDropContext>
)}
</Draggable>
);
})}
{placeholder}
</div>
)}
</Droppable>
</DragDropContext>
</>
)}
<div style={{ marginTop: useDynamicColumn ? '0px' : '30px' }}>{renderCustomElement('useDynamicColumn')}</div>
{useDynamicColumn && <div>{renderCustomElement('columnData')}</div>}
</div>
),
});

View file

@ -134,6 +134,17 @@ export const widgets = [
// },
// },
},
useDynamicColumn: {
type: 'toggle',
displayName: 'Use dynamic column',
validation: {
schema: { type: 'boolean' },
},
},
columnData: {
type: 'code',
displayName: 'Column data',
},
rowsPerPage: {
type: 'code',
displayName: 'Number of rows per page',
@ -400,6 +411,10 @@ export const widgets = [
value:
"{{ [ \n\t\t{ id: 1, name: 'Sarah', email: 'sarah@example.com'}, \n\t\t{ id: 2, name: 'Lisa', email: 'lisa@example.com'}, \n\t\t{ id: 3, name: 'Sam', email: 'sam@example.com'}, \n\t\t{ id: 4, name: 'Jon', email: 'jon@example.com'} \n] }}",
},
useDynamicColumn: { value: '{{false}}' },
columnData: {
value: "{{[{name: 'email', key: 'email'}, {name: 'Full name', key: 'name', isEditable: true}]}}",
},
rowsPerPage: { value: '{{10}}' },
serverSidePagination: { value: '{{false}}' },
enableNextButton: { value: '{{true}}' },