feat: add clusteredColumnChart, clusteredBarChart, textSlicer, listSlicer (v3.5.0)

This commit is contained in:
MinaSaad1 2026-04-01 20:45:16 +02:00
parent 489e8b2dbb
commit 8362335866
8 changed files with 160 additions and 0 deletions

View file

@ -65,6 +65,11 @@ SUPPORTED_VISUAL_TYPES: frozenset[str] = frozenset({
# v3.4.0 additions
"cardVisual",
"actionButton",
# v3.5.0 additions (confirmed from HR Analysis Desktop export)
"clusteredColumnChart",
"clusteredBarChart",
"textSlicer",
"listSlicer",
})
# Mapping from user-friendly names to PBIR visualType identifiers
@ -109,6 +114,13 @@ VISUAL_TYPE_ALIASES: dict[str, str] = {
"modern_card": "cardVisual",
"action_button": "actionButton",
"button": "actionButton",
# v3.5.0 additions
"clustered_column": "clusteredColumnChart",
"clustered_column_chart": "clusteredColumnChart",
"clustered_bar": "clusteredBarChart",
"clustered_bar_chart": "clusteredBarChart",
"text_slicer": "textSlicer",
"list_slicer": "listSlicer",
}

View file

@ -71,6 +71,11 @@ VISUAL_DATA_ROLES: dict[str, list[str]] = {
# v3.4.0 additions
"cardVisual": ["Data"],
"actionButton": [],
# v3.5.0 additions
"clusteredColumnChart": ["Category", "Y", "Legend"],
"clusteredBarChart": ["Category", "Y", "Legend"],
"textSlicer": ["Values"],
"listSlicer": ["Values"],
}
# Roles that should default to Measure references (not Column)
@ -118,6 +123,11 @@ ROLE_ALIASES: dict[str, dict[str, str]] = {
# v3.4.0 additions
"cardVisual": {"field": "Data", "value": "Data"},
"actionButton": {},
# v3.5.0 additions
"clusteredColumnChart": {"category": "Category", "value": "Y", "legend": "Legend"},
"clusteredBarChart": {"category": "Category", "value": "Y", "legend": "Legend"},
"textSlicer": {"value": "Values", "field": "Values"},
"listSlicer": {"value": "Values", "field": "Values"},
}
@ -194,6 +204,11 @@ DEFAULT_SIZES: dict[str, tuple[float, float]] = {
# v3.4.0 additions -- sizes from real Desktop export
"cardVisual": (217, 87),
"actionButton": (51, 22),
# v3.5.0 additions
"clusteredColumnChart": (400, 300),
"clusteredBarChart": (400, 300),
"textSlicer": (200, 50),
"listSlicer": (200, 300),
}

View file

@ -74,6 +74,11 @@ _VISUAL_COLORS: dict[str, str] = {
# v3.4.0 additions
"cardVisual": "#767171",
"actionButton": "#E8832A",
# v3.5.0 additions
"clusteredColumnChart": "#4472C4",
"clusteredBarChart": "#4472C4",
"textSlicer": "#FFC000",
"listSlicer": "#FFC000",
}
_VISUAL_ICONS: dict[str, str] = {
@ -102,6 +107,11 @@ _VISUAL_ICONS: dict[str, str] = {
# v3.4.0 additions
"cardVisual": "■",
"actionButton": "▶",
# v3.5.0 additions
"clusteredColumnChart": "▐▐▐",
"clusteredBarChart": "▌▌▌",
"textSlicer": "☰",
"listSlicer": "☰",
}

View file

@ -0,0 +1,24 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/fabric/item/report/definition/visualContainer/2.7.0/schema.json",
"name": "__VISUAL_NAME__",
"position": {
"x": __X__,
"y": __Y__,
"z": __Z__,
"height": __HEIGHT__,
"width": __WIDTH__,
"tabOrder": __TAB_ORDER__
},
"visual": {
"visualType": "clusteredBarChart",
"query": {
"queryState": {
"Category": {"projections": []},
"Y": {"projections": []},
"Legend": {"projections": []}
}
},
"objects": {},
"drillFilterOtherVisuals": true
}
}

View file

@ -0,0 +1,24 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/fabric/item/report/definition/visualContainer/2.7.0/schema.json",
"name": "__VISUAL_NAME__",
"position": {
"x": __X__,
"y": __Y__,
"z": __Z__,
"height": __HEIGHT__,
"width": __WIDTH__,
"tabOrder": __TAB_ORDER__
},
"visual": {
"visualType": "clusteredColumnChart",
"query": {
"queryState": {
"Category": {"projections": []},
"Y": {"projections": []},
"Legend": {"projections": []}
}
},
"objects": {},
"drillFilterOtherVisuals": true
}
}

View file

@ -0,0 +1,22 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/fabric/item/report/definition/visualContainer/2.7.0/schema.json",
"name": "__VISUAL_NAME__",
"position": {
"x": __X__,
"y": __Y__,
"z": __Z__,
"height": __HEIGHT__,
"width": __WIDTH__,
"tabOrder": __TAB_ORDER__
},
"visual": {
"visualType": "listSlicer",
"query": {
"queryState": {
"Values": {"projections": [], "active": true}
}
},
"objects": {},
"drillFilterOtherVisuals": true
}
}

View file

@ -0,0 +1,22 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/fabric/item/report/definition/visualContainer/2.7.0/schema.json",
"name": "__VISUAL_NAME__",
"position": {
"x": __X__,
"y": __Y__,
"z": __Z__,
"height": __HEIGHT__,
"width": __WIDTH__,
"tabOrder": __TAB_ORDER__
},
"visual": {
"visualType": "textSlicer",
"query": {
"queryState": {
"Values": {"projections": []}
}
},
"objects": {},
"drillFilterOtherVisuals": true
}
}

View file

@ -824,3 +824,34 @@ def test_visual_list_tags_group_containers_as_group(report_with_page: Path) -> N
results = visual_list(report_with_page, "test_page")
grp = next(r for r in results if r["name"] == "grp1")
assert grp["visual_type"] == "group"
# ---------------------------------------------------------------------------
# Task 3 -- v3.5.0 new visual types
# ---------------------------------------------------------------------------
@pytest.mark.parametrize("vtype,alias", [
("clusteredColumnChart", "clustered_column"),
("clusteredBarChart", "clustered_bar"),
("textSlicer", "text_slicer"),
("listSlicer", "list_slicer"),
])
def test_visual_add_new_v35_types(
report_with_page: Path, vtype: str, alias: str
) -> None:
r = visual_add(report_with_page, "test_page", vtype, x=0, y=0)
assert r["visual_type"] == vtype
r2 = visual_add(report_with_page, "test_page", alias, x=50, y=0)
assert r2["visual_type"] == vtype
def test_list_slicer_template_has_active_flag(report_with_page: Path) -> None:
r = visual_add(report_with_page, "test_page", "listSlicer", x=0, y=0)
vfile = (
report_with_page / "pages" / "test_page" / "visuals"
/ r["name"] / "visual.json"
)
data = json.loads(vfile.read_text())
values = data["visual"]["query"]["queryState"]["Values"]
assert values.get("active") is True