Skip to content

Commit 2664082

Browse files
committed
clone original Table Comp
1 parent 1671585 commit 2664082

39 files changed

+10622
-0
lines changed
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
import { CellProps } from "components/table/EditableCell";
2+
import { DateTimeComp } from "comps/comps/tableComp/column/columnTypeComps/columnDateTimeComp";
3+
import { TimeComp } from "./columnTypeComps/columnTimeComp";
4+
import { ButtonComp } from "comps/comps/tableComp/column/simpleColumnTypeComps";
5+
import { withType } from "comps/generators";
6+
import { trans } from "i18n";
7+
import { Dropdown } from "lowcoder-design/src/components/Dropdown";
8+
import { BooleanComp } from "./columnTypeComps/columnBooleanComp";
9+
import { SwitchComp } from "./columnTypeComps/columnSwitchComp";
10+
import { DateComp } from "./columnTypeComps/columnDateComp";
11+
import { ImageComp } from "./columnTypeComps/columnImgComp";
12+
import { LinkComp } from "./columnTypeComps/columnLinkComp";
13+
import { ColumnLinksComp } from "./columnTypeComps/columnLinksComp";
14+
import { ColumnMarkdownComp } from "./columnTypeComps/columnMarkdownComp";
15+
import { ProgressComp } from "./columnTypeComps/columnProgressComp";
16+
import { RatingComp } from "./columnTypeComps/columnRatingComp";
17+
import { BadgeStatusComp } from "./columnTypeComps/columnStatusComp";
18+
import { ColumnTagsComp } from "./columnTypeComps/columnTagsComp";
19+
import { ColumnSelectComp } from "./columnTypeComps/columnSelectComp";
20+
import { SimpleTextComp } from "./columnTypeComps/simpleTextComp";
21+
import { ColumnNumberComp } from "./columnTypeComps/ColumnNumberComp";
22+
23+
import { ColumnAvatarsComp } from "./columnTypeComps/columnAvatarsComp";
24+
import { ColumnDropdownComp } from "./columnTypeComps/columnDropdownComp";
25+
26+
const actionOptions = [
27+
{
28+
label: trans("table.avatars"),
29+
value: "avatars",
30+
},
31+
{
32+
label: trans("table.text"),
33+
value: "text",
34+
},
35+
{
36+
label: trans("table.number"),
37+
value: "number",
38+
},
39+
{
40+
label: trans("table.link"),
41+
value: "link",
42+
},
43+
{
44+
label: trans("table.links"),
45+
value: "links",
46+
},
47+
{
48+
label: trans("table.tag"),
49+
value: "tag",
50+
},
51+
{
52+
label: trans("table.select"),
53+
value: "select",
54+
},
55+
{
56+
label: trans("table.dropdown"),
57+
value: "dropdown",
58+
},
59+
{
60+
label: trans("table.badgeStatus"),
61+
value: "badgeStatus",
62+
},
63+
{
64+
label: trans("table.button"),
65+
value: "button",
66+
},
67+
{
68+
label: trans("table.image"),
69+
value: "image",
70+
},
71+
{
72+
label: trans("table.time"),
73+
value: "time",
74+
},
75+
76+
{
77+
label: trans("table.date"),
78+
value: "date",
79+
},
80+
{
81+
label: trans("table.dateTime"),
82+
value: "dateTime",
83+
},
84+
{
85+
label: "Markdown",
86+
value: "markdown",
87+
},
88+
{
89+
label: trans("table.boolean"),
90+
value: "boolean",
91+
},
92+
{
93+
label: trans("table.switch"),
94+
value: "switch",
95+
},
96+
{
97+
label: trans("table.rating"),
98+
value: "rating",
99+
},
100+
{
101+
label: trans("table.progress"),
102+
value: "progress",
103+
},
104+
] as const;
105+
106+
export const ColumnTypeCompMap = {
107+
avatars: ColumnAvatarsComp,
108+
text: SimpleTextComp,
109+
number: ColumnNumberComp,
110+
button: ButtonComp,
111+
badgeStatus: BadgeStatusComp,
112+
link: LinkComp,
113+
tag: ColumnTagsComp,
114+
select: ColumnSelectComp,
115+
dropdown: ColumnDropdownComp,
116+
links: ColumnLinksComp,
117+
image: ImageComp,
118+
markdown: ColumnMarkdownComp,
119+
dateTime: DateTimeComp,
120+
boolean: BooleanComp,
121+
switch: SwitchComp,
122+
rating: RatingComp,
123+
progress: ProgressComp,
124+
date: DateComp,
125+
time: TimeComp,
126+
};
127+
128+
type ColumnTypeMapType = typeof ColumnTypeCompMap;
129+
export type ColumnTypeKeys = keyof ColumnTypeMapType;
130+
131+
const TypedColumnTypeComp = withType(ColumnTypeCompMap, "text");
132+
133+
export class ColumnTypeComp extends TypedColumnTypeComp {
134+
override getView() {
135+
const childView = this.children.comp.getView();
136+
return {
137+
view: (cellProps: CellProps) => {
138+
return childView(cellProps);
139+
},
140+
value: this.children.comp.getDisplayValue(),
141+
};
142+
}
143+
144+
private handleTypeChange: (value: ColumnTypeKeys) => void = (value) => {
145+
// Keep the previous text value, some components do not have text, the default value is currentCell
146+
let textRawData = "{{currentCell}}";
147+
if (this.children.comp.children.hasOwnProperty("text")) {
148+
textRawData = (this.children.comp.children as any).text.toJsonValue();
149+
}
150+
this.dispatchChangeValueAction({
151+
compType: value,
152+
comp: { text: textRawData },
153+
} as any);
154+
}
155+
156+
override getPropertyView() {
157+
return (
158+
<>
159+
<Dropdown
160+
showSearch={true}
161+
value={this.children.compType.getView()}
162+
options={actionOptions}
163+
label={trans("table.columnType")}
164+
onChange={this.handleTypeChange}
165+
/>
166+
{this.children.comp.getPropertyView()}
167+
</>
168+
);
169+
}
170+
}
Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
import {
2+
CellViewReturn,
3+
EditableCell,
4+
EditViewFn,
5+
TABLE_EDITABLE_SWITCH_ON,
6+
} from "components/table/EditableCell";
7+
import { stateComp } from "comps/generators";
8+
import {
9+
MultiCompBuilder,
10+
PropertyViewFnTypeForComp,
11+
ToConstructor,
12+
ViewFnTypeForComp,
13+
} from "comps/generators/multi";
14+
import _ from "lodash";
15+
import {
16+
CompConstructor,
17+
ConstructorToNodeType,
18+
fromRecord,
19+
NodeToValue,
20+
RecordConstructorToComp,
21+
withFunction,
22+
} from "lowcoder-core";
23+
import { ReactNode } from "react";
24+
import { JSONValue } from "util/jsonTypes";
25+
26+
export const __COLUMN_DISPLAY_VALUE_FN = "__COLUMN_DISPLAY_VALUE_FN";
27+
28+
type RecordConstructorToNodeValue<T> = {
29+
[K in keyof T]: NodeToValue<ConstructorToNodeType<T[K]>>;
30+
};
31+
32+
type ViewValueFnType<ChildrenCtorMap extends Record<string, CompConstructor<unknown>>> = (
33+
nodeValue: RecordConstructorToNodeValue<ChildrenCtorMap>
34+
) => JSONValue;
35+
36+
type NewChildrenCtorMap<ChildrenCtorMap, T extends JSONValue> = ChildrenCtorMap & {
37+
changeValue: ReturnType<typeof stateComp<T | null>>;
38+
};
39+
40+
export type ColumnTypeViewFn<ChildrenCtroMap, T extends JSONValue, ViewReturn> = ViewFnTypeForComp<
41+
ViewReturn,
42+
RecordConstructorToComp<NewChildrenCtorMap<ChildrenCtroMap, T>>
43+
>;
44+
45+
export class ColumnTypeCompBuilder<
46+
ChildrenCtorMap extends Record<string, CompConstructor<unknown>>,
47+
T extends JSONValue = JSONValue
48+
> {
49+
private childrenMap: NewChildrenCtorMap<ChildrenCtorMap, T>;
50+
private propertyViewFn?: PropertyViewFnTypeForComp<
51+
RecordConstructorToComp<NewChildrenCtorMap<ChildrenCtorMap, T>>
52+
>;
53+
private stylePropertyViewFn?: PropertyViewFnTypeForComp<
54+
RecordConstructorToComp<NewChildrenCtorMap<ChildrenCtorMap, T>>
55+
>;
56+
private editViewFn?: EditViewFn<T>;
57+
private cleanupFunctions: (() => void)[] = [];
58+
59+
constructor(
60+
childrenMap: ChildrenCtorMap,
61+
private viewFn: ColumnTypeViewFn<ChildrenCtorMap, T, ReactNode>,
62+
private displayValueFn: ViewValueFnType<ChildrenCtorMap>,
63+
private baseValueFn?: ColumnTypeViewFn<ChildrenCtorMap, T, T>
64+
) {
65+
this.childrenMap = { ...childrenMap, changeValue: stateComp<T | null>(null) };
66+
}
67+
68+
setEditViewFn(editViewFn: NonNullable<typeof this.editViewFn>) {
69+
if (TABLE_EDITABLE_SWITCH_ON) {
70+
this.editViewFn = editViewFn;
71+
}
72+
return this;
73+
}
74+
75+
setPropertyViewFn(
76+
propertyViewFn: PropertyViewFnTypeForComp<
77+
RecordConstructorToComp<NewChildrenCtorMap<ChildrenCtorMap, T>>
78+
>
79+
) {
80+
this.propertyViewFn = propertyViewFn;
81+
return this;
82+
}
83+
84+
setStylePropertyViewFn(
85+
stylePropertyViewFn: PropertyViewFnTypeForComp<
86+
RecordConstructorToComp<NewChildrenCtorMap<ChildrenCtorMap, T>>
87+
>
88+
) {
89+
this.stylePropertyViewFn = stylePropertyViewFn;
90+
return this;
91+
}
92+
93+
build() {
94+
if (!this.propertyViewFn) {
95+
throw new Error("need property view fn");
96+
}
97+
98+
// Memoize the props processing
99+
const memoizedViewFn = _.memoize(
100+
(props: any, dispatch: any) => {
101+
const baseValue = this.baseValueFn?.(props, dispatch);
102+
const normalView = this.viewFn(props, dispatch);
103+
return (
104+
<EditableCell<T>
105+
{...props}
106+
normalView={normalView}
107+
dispatch={dispatch}
108+
baseValue={baseValue}
109+
changeValue={props.changeValue as any}
110+
editViewFn={this.editViewFn}
111+
/>
112+
);
113+
},
114+
(props) => {
115+
let safeOptions = [];
116+
let safeAvatars = [];
117+
if(props.options) {
118+
safeOptions = props.options.map((option: Record<string, any>) => {
119+
const {prefixIcon, suffixIcon, ...safeOption} = option;
120+
return safeOption;
121+
})
122+
}
123+
if(props.avatars) {
124+
safeAvatars = props.avatars.map((avatar: Record<string, any>) => {
125+
const {AvatarIcon, ...safeAvatar} = avatar;
126+
return safeAvatar;
127+
})
128+
}
129+
const {
130+
prefixIcon,
131+
suffixIcon,
132+
iconFalse,
133+
iconTrue,
134+
iconNull,
135+
tagColors,
136+
options,
137+
avatars,
138+
...safeProps
139+
} = props;
140+
return safeProps;
141+
}
142+
);
143+
144+
const viewFn: ColumnTypeViewFn<ChildrenCtorMap, T, CellViewReturn> =
145+
(props, dispatch): CellViewReturn =>
146+
(cellProps) => memoizedViewFn({ ...props, ...cellProps } as any, dispatch);
147+
148+
const ColumnTypeCompTmp = new MultiCompBuilder(
149+
this.childrenMap as ToConstructor<
150+
RecordConstructorToComp<NewChildrenCtorMap<ChildrenCtorMap, T>>
151+
>,
152+
viewFn
153+
)
154+
.setPropertyViewFn(this.propertyViewFn)
155+
.build();
156+
157+
const displayValueFn = this.displayValueFn;
158+
const editViewFn = this.editViewFn;
159+
160+
return class extends ColumnTypeCompTmp {
161+
// table cell data
162+
private _displayValue: JSONValue = null;
163+
private cleanupFunctions: (() => void)[] = [];
164+
constructor(props: any) {
165+
super(props);
166+
this.cleanupFunctions.push(() => {
167+
this._displayValue = null;
168+
memoizedViewFn.cache.clear?.();
169+
});
170+
}
171+
172+
override extraNode() {
173+
return {
174+
node: {
175+
[__COLUMN_DISPLAY_VALUE_FN]: withFunction(
176+
fromRecord(this.childrenNode()),
177+
() => displayValueFn
178+
),
179+
},
180+
updateNodeFields: (value: any) => {
181+
const displayValueFunc = value[__COLUMN_DISPLAY_VALUE_FN];
182+
this._displayValue = displayValueFunc(value);
183+
return { displayValue: this._displayValue };
184+
},
185+
};
186+
}
187+
188+
/**
189+
* Get the data actually displayed by the table cell
190+
*/
191+
getDisplayValue() {
192+
return this._displayValue;
193+
}
194+
195+
static canBeEditable() {
196+
return !_.isNil(editViewFn);
197+
}
198+
199+
componentWillUnmount() {
200+
// Cleanup all registered cleanup functions
201+
this.cleanupFunctions.forEach(cleanup => cleanup());
202+
this.cleanupFunctions = [];
203+
}
204+
};
205+
}
206+
207+
// Cleanup method to be called when the builder is no longer needed
208+
cleanup() {
209+
this.cleanupFunctions.forEach(cleanup => cleanup());
210+
this.cleanupFunctions = [];
211+
}
212+
}

0 commit comments

Comments
 (0)