Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit fa2d9e4

Browse files
Merge pull request #2023 from iamfaran/feat/table-tags
[Feat]: add new pending tags in suggestions for Table Tags Column
2 parents 242bbf4 + 90b1ac0 commit fa2d9e4

File tree

3 files changed

+91
-44
lines changed

3 files changed

+91
-44
lines changed

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

Lines changed: 46 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@ const TagsControl = codeControl<Array<string> | string>(
5757
{ expectedType: "string | Array<string>", codeType: "JSON" }
5858
);
5959

60-
function getTagColor(tagText : any, tagOptions: any[]) {
61-
const foundOption = tagOptions.find((option: {label: any;}) => option.label === tagText);
60+
function getTagColor(tagText: string, tagOptions: TagOption[]): string|undefined {
61+
const foundOption = tagOptions.find(option => option.label === tagText);
6262
if (foundOption) {
6363
if (foundOption.colorType === "preset") {
6464
return foundOption.presetColor;
@@ -73,10 +73,10 @@ function getTagColor(tagText : any, tagOptions: any[]) {
7373
return colors[index];
7474
}
7575

76-
function getTagStyle(tagText: any, tagOptions: any[]) {
77-
const foundOption = tagOptions.find((option: {label: any;}) => option.label === tagText);
76+
function getTagStyle(tagText: string, tagOptions: TagOption[]): React.CSSProperties {
77+
const foundOption = tagOptions.find(option => option.label === tagText);
7878
if (foundOption) {
79-
const style: any = {};
79+
const style: React.CSSProperties = {};
8080

8181
// Handle color styling
8282
if (foundOption.colorType === "custom") {
@@ -113,11 +113,23 @@ function getTagStyle(tagText: any, tagOptions: any[]) {
113113
return {};
114114
}
115115

116-
function getTagIcon(tagText: any, tagOptions: any[]) {
116+
function getTagIcon(tagText: string, tagOptions: TagOption[]): React.ReactNode|undefined {
117117
const foundOption = tagOptions.find(option => option.label === tagText);
118118
return foundOption ? foundOption.icon : undefined;
119119
}
120120

121+
// Utility function to process comma-separated tags into individual tags
122+
function processTagItems(tagItems: string[]): string[] {
123+
const result: string[] = [];
124+
tagItems.forEach((item) => {
125+
if (item.split(",")[1]) {
126+
item.split(",").forEach((tag) => result.push(tag));
127+
}
128+
result.push(item);
129+
});
130+
return result;
131+
}
132+
121133
const childrenMap = {
122134
text: TagsControl,
123135
tagColors: ColoredTagOptionControl,
@@ -128,11 +140,25 @@ const getBaseValue: ColumnTypeViewFn<typeof childrenMap, string | string[], stri
128140
props
129141
) => props.text;
130142

143+
interface TagOption {
144+
label: string;
145+
colorType?: "preset" | "custom";
146+
presetColor?: string;
147+
color?: string;
148+
textColor?: string;
149+
border?: string;
150+
radius?: string;
151+
margin?: string;
152+
padding?: string;
153+
icon?: React.ReactNode;
154+
onEvent?: (eventType: string) => void;
155+
}
156+
131157
type TagEditPropsType = {
132158
value: string | string[];
133159
onChange: (value: string | string[]) => void;
134160
onChangeEnd: () => void;
135-
tagOptions: any[];
161+
tagOptions: TagOption[];
136162
};
137163

138164
export const Wrapper = styled.div`
@@ -240,16 +266,7 @@ export const TagStyled = styled(Tag)`
240266

241267
const TagEdit = React.memo((props: TagEditPropsType) => {
242268
const defaultTags = useContext(TagsContext);
243-
const [tags, setTags] = useState(() => {
244-
const result: string[] = [];
245-
defaultTags.forEach((item) => {
246-
if (item.split(",")[1]) {
247-
item.split(",").forEach((tag) => result.push(tag));
248-
}
249-
result.push(item);
250-
});
251-
return result;
252-
});
269+
const [tags, setTags] = useState(() => processTagItems(defaultTags));
253270
const [open, setOpen] = useState(false);
254271
const mountedRef = useRef(true);
255272

@@ -268,24 +285,16 @@ const TagEdit = React.memo((props: TagEditPropsType) => {
268285
// Update tags when defaultTags changes
269286
useEffect(() => {
270287
if (!mountedRef.current) return;
271-
272-
const result: string[] = [];
273-
defaultTags.forEach((item) => {
274-
if (item.split(",")[1]) {
275-
item.split(",").forEach((tag) => result.push(tag));
276-
}
277-
result.push(item);
278-
});
279-
setTags(result);
288+
setTags(processTagItems(defaultTags));
280289
}, [defaultTags]);
281290

282291
const handleSearch = useCallback((value: string) => {
283292
if (!mountedRef.current) return;
284293

285294
if (defaultTags.findIndex((item) => item.includes(value)) < 0) {
286-
setTags([...defaultTags, value]);
295+
setTags([...processTagItems(defaultTags), value]);
287296
} else {
288-
setTags(defaultTags);
297+
setTags(processTagItems(defaultTags));
289298
}
290299
props.onChange(value);
291300
}, [defaultTags, props.onChange]);
@@ -426,17 +435,15 @@ export const ColumnTagsComp = (function () {
426435
const tagStyle = getTagStyle(tagText, tagOptions);
427436

428437
return (
429-
<React.Fragment key={`${tag.split(' ').join('_')}-${index}`}>
430-
<TagStyled
431-
color={tagColor}
432-
icon={tagIcon}
433-
key={index}
434-
style={tagStyle}
435-
onClick={(e) => handleTagClick(e, tagText)}
436-
>
437-
{tagText}
438-
</TagStyled>
439-
</React.Fragment>
438+
<TagStyled
439+
key={`${tagText.split(' ').join('_')}-${index}`}
440+
color={tagColor}
441+
icon={tagIcon}
442+
style={tagStyle}
443+
onClick={(e) => handleTagClick(e, tagText)}
444+
>
445+
{tagText}
446+
</TagStyled>
440447
);
441448
});
442449
return (

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

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -481,7 +481,6 @@ export class TableImplComp extends TableInitComp implements IContainer {
481481
return { ...oriRow, ...changeValues };
482482
})
483483
.value();
484-
// console.info("toUpdateRowsNode. input: ", input, " res: ", res);
485484
return res;
486485
});
487486
}
@@ -517,14 +516,25 @@ export class TableImplComp extends TableInitComp implements IContainer {
517516
oriDisplayData: this.oriDisplayDataNode(),
518517
withParams: this.children.columns.withParamsNode(),
519518
dataIndexes: this.children.columns.getColumnsNode("dataIndex"),
519+
changeSet: this.changeSetNode(),
520520
};
521521
const resNode = withFunction(fromRecord(nodes), (input) => {
522522
const dataIndexWithParamsDict = _(input.dataIndexes)
523523
.mapValues((dataIndex, idx) => input.withParams[idx])
524524
.mapKeys((withParams, idx) => input.dataIndexes[idx])
525525
.value();
526-
const res = getColumnsAggr(input.oriDisplayData, dataIndexWithParamsDict);
527-
// console.info("columnAggrNode: ", res);
526+
527+
const columnChangeSets: Record<string, Record<string, any>> = {};
528+
_.forEach(input.changeSet, (rowData, rowId) => {
529+
_.forEach(rowData, (value, dataIndex) => {
530+
if (!columnChangeSets[dataIndex]) {
531+
columnChangeSets[dataIndex] = {};
532+
}
533+
columnChangeSets[dataIndex][rowId] = value;
534+
});
535+
});
536+
537+
const res = getColumnsAggr(input.oriDisplayData, dataIndexWithParamsDict, columnChangeSets);
528538
return res;
529539
});
530540
return lastValueIfEqual(this, "columnAggrNode", [resNode, nodes] as const, (a, b) =>

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

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -230,17 +230,47 @@ export function getColumnsAggr(
230230
oriDisplayData: JSONObject[],
231231
dataIndexWithParamsDict: NodeToValue<
232232
ReturnType<InstanceType<typeof ColumnListComp>["withParamsNode"]>
233-
>
233+
>,
234+
columnChangeSets?: Record<string, Record<string, any>>
234235
): ColumnsAggrData {
235236
return _.mapValues(dataIndexWithParamsDict, (withParams, dataIndex) => {
236237
const compType = (withParams.wrap() as any).compType;
237238
const res: Record<string, JSONValue> & { compType: string } = { compType };
239+
238240
if (compType === "tag") {
239-
res.uniqueTags = _(oriDisplayData)
241+
constoriginalTags = _(oriDisplayData)
240242
.map((row) => row[dataIndex]!)
241243
.filter((tag) => !!tag)
244+
.value();
245+
246+
const pendingChanges = columnChangeSets?.[dataIndex] || {};
247+
const pendingTags = _(pendingChanges)
248+
.values()
249+
.filter((value) => !!value)
250+
.value();
251+
252+
const extractTags = (value: any): string[] => {
253+
if (!value) return [];
254+
if (_.isArray(value)) return value.map(String);
255+
if (typeof value === "string") {
256+
// Handle comma-separated tags
257+
if (value.includes(",")) {
258+
return value.split(",").map(tag => tag.trim()).filter(tag => tag);
259+
}
260+
return [value];
261+
}
262+
return [String(value)];
263+
};
264+
265+
const allTags = [
266+
...originalTags.flatMap(extractTags),
267+
...pendingTags.flatMap(extractTags)
268+
];
269+
270+
res.uniqueTags = _(allTags)
242271
.uniq()
243272
.value();
273+
244274
} else if (compType === "badgeStatus") {
245275
res.uniqueStatus = _(oriDisplayData)
246276
.map((row) => {

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /