mirror of
https://github.com/ToolJet/ToolJet
synced 2026-05-23 17:08:34 +00:00
Major bug fixes for table actions
This commit is contained in:
parent
2e7eaa7fe3
commit
c88d98eb0a
4 changed files with 167 additions and 131 deletions
|
|
@ -42,16 +42,18 @@ export const Table = function Table({ id, component, onComponentClick, currentSt
|
|||
<tr onClick={(e) => { e.stopPropagation(); onEvent('onRowClicked', { component, row }); }}>
|
||||
{columns.map((column) => <td>{row[column.name]}</td>)}
|
||||
|
||||
<td>
|
||||
{actions.value.map((action) => (
|
||||
<button
|
||||
class="btn btn-sm m-1 btn-light"
|
||||
onClick={(e) => { e.stopPropagation(); onEvent('onTableActionButtonClicked', { component, data: row, action }); }}
|
||||
>
|
||||
{action.buttonText}
|
||||
</button>
|
||||
))}
|
||||
</td>
|
||||
{actions.value.length > 0 &&
|
||||
<td>
|
||||
{actions.value.map((action) => (
|
||||
<button
|
||||
class="btn btn-sm m-1 btn-light"
|
||||
onClick={(e) => { e.stopPropagation(); onEvent('onTableActionButtonClicked', { component, data: row, action }); }}
|
||||
>
|
||||
{action.buttonText}
|
||||
</button>
|
||||
))}
|
||||
</td>
|
||||
}
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
import React, {useRef, useState} from 'react';
|
||||
|
||||
import React from 'react';
|
||||
import CodeMirror from '@uiw/react-codemirror';
|
||||
import 'codemirror/theme/duotone-light.css';
|
||||
import { renderElement, renderEvent } from '../Utils';
|
||||
import { computeActionName } from '@/_helpers/utils';
|
||||
import SortableList, { SortableItem } from "react-easy-sort";
|
||||
|
|
@ -7,19 +10,34 @@ import OverlayTrigger from 'react-bootstrap/OverlayTrigger';
|
|||
import Popover from 'react-bootstrap/Popover';
|
||||
import { EventSelector } from '../EventSelector';
|
||||
|
||||
export const Table = ({ dataQueries, component, paramUpdated, componentMeta, eventUpdated, eventOptionUpdated }) => {
|
||||
class Table extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
const columns = component.component.definition.properties.columns;
|
||||
const actions = component.component.definition.properties.actions || { value: [] };
|
||||
const { dataQueries, component, paramUpdated, componentMeta, eventUpdated, eventOptionUpdated } = props;
|
||||
|
||||
function onActionButtonPropertyChanged(index, property, value) {
|
||||
let newValues = actions.value;
|
||||
newValues[index][property] = value;
|
||||
|
||||
paramUpdated ({name: 'actions'}, 'value', newValues, 'properties');
|
||||
this.state = {
|
||||
dataQueries, component, paramUpdated, componentMeta, eventUpdated, eventOptionUpdated
|
||||
};
|
||||
}
|
||||
|
||||
function actionButtonEventUpdated(event, value, extraData) {
|
||||
componentDidMount() {
|
||||
const { dataQueries, component, paramUpdated, componentMeta, eventUpdated, eventOptionUpdated } = this.props;
|
||||
|
||||
this.state = {
|
||||
dataQueries, component, paramUpdated, componentMeta, eventUpdated, eventOptionUpdated
|
||||
};
|
||||
}
|
||||
|
||||
onActionButtonPropertyChanged = (index, property, value) => {
|
||||
|
||||
const actions = this.state.component.component.definition.properties.actions;
|
||||
actions.value[index][property] = value;
|
||||
this.props.paramUpdated ({name: 'actions'}, 'value', actions.value, 'properties');
|
||||
}
|
||||
|
||||
actionButtonEventUpdated = (event, value, extraData) => {
|
||||
const actions = this.state.component.component.definition.properties.actions;
|
||||
const actionButton = extraData.actionButton;
|
||||
const index = extraData.index;
|
||||
|
||||
|
|
@ -28,13 +46,13 @@ export const Table = ({ dataQueries, component, paramUpdated, componentMeta, eve
|
|||
actionId: value
|
||||
}
|
||||
|
||||
paramUpdated ({name: 'actions'}, 'value', newValues, 'properties');
|
||||
this.props.paramUpdated ({name: 'actions'}, 'value', newValues, 'properties');
|
||||
}
|
||||
|
||||
function actionButtonEventOptionUpdated(event, option, value, extraData) {
|
||||
actionButtonEventOptionUpdated = (event, option, value, extraData) => {
|
||||
const actions = this.state.component.component.definition.properties.actions;
|
||||
const index = extraData.index;
|
||||
|
||||
|
||||
let newValues = actions.value;
|
||||
const options = newValues[index][event.name].options;
|
||||
|
||||
|
|
@ -43,10 +61,10 @@ export const Table = ({ dataQueries, component, paramUpdated, componentMeta, eve
|
|||
[option]: value
|
||||
}
|
||||
|
||||
paramUpdated ({name: 'actions'}, 'value', newValues, 'properties');
|
||||
this.props.paramUpdated ({name: 'actions'}, 'value', newValues, 'properties');
|
||||
}
|
||||
|
||||
function actionPopOver(action, index) {
|
||||
actionPopOver = (action, index) => {
|
||||
return (
|
||||
<Popover id="popover-basic">
|
||||
<Popover.Title as="h3">{action.name}</Popover.Title>
|
||||
|
|
@ -56,165 +74,183 @@ export const Table = ({ dataQueries, component, paramUpdated, componentMeta, eve
|
|||
<input
|
||||
type="text"
|
||||
class="form-control text-field"
|
||||
onChange={(e) => { e.stopPropagation(); onActionButtonPropertyChanged(index, 'buttonText', e.target.value)}}
|
||||
onChange={(e) => { e.stopPropagation(); this.onActionButtonPropertyChanged(index, 'buttonText', e.target.value); }}
|
||||
value={action.buttonText}
|
||||
/>
|
||||
</div>
|
||||
<EventSelector
|
||||
param={ { name: 'onClick' } }
|
||||
definition={action.onClick}
|
||||
eventUpdated={actionButtonEventUpdated}
|
||||
dataQueries={dataQueries}
|
||||
eventOptionUpdated={actionButtonEventOptionUpdated}
|
||||
eventUpdated={this.actionButtonEventUpdated}
|
||||
dataQueries={this.state.dataQueries}
|
||||
eventOptionUpdated={this.actionButtonEventOptionUpdated}
|
||||
extraData={{ actionButton: action, index: index }} // This data is returned in the callbacks
|
||||
/>
|
||||
<button className="btn btn-sm btn-danger col" onClick={() => this.removeAction(index)}>Remove</button>
|
||||
</Popover.Content>
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
|
||||
const ActionButton = ({ action , index}) => (
|
||||
<OverlayTrigger
|
||||
actionButton(action , index) {
|
||||
return <OverlayTrigger
|
||||
trigger="click"
|
||||
placement="top"
|
||||
overlay={actionPopOver(action, index)}>
|
||||
placement="left"
|
||||
overlay={this.actionPopOver(action, index)}>
|
||||
|
||||
<div className="card p-2 bg-light" role="button">
|
||||
<div className="row bg-light">
|
||||
<div className="col-auto">
|
||||
<div class="text">
|
||||
{action.name}
|
||||
{action.buttonText}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</OverlayTrigger>
|
||||
);
|
||||
};
|
||||
|
||||
function onSortEnd(oldIndex, newIndex) {
|
||||
onSortEnd(oldIndex, newIndex) {
|
||||
const newColumns = arrayMove(columns.value, oldIndex, newIndex);
|
||||
paramUpdated ({name: 'columns'}, 'value', newColumns, 'properties');
|
||||
}
|
||||
|
||||
function addNewColumn() {
|
||||
addNewColumn = () => {
|
||||
const columns = this.state.component.component.definition.properties.columns;
|
||||
const newValue = columns.value;
|
||||
newValue.push({ name: 'new_column'});
|
||||
paramUpdated({name: 'columns'}, 'value', newValue, 'properties');
|
||||
this.props.paramUpdated({name: 'columns'}, 'value', newValue, 'properties');
|
||||
}
|
||||
|
||||
function addNewAction() {
|
||||
addNewAction = () => {
|
||||
const actions = this.state.component.component.definition.properties.actions;
|
||||
const newValue = actions.value;
|
||||
newValue.push({ name: computeActionName(actions), buttonText: 'Button'});
|
||||
paramUpdated({name: 'actions'}, 'value', newValue, 'properties');
|
||||
this.props.paramUpdated({name: 'actions'}, 'value', newValue, 'properties');
|
||||
}
|
||||
|
||||
function onColumnItemChange(index, e) {
|
||||
removeAction = (index) => {
|
||||
const newValue = actions.value;
|
||||
newValue.splice(index, 1);
|
||||
paramUpdated ({name: 'actions'}, 'value', newValue, 'properties');
|
||||
}
|
||||
|
||||
onColumnItemChange = (index, e) => {
|
||||
e.preventDefault();
|
||||
const columns = this.state.component.component.definition.properties.columns;
|
||||
const value = e.target.value;
|
||||
const column = columns.value[index];
|
||||
column.name = value;
|
||||
const newColumns = columns.value;
|
||||
newColumns[index] = column;
|
||||
paramUpdated ({name: 'columns'}, 'value', newColumns, 'properties');
|
||||
this.props.paramUpdated ({name: 'columns'}, 'value', newColumns, 'properties');
|
||||
}
|
||||
|
||||
function removeColumn(index) {
|
||||
removeColumn = (index) => {
|
||||
const columns = this.state.component.component.definition.properties.columns;
|
||||
const newValue = columns.value;
|
||||
newValue.splice(index, 1);
|
||||
paramUpdated ({name: 'columns'}, 'value', newValue, 'properties');
|
||||
this.props.paramUpdated ({name: 'columns'}, 'value', newValue, 'properties');
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="properties-container p-2">
|
||||
{renderElement(component, componentMeta, paramUpdated, dataQueries, 'title', 'properties')}
|
||||
{renderElement(component, componentMeta, paramUpdated, dataQueries, 'data', 'properties')}
|
||||
|
||||
<div className="field mb-2 mt-2">
|
||||
<div class="row g-2">
|
||||
<div class="col-auto">
|
||||
<label class="form-label col pt-1">Columns</label>
|
||||
render() {
|
||||
const { dataQueries, component, paramUpdated, componentMeta, eventUpdated, eventOptionUpdated } = this.state;
|
||||
|
||||
const columns = component.component.definition.properties.columns;
|
||||
const actions = component.component.definition.properties.actions || { value: [] };
|
||||
|
||||
return (
|
||||
<div className="properties-container p-2">
|
||||
{renderElement(component, componentMeta, paramUpdated, dataQueries, 'title', 'properties')}
|
||||
{renderElement(component, componentMeta, paramUpdated, dataQueries, 'data', 'properties')}
|
||||
|
||||
<div className="field mb-2 mt-2">
|
||||
<div class="row g-2">
|
||||
<div class="col-auto">
|
||||
<label class="form-label col pt-1">Columns</label>
|
||||
</div>
|
||||
<div class="col">
|
||||
<button onClick={this.addNewColumn} className="btn btn-sm btn-light col-auto">
|
||||
+ Add column
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<button onClick={addNewColumn} className="btn btn-sm btn-light col-auto">
|
||||
+ Add column
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<SortableList
|
||||
onSortEnd={onSortEnd}
|
||||
className="w-100 p-2"
|
||||
draggedItemClassName="dragged"
|
||||
>
|
||||
{columns.value.map((item, index) => (
|
||||
|
||||
<div className="card p-2 bg-light">
|
||||
<div className="row bg-light">
|
||||
<div className="col-auto">
|
||||
<SortableItem key={item.name}>
|
||||
<img
|
||||
style={{cursor: 'move'}}
|
||||
src="https://www.svgrepo.com/show/20663/menu.svg"
|
||||
width="10"
|
||||
height="10" />
|
||||
</SortableItem>
|
||||
</div>
|
||||
<div className="col-auto">
|
||||
<div class="text">
|
||||
<input
|
||||
type="text"
|
||||
onChange={(e) => onColumnItemChange(index, e)}
|
||||
class="form-control-plaintext form-control-plaintext-sm"
|
||||
value={item.name}
|
||||
/>
|
||||
<div>
|
||||
<SortableList
|
||||
onSortEnd={this.onSortEnd}
|
||||
className="w-100 p-2"
|
||||
draggedItemClassName="dragged"
|
||||
>
|
||||
{columns.value.map((item, index) => (
|
||||
|
||||
<div className="card p-2 bg-light">
|
||||
<div className="row bg-light">
|
||||
<div className="col-auto">
|
||||
<SortableItem key={item.name}>
|
||||
<img
|
||||
style={{cursor: 'move'}}
|
||||
src="https://www.svgrepo.com/show/20663/menu.svg"
|
||||
width="10"
|
||||
height="10" />
|
||||
</SortableItem>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col">
|
||||
<div class="btn btn-sm text-danger" onClick={() => removeColumn(index)}>
|
||||
x
|
||||
<div className="col-auto">
|
||||
<div class="text">
|
||||
<input
|
||||
type="text"
|
||||
onChange={(e) => this.onColumnItemChange(index, e)}
|
||||
class="form-control-plaintext form-control-plaintext-sm"
|
||||
value={item.name}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col">
|
||||
<div class="btn btn-sm text-danger" onClick={() => this.removeColumn(index)}>
|
||||
x
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
))}
|
||||
</SortableList>
|
||||
|
||||
</div>
|
||||
|
||||
<hr></hr>
|
||||
<h4 className="text-muted">Actions</h4>
|
||||
<div className="field mb-2 mt-2">
|
||||
<div class="row g-2">
|
||||
<div class="col">
|
||||
<label class="form-label col pt-1">Actions</label>
|
||||
</div>
|
||||
|
||||
))}
|
||||
</SortableList>
|
||||
|
||||
<div class="col-auto">
|
||||
<button onClick={this.addNewAction} className="btn btn-sm btn-light col-auto">
|
||||
+ Action
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
{actions.value.map((action, index) =>
|
||||
this.actionButton(action, index)
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<hr></hr>
|
||||
|
||||
{renderEvent(component, eventUpdated, dataQueries, eventOptionUpdated, 'onRowClicked')}
|
||||
|
||||
<hr></hr>
|
||||
</div>
|
||||
|
||||
<hr></hr>
|
||||
<h4 className="text-muted">Actions</h4>
|
||||
<div className="field mb-2 mt-2">
|
||||
<div class="row g-2">
|
||||
<div class="col">
|
||||
<label class="form-label col pt-1">Actions</label>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<button onClick={addNewAction} className="btn btn-sm btn-light col-auto">
|
||||
+ Action
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
{actions.value.map((action, index) =>
|
||||
<ActionButton
|
||||
action={action}
|
||||
index={index}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<hr></hr>
|
||||
|
||||
{renderEvent(component, eventUpdated, dataQueries, eventOptionUpdated, 'onRowClicked')}
|
||||
|
||||
<hr></hr>
|
||||
</div>
|
||||
|
||||
{renderElement(component, componentMeta, paramUpdated, dataQueries, 'visible', 'properties')}
|
||||
{renderElement(component, componentMeta, paramUpdated, dataQueries, 'backgroundColor', 'styles')}
|
||||
{renderElement(component, componentMeta, paramUpdated, dataQueries, 'textColor', 'styles')}
|
||||
</div>
|
||||
)
|
||||
{renderElement(component, componentMeta, paramUpdated, dataQueries, 'visible', 'properties')}
|
||||
{renderElement(component, componentMeta, paramUpdated, dataQueries, 'backgroundColor', 'styles')}
|
||||
{renderElement(component, componentMeta, paramUpdated, dataQueries, 'textColor', 'styles')}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export { Table };
|
||||
|
|
|
|||
|
|
@ -5,8 +5,6 @@ export const EventSelector = ({ param, definition, eventUpdated, eventOptionUpda
|
|||
|
||||
console.log('dq', dataQueries);
|
||||
|
||||
debugger
|
||||
|
||||
function onChange(e) {
|
||||
const query = dataQueries.find(query => query.id === e.target.value)
|
||||
eventOptionUpdated(param, 'queryId', query.id, extraData);
|
||||
|
|
@ -26,7 +24,7 @@ export const EventSelector = ({ param, definition, eventUpdated, eventOptionUpda
|
|||
return (
|
||||
<div className="field mb-2 mt-1">
|
||||
<label class="form-label">{param.name}</label>
|
||||
<select onChange={(e) => eventUpdated(param, e.target.value, extraData)} value={definition.actionId} class="form-select" >
|
||||
<select onClick={(e) => { e.stopPropagation(); e.preventDefault() } } onChange={(e) => { e.stopPropagation(); eventUpdated(param, e.target.value, extraData)}} value={definition.actionId} class="form-select" >
|
||||
<option value="none">None</option>
|
||||
{ActionTypes.map((action) => (<option value={action.id}>{action.name}</option>))}
|
||||
</select>
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ export const Inspector = ({ selectedComponent, componentDefinitionChanged, dataQ
|
|||
<span className="p-2">{component.component.name}</span>
|
||||
<CopyToClipboard text={`{{components.${component.component.name}}}`}
|
||||
onCopy={() => toast.success('Reference copied to clipboard', { hideProgressBar: true, position: "bottom-center", })}>
|
||||
<img src="https://www.svgrepo.com/show/86790/copy.svg" width="15" height="15" role="button"></img>
|
||||
<img src="https://www.svgrepo.com/show/86790/copy.svg" width="10" height="10" role="button"></img>
|
||||
</CopyToClipboard>
|
||||
</span>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue