Skip to content

Commit 185b169

Browse files
authored
Merge pull request #628 from raheeliftikhar5/table-updates
Table enhancements and events
2 parents 8d485a2 + 6fa43f1 commit 185b169

File tree

13 files changed

+182
-82
lines changed

13 files changed

+182
-82
lines changed

client/packages/lowcoder/src/components/table/EditableCell.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export interface CellProps {
3535
candidateTags?: string[];
3636
candidateStatus?: { text: string; status: StatusType }[];
3737
textOverflow?: boolean;
38+
onTableEvent?: (eventName: any) => void;
3839
}
3940

4041
export type CellViewReturn = (props: CellProps) => ReactNode;
@@ -71,6 +72,7 @@ export function EditableCell<T extends JSONValue>(props: EditableCellProps<T>) {
7172
baseValue,
7273
candidateTags,
7374
candidateStatus,
75+
onTableEvent,
7476
} = props;
7577
const status = _.isNil(changeValue) ? "normal" : "toSave";
7678
const editable = editViewFn ? props.editable : false;
@@ -96,6 +98,9 @@ export function EditableCell<T extends JSONValue>(props: EditableCellProps<T>) {
9698
false
9799
)
98100
);
101+
if(!_.isEqual(tmpValue, value)) {
102+
onTableEvent?.('columnEdited');
103+
}
99104
}, [dispatch, baseValue, tmpValue]);
100105
const editView = useMemo(
101106
() => editViewFn?.({ value, onChange, onChangeEnd }) ?? <></>,

client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/ColumnNumberComp.tsx

Lines changed: 69 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,40 @@
1-
import { default as Input } from "antd/es/input";
2-
import { NumberControl, StringControl } from "comps/controls/codeControl";
1+
import { default as InputNumber } from "antd/es/input-number";
2+
import { NumberControl, RangeControl, StringControl } from "comps/controls/codeControl";
33
import { BoolControl } from "comps/controls/boolControl";
44
import { trans } from "i18n";
55
import { ColumnTypeCompBuilder, ColumnTypeViewFn } from "../columnTypeCompBuilder";
66
import { ColumnValueTooltip } from "../simpleColumnTypeComps";
7+
import { withDefault } from "comps/generators";
8+
import styled from "styled-components";
9+
10+
const InputNumberWrapper = styled.div`
11+
.ant-input-number {
12+
width: 100%;
13+
border-radius: 0;
14+
background: transparent !important;
15+
padding: 0 !important;
16+
box-shadow: none;
17+
18+
input {
19+
padding: 0;
20+
border-radius: 0;
21+
}
22+
}
23+
`;
724

825
const childrenMap = {
926
text: NumberControl,
27+
step: withDefault(NumberControl, 1),
28+
precision: RangeControl.closed(0, 20, 0),
1029
float: BoolControl,
1130
prefix: StringControl,
1231
suffix: StringControl,
1332
};
1433

1534
let float = false;
35+
let step = 1;
36+
let precision = 0;
37+
1638
const getBaseValue: ColumnTypeViewFn<typeof childrenMap, number, number> = (
1739
props
1840
) => {
@@ -24,26 +46,35 @@ export const ColumnNumberComp = (function () {
2446
childrenMap,
2547
(props, dispatch) => {
2648
float = props.float;
27-
const value = !float ? Math.floor(props.changeValue ?? getBaseValue(props, dispatch)) : props.changeValue ?? getBaseValue(props, dispatch);
28-
return props.prefix + value + props.suffix;
49+
step = props.step;
50+
precision = props.precision;
51+
const value = props.changeValue ?? getBaseValue(props, dispatch);
52+
let formattedValue: string | number = !float ? Math.floor(value) : value;
53+
if(float) {
54+
formattedValue = formattedValue.toPrecision(precision + 1);
55+
}
56+
return props.prefix + formattedValue + props.suffix;
2957
},
3058
(nodeValue) => nodeValue.text.value,
3159
getBaseValue,
3260
)
3361
.setEditViewFn((props) => {
3462
return (
35-
<Input
36-
type="number"
37-
step={float?"0.01": "1"}
38-
defaultValue={props.value}
39-
autoFocus
40-
bordered={false}
41-
onChange={(e) => {
42-
props.onChange(!float ? Math.floor(e.target.valueAsNumber) : e.target.valueAsNumber);
43-
}}
44-
onBlur={props.onChangeEnd}
45-
onPressEnter={props.onChangeEnd}
46-
/>
63+
<InputNumberWrapper>
64+
<InputNumber
65+
step={step}
66+
defaultValue={props.value}
67+
autoFocus
68+
bordered={false}
69+
onChange={(value) => {
70+
value = value ?? 0;
71+
props.onChange(!float ? Math.floor(value) : value);
72+
}}
73+
precision={float ? precision : 0}
74+
onBlur={props.onChangeEnd}
75+
onPressEnter={props.onChangeEnd}
76+
/>
77+
</InputNumberWrapper>
4778
)})
4879
.setPropertyViewFn((children) => {
4980
return (
@@ -52,17 +83,36 @@ export const ColumnNumberComp = (function () {
5283
label: trans("table.columnValue"),
5384
tooltip: ColumnValueTooltip,
5485
})}
86+
{children.step.propertyView({
87+
label: trans("table.numberStep"),
88+
tooltip: trans("table.numberStepTooltip"),
89+
onFocus: (focused) => {
90+
if(!focused) {
91+
const value = children.step.getView();
92+
const isFloat = children.float.getView();
93+
const newValue = !isFloat ? Math.floor(value) : value;
94+
children.step.dispatchChangeValueAction(String(newValue));
95+
}
96+
}
97+
})}
98+
{float && (
99+
children.precision.propertyView({
100+
label: trans("table.precision"),
101+
})
102+
)}
55103
{children.prefix.propertyView({
56104
label: trans("table.prefix"),
57-
// tooltip: ColumnValueTooltip,
58105
})}
59106
{children.suffix.propertyView({
60107
label: trans("table.suffix"),
61-
// tooltip: ColumnValueTooltip,
62108
})}
63109
{children.float.propertyView({
64110
label: trans("table.float"),
65-
// tooltip: ColumnValueTooltip,
111+
onChange: (isFloat) => {
112+
const value = children.step.getView();
113+
const newValue = !isFloat ? Math.floor(value) : value;
114+
children.step.dispatchChangeValueAction(String(newValue));
115+
}
66116
})}
67117
</>
68118
);

client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnLinksComp.tsx

Lines changed: 36 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import { EllipsisOutlined } from "@ant-design/icons";
2-
import { default as Dropdown} from "antd/es/dropdown";
31
import { default as Menu } from "antd/es/menu";
42
import { ColumnTypeCompBuilder } from "comps/comps/tableComp/column/columnTypeCompBuilder";
53
import { ActionSelectorControlInContext } from "comps/controls/actionSelector/actionSelectorControl";
@@ -12,18 +10,6 @@ import styled from "styled-components";
1210
import { ColumnLink } from "comps/comps/tableComp/column/columnTypeComps/columnLinkComp";
1311
import { LightActiveTextColor, PrimaryColor } from "constants/style";
1412

15-
const LinksWrapper = styled.div`
16-
white-space: nowrap;
17-
18-
> a {
19-
margin-right: 8px;
20-
}
21-
22-
> a:last-child {
23-
margin-right: 0;
24-
}
25-
`;
26-
2713
const MenuLinkWrapper = styled.div`
2814
> a {
2915
color: ${PrimaryColor} !important;
@@ -34,6 +20,22 @@ const MenuLinkWrapper = styled.div`
3420
}
3521
`;
3622

23+
const MenuWrapper = styled.div`
24+
ul {
25+
background: transparent !important;
26+
border-bottom: 0;
27+
28+
li {
29+
padding: 0 10px 0 0 !important;
30+
line-height: normal !important;
31+
32+
&::after {
33+
content: none !important;
34+
}
35+
}
36+
}
37+
`;
38+
3739
const OptionItem = new MultiCompBuilder(
3840
{
3941
label: StringControl,
@@ -69,48 +71,28 @@ export const ColumnLinksComp = (function () {
6971
return new ColumnTypeCompBuilder(
7072
childrenMap,
7173
(props) => {
72-
const menu = props.options.length > 3 && (
73-
<Menu>
74-
{props.options
75-
.filter((o) => !o.hidden)
76-
.slice(3)
77-
.map((option, index) => (
78-
<Menu.Item key={index}>
79-
<MenuLinkWrapper>
80-
<ColumnLink
81-
disabled={option.disabled}
82-
label={option.label}
83-
onClick={option.onClick}
84-
/>
85-
</MenuLinkWrapper>
86-
</Menu.Item>
87-
))}
88-
</Menu>
89-
);
74+
const menuItems = props.options
75+
.filter((o) => !o.hidden)
76+
.map((option, index) => (
77+
{
78+
key: index,
79+
label: (
80+
<MenuLinkWrapper>
81+
<ColumnLink
82+
disabled={option.disabled}
83+
label={option.label}
84+
onClick={option.onClick}
85+
/>
86+
</MenuLinkWrapper>
87+
)
88+
}
89+
));
9090

9191
return (
92-
<LinksWrapper>
93-
{props.options
94-
.filter((o) => !o.hidden)
95-
.slice(0, 3)
96-
.map((option, i) => (
97-
<ColumnLink
98-
key={i}
99-
disabled={option.disabled}
100-
label={option.label}
101-
onClick={option.onClick}
102-
/>
103-
))}
104-
{menu && (
105-
<Dropdown
106-
trigger={["hover"]}
107-
dropdownRender={() => menu}
108-
>
109-
<EllipsisOutlined onClick={(e) => e.preventDefault()} />
110-
</Dropdown>
111-
)}
112-
</LinksWrapper>
113-
);
92+
<MenuWrapper>
93+
<Menu mode="horizontal" items={menuItems} />
94+
</MenuWrapper>
95+
)
11496
},
11597
() => ""
11698
)

client/packages/lowcoder/src/comps/comps/tableComp/column/tableColumnComp.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,6 @@ export function newPrimaryColumn(
323323
title?: string,
324324
isTag?: boolean
325325
): ConstructorToDataType<typeof ColumnComp> {
326-
console.log('newPrimaryColumn', title);
327326
return {
328327
title: title ?? key,
329328
dataIndex: key,

client/packages/lowcoder/src/comps/comps/tableComp/tableComp.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,6 @@ export class TableImplComp extends TableInitComp implements IContainer {
176176

177177
override reduce(action: CompAction): this {
178178
let comp = super.reduce(action);
179-
180179
let dataChanged = false;
181180
if (action.type === CompActionTypes.UPDATE_NODES_V2) {
182181
const nextRowExample = tableDataRowExample(comp.children.data.getView());
@@ -316,10 +315,18 @@ export class TableImplComp extends TableInitComp implements IContainer {
316315
filter: this.children.toolbar.children.filter.node(),
317316
showFilter: this.children.toolbar.children.showFilter.node(),
318317
};
318+
let context = this;
319319
const filteredDataNode = withFunction(fromRecord(nodes), (input) => {
320320
const { data, searchValue, filter, showFilter } = input;
321321
const filteredData = filterData(data, searchValue.value, filter, showFilter.value);
322322
// console.info("filterNode. data: ", data, " filter: ", filter, " filteredData: ", filteredData);
323+
// if data is changed on search then trigger event
324+
if(Boolean(searchValue.value) && data.length !== filteredData.length) {
325+
const onEvent = context.children.onEvent.getView();
326+
setTimeout(() => {
327+
onEvent("dataSearch");
328+
});
329+
}
323330
return filteredData.map((row) => tranToTableRecord(row, row[OB_ROW_ORI_INDEX]));
324331
});
325332
return lastValueIfEqual(this, "filteredDataNode", [filteredDataNode, nodes] as const, (a, b) =>

client/packages/lowcoder/src/comps/comps/tableComp/tableCompView.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,7 @@ export function TableCompView(props: {
680680
dynamicColumn,
681681
dynamicColumnConfig,
682682
columnsAggrData,
683+
onEvent,
683684
),
684685
[
685686
columnViews,
@@ -745,7 +746,10 @@ export function TableCompView(props: {
745746
setLoading
746747
)
747748
}
748-
onDownload={() => onDownload(`${compName}-data`)}
749+
onDownload={() => {
750+
handleChangeEvent("download");
751+
onDownload(`${compName}-data`)
752+
}}
749753
hasChange={hasChange}
750754
onSaveChanges={() => handleChangeEvent("saveChanges")}
751755
onCancelChanges={() => handleChangeEvent("cancelChanges")}
@@ -778,7 +782,11 @@ export function TableCompView(props: {
778782
: "OB_CHILDREN_KEY_PLACEHOLDER",
779783
fixed: "left",
780784
onExpand: (expanded) => {
781-
if(expanded) handleChangeEvent('rowExpand')
785+
if(expanded) {
786+
handleChangeEvent('rowExpand')
787+
} else {
788+
handleChangeEvent('rowShrink')
789+
}
782790
}
783791
}}
784792
rowColorFn={compChildren.rowColor.getView() as any}

client/packages/lowcoder/src/comps/comps/tableComp/tableDynamicColumn.test.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,16 @@ const expectColumn = (
3636
// with dynamic config
3737
const dynamicColumnConfig = comp.children.dynamicColumnConfig.getView();
3838
if (dynamicColumnConfig?.length > 0) {
39+
const onEvent = (eventName: any) => {};
3940
const antdColumns = columnsToAntdFormat(
4041
columnViews,
4142
comp.children.sort.getView(),
4243
comp.children.toolbar.getView().columnSetting,
4344
comp.children.size.getView(),
4445
comp.children.dynamicColumn.getView(),
4546
dynamicColumnConfig,
46-
comp.columnAggrData
47+
comp.columnAggrData,
48+
onEvent,
4749
);
4850
expect(columnViews.length).toBeGreaterThanOrEqual(antdColumns.length);
4951
antdColumns.forEach((column) => {

client/packages/lowcoder/src/comps/comps/tableComp/tableTypes.tsx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,26 @@ export const TableEventOptions = [
7878
value: "rowExpand",
7979
description: trans("table.rowExpand"),
8080
},
81+
{
82+
label: trans("table.rowShrink"),
83+
value: "rowShrink",
84+
description: trans("table.rowShrink"),
85+
},
86+
{
87+
label: trans("table.columnEdited"),
88+
value: "columnEdited",
89+
description: trans("table.columnEdited"),
90+
},
91+
{
92+
label: trans("table.search"),
93+
value: "dataSearch",
94+
description: trans("table.search"),
95+
},
96+
{
97+
label: trans("table.download"),
98+
value: "download",
99+
description: trans("table.download"),
100+
},
81101
{
82102
label: trans("table.filterChange"),
83103
value: "filterChange",

0 commit comments

Comments
 (0)