Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ const TagsControl = codeControl<Array<string> | string>(
{ expectedType: "string | Array<string>", codeType: "JSON" }
);

function getTagColor(tagText : any, tagOptions: any[]) {
const foundOption = tagOptions.find((option: { label: any; }) => option.label === tagText);
function getTagColor(tagText: string, tagOptions: TagOption[]): string | undefined {
const foundOption = tagOptions.find(option => option.label === tagText);
if (foundOption) {
if (foundOption.colorType === "preset") {
return foundOption.presetColor;
Expand All @@ -73,10 +73,10 @@ function getTagColor(tagText : any, tagOptions: any[]) {
return colors[index];
}

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

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

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

// Utility function to process comma-separated tags into individual tags
function processTagItems(tagItems: string[]): string[] {
const result: string[] = [];
tagItems.forEach((item) => {
if (item.split(",")[1]) {
item.split(",").forEach((tag) => result.push(tag));
}
result.push(item);
});
return result;
}

const childrenMap = {
text: TagsControl,
tagColors: ColoredTagOptionControl,
Expand All @@ -128,11 +140,25 @@ const getBaseValue: ColumnTypeViewFn<typeof childrenMap, string | string[], stri
props
) => props.text;

interface TagOption {
label: string;
colorType?: "preset" | "custom";
presetColor?: string;
color?: string;
textColor?: string;
border?: string;
radius?: string;
margin?: string;
padding?: string;
icon?: React.ReactNode;
onEvent?: (eventType: string) => void;
}

type TagEditPropsType = {
value: string | string[];
onChange: (value: string | string[]) => void;
onChangeEnd: () => void;
tagOptions: any[];
tagOptions: TagOption[];
};

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

const TagEdit = React.memo((props: TagEditPropsType) => {
const defaultTags = useContext(TagsContext);
const [tags, setTags] = useState(() => {
const result: string[] = [];
defaultTags.forEach((item) => {
if (item.split(",")[1]) {
item.split(",").forEach((tag) => result.push(tag));
}
result.push(item);
});
return result;
});
const [tags, setTags] = useState(() => processTagItems(defaultTags));
const [open, setOpen] = useState(false);
const mountedRef = useRef(true);

Expand All @@ -268,24 +285,16 @@ const TagEdit = React.memo((props: TagEditPropsType) => {
// Update tags when defaultTags changes
useEffect(() => {
if (!mountedRef.current) return;

const result: string[] = [];
defaultTags.forEach((item) => {
if (item.split(",")[1]) {
item.split(",").forEach((tag) => result.push(tag));
}
result.push(item);
});
setTags(result);
setTags(processTagItems(defaultTags));
}, [defaultTags]);

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

if (defaultTags.findIndex((item) => item.includes(value)) < 0) {
setTags([...defaultTags, value]);
setTags([...processTagItems(defaultTags), value]);
} else {
setTags(defaultTags);
setTags(processTagItems(defaultTags));
}
props.onChange(value);
}, [defaultTags, props.onChange]);
Expand Down Expand Up @@ -426,17 +435,15 @@ export const ColumnTagsComp = (function () {
const tagStyle = getTagStyle(tagText, tagOptions);

return (
<React.Fragment key={`${tag.split(' ').join('_')}-${index}`}>
<TagStyled
color={tagColor}
icon={tagIcon}
key={index}
style={tagStyle}
onClick={(e) => handleTagClick(e, tagText)}
>
{tagText}
</TagStyled>
</React.Fragment>
<TagStyled
key={`${tagText.split(' ').join('_')}-${index}`}
color={tagColor}
icon={tagIcon}
style={tagStyle}
onClick={(e) => handleTagClick(e, tagText)}
>
{tagText}
</TagStyled>
);
});
return (
Expand Down
16 changes: 13 additions & 3 deletions client/packages/lowcoder/src/comps/comps/tableComp/tableComp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -481,7 +481,6 @@ export class TableImplComp extends TableInitComp implements IContainer {
return { ...oriRow, ...changeValues };
})
.value();
// console.info("toUpdateRowsNode. input: ", input, " res: ", res);
return res;
});
}
Expand Down Expand Up @@ -517,14 +516,25 @@ export class TableImplComp extends TableInitComp implements IContainer {
oriDisplayData: this.oriDisplayDataNode(),
withParams: this.children.columns.withParamsNode(),
dataIndexes: this.children.columns.getColumnsNode("dataIndex"),
changeSet: this.changeSetNode(),
};
const resNode = withFunction(fromRecord(nodes), (input) => {
const dataIndexWithParamsDict = _(input.dataIndexes)
.mapValues((dataIndex, idx) => input.withParams[idx])
.mapKeys((withParams, idx) => input.dataIndexes[idx])
.value();
const res = getColumnsAggr(input.oriDisplayData, dataIndexWithParamsDict);
// console.info("columnAggrNode: ", res);

const columnChangeSets: Record<string, Record<string, any>> = {};
_.forEach(input.changeSet, (rowData, rowId) => {
_.forEach(rowData, (value, dataIndex) => {
if (!columnChangeSets[dataIndex]) {
columnChangeSets[dataIndex] = {};
}
columnChangeSets[dataIndex][rowId] = value;
});
});

const res = getColumnsAggr(input.oriDisplayData, dataIndexWithParamsDict, columnChangeSets);
return res;
});
return lastValueIfEqual(this, "columnAggrNode", [resNode, nodes] as const, (a, b) =>
Expand Down
34 changes: 32 additions & 2 deletions client/packages/lowcoder/src/comps/comps/tableComp/tableUtils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -230,17 +230,47 @@ export function getColumnsAggr(
oriDisplayData: JSONObject[],
dataIndexWithParamsDict: NodeToValue<
ReturnType<InstanceType<typeof ColumnListComp>["withParamsNode"]>
>
>,
columnChangeSets?: Record<string, Record<string, any>>
): ColumnsAggrData {
return _.mapValues(dataIndexWithParamsDict, (withParams, dataIndex) => {
const compType = (withParams.wrap() as any).compType;
const res: Record<string, JSONValue> & { compType: string } = { compType };

if (compType === "tag") {
res.uniqueTags = _(oriDisplayData)
const originalTags = _(oriDisplayData)
.map((row) => row[dataIndex]!)
.filter((tag) => !!tag)
.value();

const pendingChanges = columnChangeSets?.[dataIndex] || {};
const pendingTags = _(pendingChanges)
.values()
.filter((value) => !!value)
.value();

const extractTags = (value: any): string[] => {
if (!value) return [];
if (_.isArray(value)) return value.map(String);
if (typeof value === "string") {
// Handle comma-separated tags
if (value.includes(",")) {
return value.split(",").map(tag => tag.trim()).filter(tag => tag);
}
return [value];
}
return [String(value)];
};

const allTags = [
...originalTags.flatMap(extractTags),
...pendingTags.flatMap(extractTags)
];

res.uniqueTags = _(allTags)
.uniq()
.value();

} else if (compType === "badgeStatus") {
res.uniqueStatus = _(oriDisplayData)
.map((row) => {
Expand Down
Loading