Skip to content

Commit 327e4f8

Browse files
authored
Merge pull request #1114 from lowcoder-org/table-summary-row
Table summary row + Inline add new row
2 parents 64d5bbd + 7f157db commit 327e4f8

21 files changed

+1056
-187
lines changed

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

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export interface CellProps {
3737
candidateStatus?: { text: string; status: StatusType }[];
3838
textOverflow?: boolean;
3939
cellTooltip?: string;
40+
editMode?: string;
4041
onTableEvent?: (eventName: any) => void;
4142
}
4243

@@ -94,17 +95,19 @@ export function EditableCell<T extends JSONValue>(props: EditableCellProps<T>) {
9495
candidateTags,
9596
// tagColors
9697
candidateStatus,
98+
editMode,
9799
onTableEvent,
98100
} = props;
99101
const status = _.isNil(changeValue) ? "normal" : "toSave";
100102
const editable = editViewFn ? props.editable : false;
101103
const { isEditing, setIsEditing } = useContext(TableCellContext);
102104
const value = changeValue ?? baseValue!;
103105
const [tmpValue, setTmpValue] = useState<T | null>(value);
106+
const singleClickEdit = editMode === 'single';
104107

105108
useEffect(() => {
106109
setTmpValue(value);
107-
}, [value]);
110+
}, [JSON.stringify(value)]);
108111

109112
const onChange = useCallback(
110113
(value: T) => {
@@ -125,21 +128,27 @@ export function EditableCell<T extends JSONValue>(props: EditableCellProps<T>) {
125128
if(!_.isEqual(tmpValue, value)) {
126129
onTableEvent?.('columnEdited');
127130
}
128-
}, [dispatch, baseValue, tmpValue]);
131+
}, [dispatch, JSON.stringify(baseValue), JSON.stringify(tmpValue)]);
132+
129133
const editView = useMemo(
130134
() => editViewFn?.({ value, onChange, onChangeEnd }) ?? <></>,
131-
[editViewFn, value, onChange, onChangeEnd]
135+
[editViewFn, JSON.stringify(value), onChange, onChangeEnd]
132136
);
137+
133138
const enterEditFn = useCallback(() => {
134139
if (editable) setIsEditing(true);
135140
}, [editable]);
136141

137142
if (isEditing) {
138143
return (
139144
<>
140-
<BorderDiv />
145+
<BorderDiv className="editing-border" />
141146
<TagsContext.Provider value={candidateTags ?? []}>
142-
<StatusContext.Provider value={candidateStatus ?? []}>{editView}</StatusContext.Provider>
147+
<StatusContext.Provider value={candidateStatus ?? []}>
148+
<div className="editing-wrapper">
149+
{editView}
150+
</div>
151+
</StatusContext.Provider>
143152
</TagsContext.Provider>
144153
</>
145154
);
@@ -151,7 +160,12 @@ export function EditableCell<T extends JSONValue>(props: EditableCellProps<T>) {
151160
>
152161
{status === "toSave" && !isEditing && <EditableChip />}
153162
<CellWrapper tooltipTitle={props.cellTooltip}>
154-
{normalView}
163+
<div
164+
tabIndex={editable ? 0 : -1 }
165+
onFocus={enterEditFn}
166+
>
167+
{normalView}
168+
</div>
155169
</CellWrapper>
156170
{/* overlay on normal view to handle double click for editing */}
157171
{editable && (
@@ -164,7 +178,8 @@ export function EditableCell<T extends JSONValue>(props: EditableCellProps<T>) {
164178
width: '100%',
165179
height: '100%',
166180
}}
167-
onDoubleClick={enterEditFn}
181+
onDoubleClick={!singleClickEdit ? enterEditFn : undefined}
182+
onClick={singleClickEdit ? enterEditFn : undefined}
168183
>
169184
</div>
170185
</CellWrapper>

client/packages/lowcoder/src/comps/comps/selectInputComp/selectCompConstants.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,10 +253,12 @@ export const SelectUIView = (
253253
inputFieldStyle: SelectStyleType;
254254
onChange: (value: any) => void;
255255
dispatch: DispatchType;
256+
autoFocus?: boolean;
256257
}
257258
) => {
258259
return <Select
259260
ref={props.viewRef}
261+
autoFocus={props.autoFocus}
260262
mode={props.mode}
261263
$inputFieldStyle={props.inputFieldStyle}
262264
$style={props.style as SelectStyleType & MultiSelectStyleType}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ const InputNumberWrapper = styled.div`
1414
width: 100%;
1515
border-radius: 0;
1616
background: transparent !important;
17-
padding: 0 !important;
17+
// padding: 0 !important;
1818
box-shadow: none;
1919
2020
input {

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,9 @@ const DatePickerStyled = styled(DatePicker)<{ $open: boolean }>`
4949
top: 0.5px;
5050
display: flex;
5151
align-items: center;
52-
background: #fff;
52+
// background: #fff;
5353
padding: 0 3px;
54-
border-left: 1px solid #d7d9e0;
54+
// border-left: 1px solid #d7d9e0;
5555
}
5656
`;
5757

@@ -183,7 +183,7 @@ export const DateEdit = (props: DateEditProps) => {
183183
nextIcon={<IconNext />}
184184
superNextIcon={<IconSuperNext />}
185185
superPrevIcon={<SuperPrevIcon />}
186-
allowClear={false}
186+
allowClear={true}
187187
variant="borderless"
188188
autoFocus
189189
value={tempValue}
@@ -197,7 +197,9 @@ export const DateEdit = (props: DateEditProps) => {
197197
overflow: "hidden",
198198
}}
199199
onOpenChange={(open) => setPanelOpen(open)}
200-
onChange={(value, dateString) => props.onChange(dateString as string)}
200+
onChange={(value, dateString) => {
201+
props.onChange(dateString as string)
202+
}}
201203
onBlur={() => props.onChangeEnd()}
202204
/>
203205
</Wrapper>

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

Lines changed: 77 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,73 @@ import { StringControl } from "comps/controls/codeControl";
77
import { trans } from "i18n";
88
import { ColumnTypeCompBuilder, ColumnTypeViewFn } from "../columnTypeCompBuilder";
99
import { ColumnValueTooltip } from "../simpleColumnTypeComps";
10+
import { styled } from "styled-components";
11+
12+
const Wrapper = styled.div`
13+
display: inline-flex;
14+
align-items: center;
15+
width: 100%;
16+
height: 100%;
17+
position: absolute;
18+
top: 0;
19+
background: transparent !important;
20+
padding: 8px;
21+
22+
> div {
23+
width: 100%;
24+
height: 100%;
25+
}
26+
27+
.ant-select {
28+
height: 100%;
29+
.ant-select-selector {
30+
padding: 0 7px;
31+
height: 100%;
32+
overflow: hidden;
33+
.ant-select-selection-item {
34+
display: inline-flex;
35+
align-items: center;
36+
padding-right: 24px;
37+
}
38+
}
39+
.ant-select-arrow {
40+
height: calc(100% - 3px);
41+
width: fit-content;
42+
top: 1.5px;
43+
margin-top: 0;
44+
background-color: white;
45+
right: 1.5px;
46+
border-right: 1px solid #d7d9e0;
47+
cursor: pointer;
48+
pointer-events: auto;
49+
svg {
50+
min-width: 18px;
51+
min-height: 18px;
52+
}
53+
&:hover svg path {
54+
fill: #315efb;
55+
}
56+
}
57+
.ant-select-selector .ant-select-selection-search {
58+
left: 7px;
59+
input {
60+
height: 100%;
61+
}
62+
}
63+
&.ant-select-open {
64+
.ant-select-arrow {
65+
border-right: none;
66+
border-left: 1px solid #d7d9e0;
67+
svg g path {
68+
fill: #315efb;
69+
}
70+
}
71+
.ant-select-selection-item {
72+
opacity: 0.4;
73+
}
74+
}
75+
}
76+
`;
1077

1178
const childrenMap = {
1279
text: StringControl,
@@ -28,6 +95,8 @@ const SelectEdit = (props: SelectEditProps) => {
2895
const [currentValue, setCurrentValue] = useState(props.initialValue);
2996
return (
3097
<SelectUIView
98+
autoFocus
99+
allowClear
31100
{...defaultProps}
32101
value={currentValue}
33102
options={props.options}
@@ -67,12 +136,14 @@ export const ColumnSelectComp = (function () {
67136
)
68137
.setEditViewFn((props) => {
69138
return (
70-
<SelectEdit
71-
initialValue={props.value}
72-
options={options}
73-
onChange={props.onChange}
74-
onChangeEnd={props.onChangeEnd}
75-
/>
139+
<Wrapper>
140+
<SelectEdit
141+
initialValue={props.value}
142+
options={options}
143+
onChange={props.onChange}
144+
onChangeEnd={props.onChangeEnd}
145+
/>
146+
</Wrapper>
76147
)
77148
})
78149
.setPropertyViewFn((children) => {

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

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ const StatusEdit = (props: StatusEditPropsType) => {
4848
const defaultStatus = useContext(StatusContext);
4949
const [status, setStatus] = useState(defaultStatus);
5050
const [allOptions, setAllOptions] = useState(BadgeStatusOptions);
51-
const [open, setOpen] = useState(true);
51+
const [open, setOpen] = useState(false);
5252

5353
return (
5454
<Wrapper>
@@ -84,18 +84,20 @@ const StatusEdit = (props: StatusEditPropsType) => {
8484
value,
8585
status: status.find((item) => item.text === value)?.status || "none",
8686
});
87+
setOpen(false)
8788
}}
8889
dropdownRender={(originNode: ReactNode) => (
8990
<DropdownStyled>
9091
<ScrollBar style={{ maxHeight: "256px" }}>{originNode}</ScrollBar>
9192
</DropdownStyled>
9293
)}
9394
dropdownStyle={{ marginTop: "7px", padding: "8px 0 6px 0" }}
94-
onBlur={props.onChangeEnd}
95-
onKeyDown={(e) => {
96-
if (e.key === "Enter") {
97-
props.onChangeEnd();
98-
}
95+
onBlur={() => {
96+
props.onChangeEnd();
97+
setOpen(false);
98+
}}
99+
onFocus={() => {
100+
setOpen(true);
99101
}}
100102
onClick={() => setOpen(!open)}
101103
>

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

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ export const Wrapper = styled.div`
9292
position: absolute;
9393
top: 0;
9494
background: transparent !important;
95+
padding: 8px;
96+
9597
> div {
9698
width: 100%;
9799
height: 100%;
@@ -147,7 +149,7 @@ export const Wrapper = styled.div`
147149
}
148150
}
149151
.ant-tag {
150-
margin-left: 20px;
152+
margin-left: 5px;
151153
}
152154
.ant-tag svg {
153155
margin-right: 4px;
@@ -159,6 +161,10 @@ export const DropdownStyled = styled.div`
159161
padding: 3px 8px;
160162
margin: 0 0 2px 8px;
161163
border-radius: 4px;
164+
165+
&.ant-select-item-option-active {
166+
background-color: #f2f7fc;
167+
}
162168
}
163169
.ant-select-item-option-content {
164170
display: flex;
@@ -193,7 +199,7 @@ const TagEdit = (props: TagEditPropsType) => {
193199
});
194200
return result;
195201
});
196-
const [open, setOpen] = useState(true);
202+
const [open, setOpen] = useState(false);
197203
return (
198204
<Wrapper>
199205
<CustomSelect
@@ -205,6 +211,7 @@ const TagEdit = (props: TagEditPropsType) => {
205211
defaultValue={props.value}
206212
style={{ width: "100%" }}
207213
open={open}
214+
allowClear={true}
208215
suffixIcon={<PackUpIcon />}
209216
onSearch={(value: string) => {
210217
if (defaultTags.findIndex((item) => item.includes(value)) < 0) {
@@ -216,18 +223,20 @@ const TagEdit = (props: TagEditPropsType) => {
216223
}}
217224
onChange={(value: string | string[]) => {
218225
props.onChange(value);
226+
setOpen(false)
219227
}}
220228
dropdownRender={(originNode: ReactNode) => (
221229
<DropdownStyled>
222230
<ScrollBar style={{ maxHeight: "256px" }}>{originNode}</ScrollBar>
223231
</DropdownStyled>
224232
)}
225233
dropdownStyle={{ marginTop: "7px", padding: "8px 0 6px 0" }}
226-
onBlur={props.onChangeEnd}
227-
onKeyDown={(e) => {
228-
if (e.key === "Enter") {
229-
props.onChangeEnd();
230-
}
234+
onFocus={() => {
235+
setOpen(true);
236+
}}
237+
onBlur={() => {
238+
props.onChangeEnd();
239+
setOpen(false);
231240
}}
232241
onClick={() => setOpen(!open)}
233242
>
@@ -259,7 +268,7 @@ export const ColumnTagsComp = (function () {
259268
tagOptionsList = props.tagColors;
260269
let value = props.changeValue ?? getBaseValue(props, dispatch);
261270
value = typeof value === "string" && value.split(",")[1] ? value.split(",") : value;
262-
const tags = _.isArray(value) ? value : [value];
271+
const tags = _.isArray(value) ? value : (value.length ? [value] : []);
263272
const view = tags.map((tag, index) => {
264273
// The actual eval value is of type number or boolean
265274
const tagText = String(tag);

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export const ButtonComp = (function () {
4545
loading={props.loading}
4646
disabled={props.disabled}
4747
$buttonStyle={props.buttonType === "primary" ? style : undefined}
48+
style={{margin: 0}}
4849
>
4950
{/* prevent the button from disappearing */}
5051
{!props.text ? " " : props.text}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy