diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Component_Compatibility.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Component_Compatibility.png index 5f84bdcfb29f99fbd6bccc256a06d0ad6a6b1c6f..4eb17524fee2f4d803f2a426c77f527f4d153b04 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Component_Compatibility.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Component_Compatibility.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Dark_Theme_Default.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Dark_Theme_Default.png index d7da5127bc020bde7fd7c5a7be10d1dea3e1cc59..9a22069a635c5304842777aa500c4d11f0335e1a 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Dark_Theme_Default.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Dark_Theme_Default.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Dark_Theme_No_Background_Default.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Dark_Theme_No_Background_Default.png index c1443174b06b11466414194ad1990cb089f6b72f..f66d386b6852409cde7d7e0ff00e1c0e17ecbaa6 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Dark_Theme_No_Background_Default.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Dark_Theme_No_Background_Default.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Dark_Theme_No_Background_Scroll.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Dark_Theme_No_Background_Scroll.png index c68e23130bb95265a73d910ef90079ea53013769..7b1a17aa9ff6161de47fde8f372922ca3097a538 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Dark_Theme_No_Background_Scroll.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Dark_Theme_No_Background_Scroll.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Dark_Theme_Scroll.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Dark_Theme_Scroll.png index 3d9d9b7bef47f1454a96aa21ae8b243932d46e20..81679da6eb92b75775180d6d22bf335ec9eea8cb 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Dark_Theme_Scroll.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Dark_Theme_Scroll.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Light_Theme_Default.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Light_Theme_Default.png index 63142b826eaf75e57f1c1d3a6812edb5bf42ad4f..c8d8d36f6e693628a6e37aca5aad5cb66d0ef479 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Light_Theme_Default.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Light_Theme_Default.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Light_Theme_No_Background_Default.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Light_Theme_No_Background_Default.png index 99ac71d7b4ab91fe383d5ae0cec727de19db2818..50134055e87bf2d39fcd876b3e7b14abe43cf625 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Light_Theme_No_Background_Default.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Light_Theme_No_Background_Default.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Light_Theme_No_Background_Scroll.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Light_Theme_No_Background_Scroll.png index 096161254fe85e5b422a69838d5e211d00a27a17..e2bed84eda915d6ebfdd0256008a6d20d4804431 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Light_Theme_No_Background_Scroll.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Light_Theme_No_Background_Scroll.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Light_Theme_Scroll.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Light_Theme_Scroll.png index 2c6241ec44d841ca928620f93a6f46aebaec58a3..3ad34876611e9e2022ade0173c05a82164b8d1f9 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Light_Theme_Scroll.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Light_Theme_Scroll.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Transparent_Theme_Default.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Transparent_Theme_Default.png index e0c920384888e1a1fd15ad4943a0d05e34e9a705..2f923ead58df06e3c619a5cd6963e298151d4eb6 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Transparent_Theme_Default.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Transparent_Theme_Default.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Transparent_Theme_No_Background_Default.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Transparent_Theme_No_Background_Default.png index 0a611518b4495d98598d4d268b419066390a1df0..b75c17b90f0942ca88b427e06da29903649a1e6e 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Transparent_Theme_No_Background_Default.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Transparent_Theme_No_Background_Default.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Transparent_Theme_No_Background_Scroll.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Transparent_Theme_No_Background_Scroll.png index e62b4dbf474fc41ae590dd6077c210a9c65b8d17..25f6a7cfc9f717b457f8646ceb7897e9838b857f 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Transparent_Theme_No_Background_Scroll.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Transparent_Theme_No_Background_Scroll.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Transparent_Theme_Scroll.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Transparent_Theme_Scroll.png index 95a52912f972662e03656b9617613ad13585d626..83b2bee35fbaf9c1dfc85f68dcb9e5c2f6147b17 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Transparent_Theme_Scroll.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_Transparent_Theme_Scroll.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Date_Filter_All_Options.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Date_Filter_All_Options.png index 974bcd8853a836ed119972670b5c580312e8a087..a5370c4db793dfe471d3182370b04737e62b00b5 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Date_Filter_All_Options.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Date_Filter_All_Options.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Date_Filter_Month_Year.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Date_Filter_Month_Year.png index 3fa84f4b514ff82d4fca59ed1f590c2e1c7a4d38..768007a171f9e2c502e18125393c09fcf6c633d5 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Date_Filter_Month_Year.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Date_Filter_Month_Year.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Date_Filter_Quarter_Year.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Date_Filter_Quarter_Year.png index 1220048a046cbe358d817a9881b87873ab78f335..4cff910ea3004af53ab9a88487a62afef7fb1747 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Date_Filter_Quarter_Year.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Date_Filter_Quarter_Year.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Date_Filter_Quarter_Year_Dropdown.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Date_Filter_Quarter_Year_Dropdown.png index c9f5497d05d15a80a92af422006d68e2218011fd..3883f48de71ca8298d53d96d0b34f9a5124dd040 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Date_Filter_Quarter_Year_Dropdown.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Date_Filter_Quarter_Year_Dropdown.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Date_Filter_Range.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Date_Filter_Range.png index 0d44e0cddb8290c7321c091182e493b8e8158fad..db8d573b51f6074bd83a5abd524a117b876bb622 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Date_Filter_Range.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Date_Filter_Range.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Date_Filter_Relative.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Date_Filter_Relative.png index c69214c00effd36d5275760faff2055a27c2b578..639b1505ca68f95dfbb3e86cf570073f2718bd53 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Date_Filter_Relative.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Date_Filter_Relative.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Date_Filter_Single.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Date_Filter_Single.png index f1ae7312e34528869dc9ba7529ad4c2e8f0b9aab..3f73165e05bc5a6f556cbb2c6451db23b0b32926 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Date_Filter_Single.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Date_Filter_Single.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Number.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Number.png index f2a326fde2c86010fa8d84c6c64effd072be063b..d23c7183daf62f5a30515b6b12eff8983c48946c 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Number.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Number.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Parameter_List.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Parameter_List.png index fbf3c5bf940d43af8746ca00681c6d92c4b81f5f..698e8f561871cf7431cea15a5ed760e8588f15f7 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Parameter_List.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Parameter_List.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Parameter_List_Single_With_Value.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Parameter_List_Single_With_Value.png index d90c5895d22e8f317869b4f3f3d5e7fa1ab6ce1e..399fdcbd480d27145ab1c34f3ae3242b3e3ca300 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Parameter_List_Single_With_Value.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Parameter_List_Single_With_Value.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Parameter_List_With_Value.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Parameter_List_With_Value.png index c9e4045439fcfb2166ba3e35b0520c488a04acf3..dd6f8d9d66e891c324621f162a77503d40302c8b 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Parameter_List_With_Value.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Parameter_List_With_Value.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Parameter_Search.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Parameter_Search.png index 6555bf66f963f92bdabdd1b29fdda7ad75068f4f..583a9696b18a626f4e262b8aa29f573ccd120d49 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Parameter_Search.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Parameter_Search.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Parameter_Search_With_Value.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Parameter_Search_With_Value.png index 78719309549ba8ed232edc8806694273d156883f..f3ff304f8d374fe0937e88e8a32a05f967aa8d9e 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Parameter_Search_With_Value.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Parameter_Search_With_Value.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Text.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Text.png index 504ebb9502a0671ca4a0a6f23e56ce530e79ae26..8a2e3a5b43552374f1e056c64bcb44f85a58cede 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Text.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Text.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Text_With_Value.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Text_With_Value.png index a937efc98fa8ade268b34c218c04b2ec69ac9dd4..e8893719a3f6308a3191760bfa0392c69f83a315 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Text_With_Value.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Text_With_Value.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Unit_Of_Time.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Unit_Of_Time.png index 5bfc491dac04e8656a60afb4f1aaa36748aec3eb..eafe23d5f6cc89a2124385d2b0c5800a7b01fc37 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Unit_Of_Time.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Dark_Theme_Unit_Of_Time.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Date_Filter_All_Options.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Date_Filter_All_Options.png index 31c3976c188473ab3494e697d4ef48bf82ec55f5..a401f04507b8430a9420c125c6689fc0af022173 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Date_Filter_All_Options.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Date_Filter_All_Options.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Date_Filter_Month_Year.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Date_Filter_Month_Year.png index c56605e598c1b1492e4ae8c34c8966a9522218ae..075a0dd2e86cf7ba4f0acd614c294efcf931d7fb 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Date_Filter_Month_Year.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Date_Filter_Month_Year.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Date_Filter_Quarter_Year.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Date_Filter_Quarter_Year.png index f4ee8a121fd6b6026fa394419faa45555cf7e0bd..25db56801beaac1c92da3d9d69918c91d6d76a07 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Date_Filter_Quarter_Year.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Date_Filter_Quarter_Year.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Date_Filter_Quarter_Year_Dropdown.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Date_Filter_Quarter_Year_Dropdown.png index 99c7f14814d926de6648998522d52cc83a65e321..a30f79954011559abf2119afc5d207d4db74b99e 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Date_Filter_Quarter_Year_Dropdown.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Date_Filter_Quarter_Year_Dropdown.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Date_Filter_Range.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Date_Filter_Range.png index b16e53e9f43a1e9b6b643fea1b7c75a734397182..f42f3c1a7c58389502aeb1cab6001d92aec92cde 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Date_Filter_Range.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Date_Filter_Range.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Date_Filter_Relative.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Date_Filter_Relative.png index 7178a9b0749e3a94cc6701eca5ec421270529858..23f6cfd0d138dc64e322e0ccba1da8abcbbe15ed 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Date_Filter_Relative.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Date_Filter_Relative.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Date_Filter_Single.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Date_Filter_Single.png index 960204a6a2137f7fe132d325fe6c466f4cbaacfc..be11694112ff76eae0283f6cc8fd13e469e51a56 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Date_Filter_Single.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Date_Filter_Single.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Number.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Number.png index 3ee55033066407e8596c4be75dde38757b6ca3d5..202a2dcfa7fafe064893b1cdc8cae575bc23db00 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Number.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Number.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Parameter_List.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Parameter_List.png index ac01ad5a8e945c5be9d66d45c4f9852fe59ecc6d..b85290c3c9e246c5b7c0b47a3c00238e0922f506 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Parameter_List.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Parameter_List.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Parameter_List_Single_With_Value.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Parameter_List_Single_With_Value.png index 51ff8f3199beada911b053ec1d5875ebf0879ea6..8d7e8d7572c110de6205e0f2e0f9da3f241a659e 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Parameter_List_Single_With_Value.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Parameter_List_Single_With_Value.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Parameter_List_With_Value.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Parameter_List_With_Value.png index 71a5a4920bea80a471e285725c936e65ec15edfd..74213a1d2e66b9a3bcfb926290605c97df528208 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Parameter_List_With_Value.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Parameter_List_With_Value.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Parameter_Search.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Parameter_Search.png index eb8de21a0bbf623ef1b727a213d117936f636d1e..3490d00097befc6e766217a5359cecf21894a96c 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Parameter_Search.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Parameter_Search.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Parameter_Search_With_Value.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Parameter_Search_With_Value.png index f8594d414c2794ad04f51f4f19578fdcbe37f167..225530ad1a468b9b136d92f82c17fc3c76b23fdc 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Parameter_Search_With_Value.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Parameter_Search_With_Value.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Text.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Text.png index 52d9a776b26cd747cd24be1f769914ab493462a7..8ec1a847457040106c7f5d580010285210e9349c 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Text.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Text.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Text_With_Value.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Text_With_Value.png index 70ef2dbdc313f6f7dc9cbb9d6452a1a02ee8d821..121599d45be5ef01cacb58adc97a1a6cc3f55197 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Text_With_Value.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Text_With_Value.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Unit_Of_Time.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Unit_Of_Time.png index 95eca09668373e9159a8909dff062afeba01171a..9b95e05459494079f7e55e1b75c7471437c285e3 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Unit_Of_Time.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedDashboardView_filters_Light_Theme_Unit_Of_Time.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedQuestionView_Dark_Theme_Default.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedQuestionView_Dark_Theme_Default.png index 999ecc6399effe08ebd8b4337a18779f735cf5cf..16f4665179b3f04746f1b9b0a86378fbb9508373 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedQuestionView_Dark_Theme_Default.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedQuestionView_Dark_Theme_Default.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedQuestionView_Dark_Theme_Default_No_Results.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedQuestionView_Dark_Theme_Default_No_Results.png index 0e9199f42df96a00d23d963931b3409753e2fe7e..ed42da0c6a4c1d11a5a05ddefdd51690fe5b2334 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedQuestionView_Dark_Theme_Default_No_Results.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedQuestionView_Dark_Theme_Default_No_Results.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedQuestionView_Light_Theme_Default.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedQuestionView_Light_Theme_Default.png index 5ff355271691d4a6ba95d328c0530d14306efabb..95e2ef2dbb093271e1bb083d761b9d28fb5f18f7 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedQuestionView_Light_Theme_Default.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedQuestionView_Light_Theme_Default.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedQuestionView_Light_Theme_Default_No_Results.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedQuestionView_Light_Theme_Default_No_Results.png index 2da8a24f488712217487a52e9fef35ea38971a9f..e674272a92a06803dc93a43c2d3b56714e8d716c 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedQuestionView_Light_Theme_Default_No_Results.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedQuestionView_Light_Theme_Default_No_Results.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedQuestionView_Pivot_Table_Dark_Theme.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedQuestionView_Pivot_Table_Dark_Theme.png index 76eaa63a555d927cc4e7de96695ec7e4959ae802..c91eb0200f32ab8cceae23d648afe4946af44ad9 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedQuestionView_Pivot_Table_Dark_Theme.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedQuestionView_Pivot_Table_Dark_Theme.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedQuestionView_Pivot_Table_Light_Theme.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedQuestionView_Pivot_Table_Light_Theme.png index 6f48a812430e280dd028284912b8f6ebde4e4cba..5d974736731bded7bb7cb49015120c6b011e4556 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedQuestionView_Pivot_Table_Light_Theme.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedQuestionView_Pivot_Table_Light_Theme.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedQuestionView_Smart_Scalar_Dark_Theme.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedQuestionView_Smart_Scalar_Dark_Theme.png index 91e85cf82311b0a869633a73ec3d4b0d5f506382..5a65f3339230af6c6c8f0d94ded92babcee2ba9e 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedQuestionView_Smart_Scalar_Dark_Theme.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedQuestionView_Smart_Scalar_Dark_Theme.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedQuestionView_Smart_Scalar_Dark_Theme_Tooltip.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedQuestionView_Smart_Scalar_Dark_Theme_Tooltip.png index 79cfe86b813aeb80bb484452b1ace90619375f4f..1f5cfa0d0af8df6f86558c80655480bffefe22ee 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedQuestionView_Smart_Scalar_Dark_Theme_Tooltip.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedQuestionView_Smart_Scalar_Dark_Theme_Tooltip.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedQuestionView_Smart_Scalar_Light_Theme.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedQuestionView_Smart_Scalar_Light_Theme.png index ae5297dd9d222342ce491503bd4b29b30e3b2003..e993994774c479793c87f12ad461350207f3ac5a 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedQuestionView_Smart_Scalar_Light_Theme.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedQuestionView_Smart_Scalar_Light_Theme.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedQuestionView_Smart_Scalar_Light_Theme_Tooltip.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedQuestionView_Smart_Scalar_Light_Theme_Tooltip.png index d5948901ab773ab55e06306a2d7a0c1ea1ac6f0a..7e03128614ed59acac2e23984f34f6c3257c51fa 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedQuestionView_Smart_Scalar_Light_Theme_Tooltip.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedQuestionView_Smart_Scalar_Light_Theme_Tooltip.png differ diff --git a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedQuestionView_Transparent_Theme_Default.png b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedQuestionView_Transparent_Theme_Default.png index 71c03f5c07e1951c927b1e204d3c32ecff3f3ab3..94b303d975892342db427255e765cda0759d81a1 100644 Binary files a/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedQuestionView_Transparent_Theme_Default.png and b/.loki/reference/chrome_laptop_embed_PublicOrEmbeddedQuestionView_Transparent_Theme_Default.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Auto_Y_Axis_Exclude_Zero_With_Goal.png b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Auto_Y_Axis_Exclude_Zero_With_Goal.png index 474658f9d49b04f54ab6d28a262675dfb42accde..20948e59b968e8ce0f1aad403707ca206842cefb 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Auto_Y_Axis_Exclude_Zero_With_Goal.png and b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Auto_Y_Axis_Exclude_Zero_With_Goal.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Bubble_Size.png b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Bubble_Size.png index 3cc9bd2935a42a1b8ef2ce64a94b7d2c93da70af..4c16532ba75871cbc5f5b0c2063afea526ba6bfc 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Bubble_Size.png and b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Bubble_Size.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Custom_Y_Axis_Range.png b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Custom_Y_Axis_Range.png index 863d648c99b72ac55ad9c0016c24a372aed4e54d..55a134513b24c87e0cd93cc2bdf913922b6c38fd 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Custom_Y_Axis_Range.png and b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Custom_Y_Axis_Range.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Custom_Y_Axis_Range_With_Column_Scaling.png b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Custom_Y_Axis_Range_With_Column_Scaling.png index 77678cfc54351054dc196197d5cd752de3f07103..3f5943f64e3221adc3c5b0271e6167c3ff57843a 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Custom_Y_Axis_Range_With_Column_Scaling.png and b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Custom_Y_Axis_Range_With_Column_Scaling.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Default.png b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Default.png index 5d6bdf38aaa020724a459dfc6f01efbb185f9f04..9410fc76b1db0eeb77f110398232231c454ff676 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Default.png and b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Default.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Goal_Line.png b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Goal_Line.png index 2fa8705fcc2c96c0edc4263c4c3ea3b406d3fa29..5af2c42311a18b9e37b70e5b9022b93b9e622f01 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Goal_Line.png and b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Goal_Line.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Histogram_X_Scale.png b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Histogram_X_Scale.png index fa0e17113dee8861e0ed6b29fb4e82adf4c0183b..08572942401726b607f197396b017509028c494f 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Histogram_X_Scale.png and b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Histogram_X_Scale.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Log_X_Scale.png b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Log_X_Scale.png index 089f9ea8bb3820362f1264d1c26083a30588d8ad..a500cdc8b457dee9c12f9c602417f1fac2c0582e 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Log_X_Scale.png and b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Log_X_Scale.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Log_X_Scale_At_One.png b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Log_X_Scale_At_One.png index 2d20e5bf6ae28463aaee40a3e12e3315d714114c..345fe2d3330caa726da47ab0557c5cdef93bfe37 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Log_X_Scale_At_One.png and b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Log_X_Scale_At_One.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Multi_Dimension_Breakout.png b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Multi_Dimension_Breakout.png index a14337d68a023010c412c9f371f1ecef074d2950..1c541ecf57ad03701624648504150a6be61fd17f 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Multi_Dimension_Breakout.png and b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Multi_Dimension_Breakout.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Multi_Dimension_Breakout_Bubble_Size.png b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Multi_Dimension_Breakout_Bubble_Size.png index 417b327b3ba95c18de99fef6975e19622a616a5d..85c85fa238fc5d6347898f3a50f15febdaa4a77e 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Multi_Dimension_Breakout_Bubble_Size.png and b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Multi_Dimension_Breakout_Bubble_Size.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Multi_Metric_Series.png b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Multi_Metric_Series.png index 0c027b56c6842177bfb5e7779775f1a0e245a3d8..98a0e4ffa77f9fde552c657271c06bd14b19faa1 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Multi_Metric_Series.png and b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Multi_Metric_Series.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Ordinal_X_Scale.png b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Ordinal_X_Scale.png index 5f8cb0ffb6551384cae3583e5579ec9ed449e7aa..4fb6f44401a54232bf9fd8770c87e3f8e626fe5d 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Ordinal_X_Scale.png and b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Ordinal_X_Scale.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Power_X_Scale.png b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Power_X_Scale.png index 5d8c283f9bd5ed3d3dca82c194e25668866d9e63..b419924ab3222f44481189c4750e6e68460893b9 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Power_X_Scale.png and b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Power_X_Scale.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Power_X_Scale_Multi_Series.png b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Power_X_Scale_Multi_Series.png index d0160e6e959a6ecb926d7fe3e311bc4cb46f6ba9..eaa070000e77074c7cd0537205175aff46d94b20 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Power_X_Scale_Multi_Series.png and b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Power_X_Scale_Multi_Series.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Timeseries_X_Scale.png b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Timeseries_X_Scale.png index 8c30e666adc139e3a9d1b952c10f0c81ddca0baa..265c3bfd2bcc09c2181481f5dc38880a86a71db8 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Timeseries_X_Scale.png and b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Timeseries_X_Scale.png differ diff --git a/.loki/reference/chrome_laptop_viz_BarChart_Default.png b/.loki/reference/chrome_laptop_viz_BarChart_Default.png index 5790438a905aa3c20c01eacb01920b37546cda6b..e3a67f0cfc0c44ebbdf5f95aee3e5d53b0870c44 100644 Binary files a/.loki/reference/chrome_laptop_viz_BarChart_Default.png and b/.loki/reference/chrome_laptop_viz_BarChart_Default.png differ diff --git a/.loki/reference/chrome_laptop_viz_BarChart_Embedding_Huge_Font.png b/.loki/reference/chrome_laptop_viz_BarChart_Embedding_Huge_Font.png index f7eb5e4c14cdb869dd1975d90a9acf2322f3c544..91c5a2ee49d82db82f0de6b431d60b9e8889d375 100644 Binary files a/.loki/reference/chrome_laptop_viz_BarChart_Embedding_Huge_Font.png and b/.loki/reference/chrome_laptop_viz_BarChart_Embedding_Huge_Font.png differ diff --git a/.loki/reference/chrome_laptop_viz_LineChart_Default.png b/.loki/reference/chrome_laptop_viz_LineChart_Default.png index b1222d607f01306a7d6a6af5af3c5ab24501e07d..0c067ea6dfef6767301631629cf4e9e8531cdbd4 100644 Binary files a/.loki/reference/chrome_laptop_viz_LineChart_Default.png and b/.loki/reference/chrome_laptop_viz_LineChart_Default.png differ diff --git a/.loki/reference/chrome_laptop_viz_LineChart_Embedding_Huge_Font.png b/.loki/reference/chrome_laptop_viz_LineChart_Embedding_Huge_Font.png index ba0678a5625ea3665a71e5049e8d9cbc930881ce..542a23537b34de41df4b02bf285a3390082b2f88 100644 Binary files a/.loki/reference/chrome_laptop_viz_LineChart_Embedding_Huge_Font.png and b/.loki/reference/chrome_laptop_viz_LineChart_Embedding_Huge_Font.png differ diff --git a/.loki/reference/chrome_laptop_viz_TableSimple_Default.png b/.loki/reference/chrome_laptop_viz_TableSimple_Default.png index 9dfebe2892d30c7267e3495f79135103d80039ec..19ed2d70f15986a00848c28200bf8fda710d6cb3 100644 Binary files a/.loki/reference/chrome_laptop_viz_TableSimple_Default.png and b/.loki/reference/chrome_laptop_viz_TableSimple_Default.png differ diff --git a/.loki/reference/chrome_laptop_viz_TableSimple_Embedding_Theme.png b/.loki/reference/chrome_laptop_viz_TableSimple_Embedding_Theme.png index 43f6eeccf39d2266338036c5b74bd497acafaf2c..b67a3d026e63826b17ab6482b3eca8a153064e39 100644 Binary files a/.loki/reference/chrome_laptop_viz_TableSimple_Embedding_Theme.png and b/.loki/reference/chrome_laptop_viz_TableSimple_Embedding_Theme.png differ diff --git a/e2e/support/helpers/e2e-visual-tests-helpers.js b/e2e/support/helpers/e2e-visual-tests-helpers.js index 429e855ef875f2588db2691b5fd7e5e9960c96e2..41e89cdc3844f52961649ef9bec6eab1dc60c922 100644 --- a/e2e/support/helpers/e2e-visual-tests-helpers.js +++ b/e2e/support/helpers/e2e-visual-tests-helpers.js @@ -119,3 +119,60 @@ export function pieSliceWithColor(color) { `path[stroke-linejoin='bevel'][fill='${color}']`, ); } + +export function echartsTooltip() { + // ECharts may keep two dom instances of the tooltip + return cy + .findAllByTestId("echarts-tooltip") + .filter(":visible") + .should("have.length", 1) + .eq(0); +} + +export function tooltipHeader() { + return cy.findByTestId("echarts-tooltip-header"); +} + +export function assertTooltipRow( + name, + { color, value, secondaryValue, index } = {}, +) { + cy.findAllByText(name) + .eq(index ?? 0) + .parent("tr") + .within(() => { + if (color) { + cy.get("td") + .eq(0) + .find("span") + .should("have.class", `marker-${color.replace("#", "")}`); + } + + if (value) { + cy.findByText(value); + } + + if (secondaryValue) { + cy.findByText(secondaryValue); + } + }); +} + +export function assertEChartsTooltip({ header, rows, blurAfter }) { + echartsTooltip().within(() => { + if (header != null) { + tooltipHeader().should("have.text", header); + } + + if (rows != null) { + rows.forEach(row => { + const { name, ...rest } = row; + assertTooltipRow(name, rest); + }); + } + }); + + if (blurAfter) { + echartsTriggerBlur(); + } +} diff --git a/e2e/test/scenarios/dashboard-cards/dashboard-drill.cy.spec.js b/e2e/test/scenarios/dashboard-cards/dashboard-drill.cy.spec.js index d847d58fff50fda09ebdb7a3183f004261f25b07..f512b256df56a89bd0e11f7e6116c69674678d65 100644 --- a/e2e/test/scenarios/dashboard-cards/dashboard-drill.cy.spec.js +++ b/e2e/test/scenarios/dashboard-cards/dashboard-drill.cy.spec.js @@ -22,9 +22,11 @@ import { chartPathWithFillColor, echartsContainer, entityPickerModal, - testPairedTooltipValues, editDashboard, saveDashboard, + echartsTooltip, + tooltipHeader, + assertTooltipRow, } from "e2e/support/helpers"; const { @@ -884,19 +886,18 @@ describe("scenarios > dashboard > dashboard drill", () => { visitDashboard(DASHBOARD_ID); - chartPathWithFillColor("#88BF4D").first().trigger("mousemove"); + const assertTooltipValues = () => + echartsTooltip().within(() => { + tooltipHeader().should("have.text", 1); + assertTooltipRow("15612_1", { color: "#88BF4D", value: "5" }); + assertTooltipRow("15612_2", { color: "#98D9D9", value: "10" }); + }); - popover().within(() => { - testPairedTooltipValues("AXIS", "1"); - testPairedTooltipValues("VALUE", "5"); - }); + chartPathWithFillColor("#88BF4D").first().trigger("mousemove"); + assertTooltipValues(); chartPathWithFillColor("#98D9D9").first().trigger("mousemove"); - - popover().within(() => { - testPairedTooltipValues("AXIS", "1"); - testPairedTooltipValues("VALUE", "10"); - }); + assertTooltipValues(); }); }); }); diff --git a/e2e/test/scenarios/dashboard/x-rays.cy.spec.js b/e2e/test/scenarios/dashboard/x-rays.cy.spec.js index 9bb18437a9a65e1cab47cfe46900ba78815586f7..1bde6c79a7320d30d9e5acc9a64fe5c440348ffe 100644 --- a/e2e/test/scenarios/dashboard/x-rays.cy.spec.js +++ b/e2e/test/scenarios/dashboard/x-rays.cy.spec.js @@ -12,6 +12,7 @@ import { saveDashboard, cartesianChartCircle, chartPathWithFillColor, + assertEChartsTooltip, } from "e2e/support/helpers"; const { ORDERS, ORDERS_ID, PRODUCTS, PRODUCTS_ID, PEOPLE, PEOPLE_ID } = @@ -302,9 +303,15 @@ describe("scenarios > x-rays", { tags: "@slow" }, () => { chartPathWithFillColor("#509EE3").should("have.length", 5); chartPathWithFillColor("#509EE3").eq(0).realHover(); - popover().within(() => { - cy.findByText("Affiliate").should("be.visible"); - cy.findByText("3,520").should("be.visible"); + assertEChartsTooltip({ + header: "Affiliate", + rows: [ + { + color: "#509EE3", + name: "Count", + value: "3,520", + }, + ], }); }); diff --git a/e2e/test/scenarios/embedding/embedding-linked-filters.cy.spec.js b/e2e/test/scenarios/embedding/embedding-linked-filters.cy.spec.js index 74fdf1318c9b8eb2c55618d31c638c44338494a9..b8934c6614d1e31c1810f2932dc3b351929a346c 100644 --- a/e2e/test/scenarios/embedding/embedding-linked-filters.cy.spec.js +++ b/e2e/test/scenarios/embedding/embedding-linked-filters.cy.spec.js @@ -6,9 +6,9 @@ import { getDashboardCard, chartPathWithFillColor, echartsContainer, - testPairedTooltipValues, multiAutocompleteInput, removeMultiAutocompleteValue, + assertEChartsTooltip, } from "e2e/support/helpers"; import { @@ -84,10 +84,10 @@ describe("scenarios > embedding > dashboard > linked filters (metabase#13639, me .and("not.contain", "TX"); chartPathWithFillColor("#509EE3").should("have.length", 1).realHover(); - - popover().within(() => { - testPairedTooltipValues("STATE", "AK"); - testPairedTooltipValues("Count", "68"); + assertEChartsTooltip({ + header: "AK", + rows: [{ color: "#509EE3", name: "Count", value: "68" }], + blurAfter: true, }); openFilterOptions("City"); @@ -105,9 +105,9 @@ describe("scenarios > embedding > dashboard > linked filters (metabase#13639, me chartPathWithFillColor("#509EE3").should("have.length", 1).realHover(); - popover().within(() => { - testPairedTooltipValues("STATE", "AK"); - testPairedTooltipValues("Count", "1"); + assertEChartsTooltip({ + header: "AK", + rows: [{ color: "#509EE3", name: "Count", value: "1" }], }); }); @@ -157,9 +157,10 @@ describe("scenarios > embedding > dashboard > linked filters (metabase#13639, me chartPathWithFillColor("#509EE3").should("have.length", 1).realHover(); - popover().within(() => { - testPairedTooltipValues("STATE", "AK"); - testPairedTooltipValues("Count", "68"); + assertEChartsTooltip({ + header: "AK", + rows: [{ color: "#509EE3", name: "Count", value: "68" }], + blurAfter: true, }); openFilterOptions("City"); @@ -180,9 +181,9 @@ describe("scenarios > embedding > dashboard > linked filters (metabase#13639, me chartPathWithFillColor("#509EE3").should("have.length", 1).realHover(); - popover().within(() => { - testPairedTooltipValues("STATE", "AK"); - testPairedTooltipValues("Count", "1"); + assertEChartsTooltip({ + header: "AK", + rows: [{ color: "#509EE3", name: "Count", value: "1" }], }); }); @@ -202,9 +203,10 @@ describe("scenarios > embedding > dashboard > linked filters (metabase#13639, me chartPathWithFillColor("#509EE3").should("have.length", 1).realHover(); - popover().within(() => { - testPairedTooltipValues("STATE", "AK"); - testPairedTooltipValues("Count", "68"); + assertEChartsTooltip({ + header: "AK", + rows: [{ color: "#509EE3", name: "Count", value: "68" }], + blurAfter: true, }); openFilterOptions("City"); @@ -222,9 +224,9 @@ describe("scenarios > embedding > dashboard > linked filters (metabase#13639, me chartPathWithFillColor("#509EE3").should("have.length", 1).realHover(); - popover().within(() => { - testPairedTooltipValues("STATE", "AK"); - testPairedTooltipValues("Count", "1"); + assertEChartsTooltip({ + header: "AK", + rows: [{ color: "#509EE3", name: "Count", value: "1" }], }); }); @@ -243,9 +245,10 @@ describe("scenarios > embedding > dashboard > linked filters (metabase#13639, me chartPathWithFillColor("#509EE3").should("have.length", 1).realHover(); - popover().within(() => { - testPairedTooltipValues("STATE", "AK"); - testPairedTooltipValues("Count", "68"); + assertEChartsTooltip({ + header: "AK", + rows: [{ color: "#509EE3", name: "Count", value: "68" }], + blurAfter: true, }); filterWidget().should("have.length", 1).and("contain", "City").click(); @@ -263,9 +266,9 @@ describe("scenarios > embedding > dashboard > linked filters (metabase#13639, me chartPathWithFillColor("#509EE3").should("have.length", 1).realHover(); - popover().within(() => { - testPairedTooltipValues("STATE", "AK"); - testPairedTooltipValues("Count", "1"); + assertEChartsTooltip({ + header: "AK", + rows: [{ color: "#509EE3", name: "Count", value: "1" }], }); }); diff --git a/e2e/test/scenarios/embedding/embedding-questions.cy.spec.js b/e2e/test/scenarios/embedding/embedding-questions.cy.spec.js index 807334941e3cc24135034df2f59706cb13f5b350..78af16fb91fb8917405f69b03575d08d7d225e84 100644 --- a/e2e/test/scenarios/embedding/embedding-questions.cy.spec.js +++ b/e2e/test/scenarios/embedding/embedding-questions.cy.spec.js @@ -8,7 +8,7 @@ import { openStaticEmbeddingModal, echartsContainer, cartesianChartCircle, - testPairedTooltipValues, + assertEChartsTooltip, describeEE, filterWidget, visitEmbeddedPage, @@ -107,12 +107,11 @@ describe("scenarios > embedding > questions", () => { echartsContainer().should("contain", "60"); // Check the tooltip for the last point on the line - cartesianChartCircle().last().realHover(); + cartesianChartCircle().last().trigger("mousemove"); - popover().within(() => { - testPairedTooltipValues("Created At", "Aug 2022"); - testPairedTooltipValues("Math", "2"); - testPairedTooltipValues("Count", "79"); + assertEChartsTooltip({ + header: "Aug 2022", + rows: [{ name: "2", value: "79" }], }); }); diff --git a/e2e/test/scenarios/question-reproductions/reproductions-3.cy.spec.js b/e2e/test/scenarios/question-reproductions/reproductions-3.cy.spec.js index dd83c24f741a11141bfa3a505530b77d1326d041..9b6c892c28e40e8f0812c496ade2976561bf074a 100644 --- a/e2e/test/scenarios/question-reproductions/reproductions-3.cy.spec.js +++ b/e2e/test/scenarios/question-reproductions/reproductions-3.cy.spec.js @@ -41,7 +41,7 @@ import { assertQueryBuilderRowCount, visitDashboard, getDashboardCard, - testTooltipPairs, + assertEChartsTooltip, join, visitQuestion, tableHeaderClick, @@ -1207,11 +1207,12 @@ describe("issue 31960", () => { getDashboardCard().within(() => { cartesianChartCircle().eq(dotIndex).realHover(); }); - testTooltipPairs([ - ["Created At:", "July 10–16, 2022"], - ["Count:", String(rowCount)], - ["Compared to previous week", "+10%"], - ]); + assertEChartsTooltip({ + header: "July 10–16, 2022", + rows: [ + { name: "Count", value: String(rowCount), secondaryValue: "+10%" }, + ], + }); getDashboardCard().within(() => { cartesianChartCircle().eq(dotIndex).click({ force: true }); }); diff --git a/e2e/test/scenarios/visualizations-charts/bar_chart.cy.spec.js b/e2e/test/scenarios/visualizations-charts/bar_chart.cy.spec.js index 3948946bdcf497dbda45398e38c4e75c21991033..479341feea0b7fbff166b227f928927a5c071a9d 100644 --- a/e2e/test/scenarios/visualizations-charts/bar_chart.cy.spec.js +++ b/e2e/test/scenarios/visualizations-charts/bar_chart.cy.spec.js @@ -15,7 +15,7 @@ import { createQuestion, chartPathsWithFillColors, createNativeQuestion, - testStackedTooltipRows, + assertEChartsTooltip, } from "e2e/support/helpers"; const { ORDERS, ORDERS_ID, PEOPLE, PRODUCTS, PRODUCTS_ID } = SAMPLE_DATABASE; @@ -617,12 +617,22 @@ describe("scenarios > visualizations > bar chart", () => { }); chartPathWithFillColor("#88BF4D").first().realHover(); - popover().within(() => { - cy.contains("Sum of Total"); - // half of the unscaled metric - cy.contains("21,078.43"); - // full value of the unscale metric - cy.contains("42,156.87"); + assertEChartsTooltip({ + header: "2022", + rows: [ + { + color: "#88BF4D", + name: "Sum of Total", + value: "21,078.43", + index: 0, + }, + { + color: "#98D9D9", + name: "Sum of Total", + value: "42,156.87", + index: 1, + }, + ], }); }); @@ -648,43 +658,123 @@ describe("scenarios > visualizations > bar chart", () => { ); chartPathWithFillColor("#A989C5").eq(0).realHover(); - testStackedTooltipRows([ - ["blue", "2", "20.00 %"], - ["yellow", "8", "80.00 %"], - ["Total", "10", "100 %"], - ]); + assertEChartsTooltip({ + rows: [ + { + color: "#A989C5", + name: "blue", + value: "2", + secondaryValue: "20.00 %", + }, + { + color: "#F9D45C", + name: "yellow", + value: "8", + secondaryValue: "80.00 %", + }, + { + name: "Total", + value: "10", + secondaryValue: "100 %", + }, + ], + }); resetHoverState(); chartPathWithFillColor("#A989C5").eq(1).realHover(); - testStackedTooltipRows([ - ["blue", "-16", "-200.00 %"], - ["yellow", "8", "100 %"], - ["Total", "-8", "-100.00 %"], - ]); + assertEChartsTooltip({ + rows: [ + { + color: "#A989C5", + name: "blue", + value: "-16", + secondaryValue: "-200.00 %", + }, + { + color: "#F9D45C", + name: "yellow", + value: "8", + secondaryValue: "100 %", + }, + { + name: "Total", + value: "-8", + secondaryValue: "-100.00 %", + }, + ], + }); resetHoverState(); chartPathWithFillColor("#A989C5").eq(2).realHover(); - testStackedTooltipRows([ - ["blue", "-7", "-350.00 %"], - ["yellow", "5", "250.00 %"], - ["Total", "-2", "-100.00 %"], - ]); + assertEChartsTooltip({ + rows: [ + { + color: "#A989C5", + name: "blue", + value: "-7", + secondaryValue: "-350.00 %", + }, + { + color: "#F9D45C", + name: "yellow", + value: "5", + secondaryValue: "250.00 %", + }, + { + name: "Total", + value: "-2", + secondaryValue: "-100.00 %", + }, + ], + }); resetHoverState(); chartPathWithFillColor("#A989C5").eq(3).realHover(); - testStackedTooltipRows([ - ["blue", "2", "Infinity %"], - ["yellow", "-2", "-Infinity %"], - ["Total", "0", "NaN %"], - ]); + assertEChartsTooltip({ + rows: [ + { + color: "#A989C5", + name: "blue", + value: "2", + secondaryValue: "Infinity %", + }, + { + color: "#F9D45C", + name: "yellow", + value: "-2", + secondaryValue: "-Infinity %", + }, + { + name: "Total", + value: "0", + secondaryValue: "NaN %", + }, + ], + }); resetHoverState(); chartPathWithFillColor("#A989C5").eq(4).realHover(); - testStackedTooltipRows([ - ["blue", "3", "300.00 %"], - ["yellow", "-2", "-200.00 %"], - ["Total", "1", "100 %"], - ]); + assertEChartsTooltip({ + rows: [ + { + color: "#A989C5", + name: "blue", + value: "3", + secondaryValue: "300.00 %", + }, + { + color: "#F9D45C", + name: "yellow", + value: "-2", + secondaryValue: "-200.00 %", + }, + { + name: "Total", + value: "1", + secondaryValue: "100 %", + }, + ], + }); resetHoverState(); }); }); diff --git a/e2e/test/scenarios/visualizations-charts/combo.cy.spec.js b/e2e/test/scenarios/visualizations-charts/combo.cy.spec.js index f2d4920052f30c723a8ec4a714cf06db2acada1b..48e60bae2502b20c0e86b6f55b0bfba59624bda7 100644 --- a/e2e/test/scenarios/visualizations-charts/combo.cy.spec.js +++ b/e2e/test/scenarios/visualizations-charts/combo.cy.spec.js @@ -4,10 +4,9 @@ import { echartsContainer, restore, visitQuestionAdhoc, - testTooltipPairs, cartesianChartCircleWithColor, - testStackedTooltipRows, chartPathWithFillColor, + assertEChartsTooltip, } from "e2e/support/helpers"; const { PRODUCTS, PRODUCTS_ID, ORDERS_ID, ORDERS } = SAMPLE_DATABASE; @@ -93,35 +92,75 @@ describe("scenarios > visualizations > combo", () => { // First circle of the line series cartesianChartCircleWithColor("#A989C5").eq(0).trigger("mousemove"); - testTooltipPairs([ - ["Created At:", "2022"], - ["Average of Total:", "56.66"], - ["Average of Subtotal:", "54.44"], - ["Min of Total:", "12.32"], - ["Min of Subtotal:", "15.69"], - ["Max of Total:", "102.77"], - ["Max of Subtotal:", "98.82"], - ]); + assertEChartsTooltip({ + header: "2022", + rows: [ + { color: "#A989C5", name: "Average of Total", value: "56.66" }, + { color: "#F2A86F", name: "Average of Subtotal", value: "54.44" }, + { color: "#EF8C8C", name: "Min of Total", value: "12.32" }, + { color: "#98D9D9", name: "Min of Subtotal", value: "15.69" }, + { color: "#F9D45C", name: "Max of Total", value: "102.77" }, + { color: "#7172AD", name: "Max of Subtotal", value: "98.82" }, + ], + }); // First circle of stacked area series cartesianChartCircleWithColor("#98D9D9").eq(0).trigger("mousemove"); // Check the tooltip shows only stacked areas series - testStackedTooltipRows([ - ["Min of Subtotal", "15.69", "56.01 %"], - ["Min of Total", "12.32", "43.99 %"], - ["Total", "28.02", "100 %"], - ]); + assertEChartsTooltip({ + header: "2022", + rows: [ + { + color: "#EF8C8C", + name: "Min of Total", + value: "12.32", + secondaryValue: "43.99 %", + }, + { + color: "#98D9D9", + name: "Min of Subtotal", + value: "15.69", + secondaryValue: "56.01 %", + }, + { + name: "Total", + value: "28.02", + secondaryValue: "100 %", + }, + ], + }); // First bar of stacked bar series chartPathWithFillColor("#7172AD").eq(0).realHover(); - - testStackedTooltipRows([ - ["Max of Subtotal", "98.82", "38.60 %"], - ["Max of Total", "102.77", "40.14 %"], - ["Average of Subtotal", "54.44", "21.26 %"], - ["Total", "256.03", "100 %"], - ]); + assertEChartsTooltip({ + header: "2022", + rows: [ + { + color: "#7172AD", + name: "Max of Subtotal", + value: "98.82", + secondaryValue: "38.60 %", + }, + { + color: "#F9D45C", + name: "Max of Total", + value: "102.77", + secondaryValue: "40.14 %", + }, + { + color: "#F2A86F", + name: "Average of Subtotal", + value: "54.44", + secondaryValue: "21.26 %", + }, + { + name: "Total", + value: "256.03", + secondaryValue: "100 %", + }, + ], + }); // Switch to normalized stacking cy.findByTestId("chartsettings-sidebar").findByText("Stack - 100%").click(); diff --git a/e2e/test/scenarios/visualizations-charts/line-bar-tooltips.cy.spec.js b/e2e/test/scenarios/visualizations-charts/line-bar-tooltips.cy.spec.js index 2f2c526560c690eefaac2bbe2223f3fa59f3ba17..c7e3009b7ffd068de7a4ea9a4ad7172ba426b250 100644 --- a/e2e/test/scenarios/visualizations-charts/line-bar-tooltips.cy.spec.js +++ b/e2e/test/scenarios/visualizations-charts/line-bar-tooltips.cy.spec.js @@ -8,11 +8,11 @@ import { cartesianChartCircle, chartPathWithFillColor, cartesianChartCircleWithColor, - testPairedTooltipValues, - testTooltipPairs, - popover, echartsTriggerBlur, - POPOVER_ELEMENT, + echartsTooltip, + tooltipHeader, + assertTooltipRow, + assertEChartsTooltip, } from "e2e/support/helpers"; const { ORDERS, ORDERS_ID } = SAMPLE_DATABASE; @@ -27,20 +27,26 @@ const SUM_OF_TOTAL = { display: "line", }; -function testSumTotalChange(tooltipSelector = showTooltipForCircleInSeries) { +function testSumTotalChange( + tooltipSelector = showTooltipForCircleInSeries, + seriesName = "Sum of Total", +) { tooltipSelector("#88BF4D", 0); - testTooltipPairs([ - ["Created At", "2022"], - ["Sum of Total", "42,156.87"], - ]); - testTooltipExcludesText("Compared to previous year"); + echartsTooltip().within(() => { + tooltipHeader("2022"); + assertTooltipRow(seriesName, { color: "#88BF4D", value: "42,156.87" }); + }); tooltipSelector("#88BF4D", 1); - testTooltipPairs([ - ["Created At", "2023"], - ["Sum of Total", "205,256.02"], - ["Compared to previous year", "+386.89%"], - ]); + + echartsTooltip().within(() => { + tooltipHeader("2023"); + assertTooltipRow(seriesName, { + color: "#88BF4D", + value: "205,256.02", + secondaryValue: "+386.89%", + }); + }); } const SUM_OF_TOTAL_MONTH = { @@ -98,20 +104,28 @@ const AVG_OF_TOTAL = { display: "line", }; -function testAvgTotalChange(tooltipSelector = showTooltipForCircleInSeries) { +function testAvgTotalChange( + tooltipSelector = showTooltipForCircleInSeries, + seriesName = "Average of Total", +) { tooltipSelector("#A989C5", 0); - testTooltipPairs([ - ["Created At", "2022"], - ["Average of Total", "56.66"], - ]); - testTooltipExcludesText("Compared to previous year"); + echartsTooltip().within(() => { + tooltipHeader("2022"); + assertTooltipRow(seriesName, { + color: "#A989C5", + value: "56.66", + }); + }); tooltipSelector("#A989C5", 1); - testTooltipPairs([ - ["Created At", "2023"], - ["Average of Total", "56.86"], - ["Compared to previous year", "+0.34%"], - ]); + echartsTooltip().within(() => { + tooltipHeader("2022"); + assertTooltipRow(seriesName, { + color: "#A989C5", + value: "56.86", + secondaryValue: "+0.34%", + }); + }); } const AVG_OF_TOTAL_CUM_SUM_QUANTITY = { @@ -127,25 +141,33 @@ const AVG_OF_TOTAL_CUM_SUM_QUANTITY = { display: "line", }; -function testCumSumChange(testFirstTooltip = true) { +function testCumSumChange( + testFirstTooltip = true, + seriesName = "Cumulative sum of Quantity", +) { // In the multi series question with added question spec, this first circle // ends up hidden behind another circle, so we'll just skip it in that // specific spec if (testFirstTooltip) { showTooltipForCircleInSeries("#88BF4D", 0); - testTooltipPairs([ - ["Created At", "2022"], - ["Cumulative sum of Quantity", "3,236"], - ]); - testTooltipExcludesText("Compared to previous year"); + echartsTooltip().within(() => { + tooltipHeader("2022"); + assertTooltipRow(seriesName, { + color: "#88BF4D", + value: "3,236", + }); + }); } showTooltipForCircleInSeries("#88BF4D", 1); - testTooltipPairs([ - ["Created At", "2023"], - ["Cumulative sum of Quantity", "17,587"], - ["Compared to previous year", "+443.48%"], - ]); + echartsTooltip().within(() => { + tooltipHeader("2023"); + assertTooltipRow(seriesName, { + color: "#88BF4D", + value: "17,587", + secondaryValue: "+443.48%", + }); + }); } const AVG_DISCOUNT_SUM_DISCOUNT = { @@ -161,36 +183,46 @@ const AVG_DISCOUNT_SUM_DISCOUNT = { display: "line", }; -function testAvgDiscountChange() { +function testAvgDiscountChange(seriesName = "Average of Discount") { showTooltipForCircleInSeries("#509EE3", 0); - testTooltipPairs([ - ["Created At", "2022"], - ["Average of Discount", "5.03"], - ]); - testTooltipExcludesText("Compared to previous year"); + echartsTooltip().within(() => { + tooltipHeader("2022"); + assertTooltipRow(seriesName, { + color: "#509EE3", + value: "5.03", + }); + }); showTooltipForCircleInSeries("#509EE3", 1); - testTooltipPairs([ - ["Created At", "2023"], - ["Average of Discount", "5.41"], - ["Compared to previous year", "+7.54%"], - ]); + echartsTooltip().within(() => { + tooltipHeader("2023"); + assertTooltipRow(seriesName, { + color: "#509EE3", + value: "5.41", + secondaryValue: "+7.54%", + }); + }); } -function testSumDiscountChange() { +function testSumDiscountChange(seriesName = "Sum of Discount") { showTooltipForCircleInSeries("#98D9D9", 0); - testTooltipPairs([ - ["Created At", "2022"], - ["Sum of Discount", "342.09"], - ]); - testTooltipExcludesText("Compared to previous year"); + echartsTooltip().within(() => { + tooltipHeader("2022"); + assertTooltipRow(seriesName, { + color: "#98D9D9", + value: "342.09", + }); + }); showTooltipForCircleInSeries("#98D9D9", 1); - testTooltipPairs([ - ["Created At", "2023"], - ["Sum of Discount", "1,953.08"], - ["Compared to previous year", "+470.93%"], - ]); + echartsTooltip().within(() => { + tooltipHeader("2023"); + assertTooltipRow(seriesName, { + color: "#98D9D9", + value: "1,953.08", + secondaryValue: "+470.93%", + }); + }); } describe("scenarios > visualizations > line/bar chart > tooltips", () => { @@ -209,27 +241,26 @@ describe("scenarios > visualizations > line/bar chart > tooltips", () => { }); it("should show updated column titles in tooltips after editing them via Visualization Options", () => { - const originalTooltipText = [ - ["Created At", "2022"], - ["Sum of Total", "42,156.87"], - ]; - - const updatedTooltipText = [ - ["Created At", "2022"], - ["Custom", "42,156.87"], - ]; + const originalName = "Sum of Total"; + const customName = "Custom"; cartesianChartCircle().first().realHover(); - testTooltipPairs(originalTooltipText); + assertEChartsTooltip({ + header: "2022", + rows: [{ name: originalName, value: "42,156.87" }], + }); openDashCardVisualizationOptions(); - updateColumnTitle(originalTooltipText[1][0], updatedTooltipText[1][0]); + updateColumnTitle(originalName, customName); saveDashCardVisualizationOptions(); cartesianChartCircle().first().realHover(); - testTooltipPairs(updatedTooltipText); + assertEChartsTooltip({ + header: "2022", + rows: [{ name: customName, value: "42,156.87" }], + }); }); it("should show percent change in tooltip for timeseries axis", () => { @@ -248,47 +279,66 @@ describe("scenarios > visualizations > line/bar chart > tooltips", () => { }); it("should show updated column titles in tooltips after editing them via Visualization Options", () => { - const originalSeriesTooltipText = [ - ["Created At", "2022"], - ["Sum of Total", "42,156.87"], - ]; - const updatedOriginalSeriesTooltipText = [ - ["Created At", "2022"], - ["Custom Q1", "42,156.87"], - ]; - - const addedSeriesTooltipText = [ - ["Created At", "2022"], - ["Average of Total", "56.66"], - ]; - const updatedAddedSeriesTooltipText = [ - ["Created At", "2022"], - ["Custom Q2", "56.66"], - ]; + const originalSeriesName = "Q1"; + const updatedOriginalSeriesName = "Custom Q1"; + const addedSeriesName = "Q2"; + const updatedAddedSeriesName = "Custom Q2"; showTooltipForCircleInSeries("#88BF4D"); - testTooltipPairs(originalSeriesTooltipText); + assertEChartsTooltip({ + header: "2022", + rows: [ + { color: "#88BF4D", name: originalSeriesName, value: "42,156.87" }, + ], + }); showTooltipForCircleInSeries("#A989C5"); - testTooltipPairs(addedSeriesTooltipText); + assertEChartsTooltip({ + header: "2022", + rows: [ + { + color: "#A989C5", + name: addedSeriesName, + value: "56.66", + }, + ], + }); openDashCardVisualizationOptions(); - updateColumnTitle("Q1", updatedOriginalSeriesTooltipText[1][0]); - updateColumnTitle("Q2", updatedAddedSeriesTooltipText[1][0]); + updateColumnTitle("Q1", updatedOriginalSeriesName); + updateColumnTitle("Q2", updatedAddedSeriesName); saveDashCardVisualizationOptions(); showTooltipForCircleInSeries("#88BF4D"); - testTooltipPairs(updatedOriginalSeriesTooltipText); + assertEChartsTooltip({ + header: "2022", + rows: [ + { + color: "#88BF4D", + name: updatedOriginalSeriesName, + value: "42,156.87", + }, + ], + }); showTooltipForCircleInSeries("#A989C5"); - testTooltipPairs(updatedAddedSeriesTooltipText); + assertEChartsTooltip({ + header: "2022", + rows: [ + { + color: "#A989C5", + name: updatedAddedSeriesName, + value: "56.66", + }, + ], + }); }); it("should show percent change in tooltip for timeseries axis", () => { - testSumTotalChange(); - testAvgTotalChange(); + testSumTotalChange(showTooltipForCircleInSeries, "Q1"); + testAvgTotalChange(showTooltipForCircleInSeries, "Q2"); }); }); @@ -302,30 +352,51 @@ describe("scenarios > visualizations > line/bar chart > tooltips", () => { }); it("should show updated column titles in tooltips after editing them via Visualization Options", () => { - const originalTooltipText = [ - ["Created At", "2022"], - ["Average of Total", "56.66"], - ["Cumulative sum of Quantity", "3,236"], - ]; - - const updatedTooltipText = [ - ["Created At", "2022"], - ["Custom 1", "56.66"], - ["Custom 2", "3,236"], - ]; + const originalAvgSeriesName = "Average of Total"; + const originalCumSumSeriesName = "Cumulative sum of Quantity"; + const customAvgSeriesName = "Custom 1"; + const customCumSumSeriesName = "Custom 2"; cartesianChartCircle().first().realHover(); - testTooltipPairs(originalTooltipText); + assertEChartsTooltip({ + header: "2022", + rows: [ + { + color: "#A989C5", + name: originalAvgSeriesName, + value: "56.66", + }, + { + color: "#88BF4D", + name: originalCumSumSeriesName, + value: "3,236", + }, + ], + }); openDashCardVisualizationOptions(); - updateColumnTitle(originalTooltipText[1][0], updatedTooltipText[1][0]); - updateColumnTitle(originalTooltipText[2][0], updatedTooltipText[2][0]); + updateColumnTitle(originalAvgSeriesName, customAvgSeriesName); + updateColumnTitle(originalCumSumSeriesName, customCumSumSeriesName); saveDashCardVisualizationOptions(); cartesianChartCircle().first().realHover(); - testTooltipPairs(updatedTooltipText); + assertEChartsTooltip({ + header: "2022", + rows: [ + { + color: "#A989C5", + name: customAvgSeriesName, + value: "56.66", + }, + { + color: "#88BF4D", + name: customCumSumSeriesName, + value: "3,236", + }, + ], + }); }); it("should show percent change in tooltip for timeseries axis", () => { @@ -347,77 +418,95 @@ describe("scenarios > visualizations > line/bar chart > tooltips", () => { it("should show updated column titles in tooltips after editing them via Visualization Options", () => { // Checking the second datum since the first circle of one series is covered with a circle from the other series const circleIndex = 1; - const originalSeriesColors = ["#A989C5", "#88BF4D"]; - const addedSeriesColors = ["#98D9D9", "#509EE3"]; - const originalSeriesTooltipText = [ - ["Created At", "2023"], - ["Average of Total", "56.86"], - ["Cumulative sum of Quantity", "17,587"], - ]; - const updatedOriginalSeriesTooltipText = [ - ["Created At", "2023"], - ["Q1 Custom 1", "56.86"], - ["Q1 Custom 2", "17,587"], - ]; - - const addedSeriesTooltipText = [ - ["Created At", "2023"], - ["Average of Discount", "5.41"], - ["Sum of Discount", "1,953.08"], - ]; - const updatedAddedSeriesTooltipText = [ - ["Created At", "2023"], - ["Q2 Custom 1", "5.41"], - ["Q2 Custom 2", "1,953.08"], - ]; - - originalSeriesColors.forEach(color => { - showTooltipForCircleInSeries(color, circleIndex); - testTooltipPairs(originalSeriesTooltipText); - }); - addedSeriesColors.forEach(color => { + const originalSeriesColors = ["#A989C5", "#88BF4D"]; + const addedSeriesColors = ["#509EE3", "#98D9D9"]; + const originalAvgSeriesName = "Q1: Average of Total"; + const originalCumSumSeriesName = "Q1: Cumulative sum of Quantity"; + const updatedOriginalAvgSeriesName = "Q1 Custom 1"; + const updatedOriginalCumSumSeriesName = "Q1 Custom 2"; + const addedAvgSeriesName = "Q2: Average of Discount"; + const addedSumSeriesName = "Q2: Sum of Discount"; + const updatedAddedAvgSeriesName = "Q2 Custom 1"; + const updatedAddedSumSeriesName = "Q2 Custom 2"; + + [...originalSeriesColors, ...addedSeriesColors].forEach(color => { showTooltipForCircleInSeries(color, circleIndex); - testTooltipPairs(addedSeriesTooltipText); + assertEChartsTooltip({ + header: "2023", + rows: [ + { + color: originalSeriesColors[0], + name: originalAvgSeriesName, + value: "56.86", + }, + { + color: originalSeriesColors[1], + name: originalCumSumSeriesName, + value: "17,587", + }, + { + color: addedSeriesColors[0], + name: addedAvgSeriesName, + value: "5.41", + }, + { + color: addedSeriesColors[1], + name: addedSumSeriesName, + value: "1,953.08", + }, + ], + }); }); openDashCardVisualizationOptions(); + updateColumnTitle(originalAvgSeriesName, updatedOriginalAvgSeriesName); updateColumnTitle( - `Q1: ${originalSeriesTooltipText[1][0]}`, - updatedOriginalSeriesTooltipText[1][0], - ); - updateColumnTitle( - `Q1: ${originalSeriesTooltipText[2][0]}`, - updatedOriginalSeriesTooltipText[2][0], + originalCumSumSeriesName, + updatedOriginalCumSumSeriesName, ); - updateColumnTitle( - `Q2: ${addedSeriesTooltipText[1][0]}`, - updatedAddedSeriesTooltipText[1][0], - ); - updateColumnTitle( - `Q2: ${addedSeriesTooltipText[2][0]}`, - updatedAddedSeriesTooltipText[2][0], - ); + updateColumnTitle(addedAvgSeriesName, updatedAddedAvgSeriesName); + updateColumnTitle(addedSumSeriesName, updatedAddedSumSeriesName); saveDashCardVisualizationOptions(); - originalSeriesColors.forEach(color => { + [...originalSeriesColors, ...addedSeriesColors].forEach(color => { showTooltipForCircleInSeries(color, circleIndex); - testTooltipPairs(updatedOriginalSeriesTooltipText); - }); - addedSeriesColors.forEach(color => { - showTooltipForCircleInSeries(color, circleIndex); - testTooltipPairs(updatedAddedSeriesTooltipText); + assertEChartsTooltip({ + header: "2023", + rows: [ + { + color: originalSeriesColors[0], + name: updatedOriginalAvgSeriesName, + value: "56.86", + }, + { + color: originalSeriesColors[1], + name: updatedOriginalCumSumSeriesName, + value: "17,587", + }, + { + color: addedSeriesColors[0], + name: updatedAddedAvgSeriesName, + value: "5.41", + }, + { + color: addedSeriesColors[1], + name: updatedAddedSumSeriesName, + value: "1,953.08", + }, + ], + }); }); }); it("should show percent change in tooltip for timeseries axis", () => { - testAvgTotalChange(); - testCumSumChange(false); - testAvgDiscountChange(); - testSumDiscountChange(); + testAvgTotalChange(showTooltipForCircleInSeries, "Q1: Average of Total"); + testCumSumChange(false, "Q1: Cumulative sum of Quantity"); + testAvgDiscountChange("Q2: Average of Discount"); + testSumDiscountChange("Q2: Sum of Discount"); }); }); @@ -431,27 +520,38 @@ describe("scenarios > visualizations > line/bar chart > tooltips", () => { }); it("should show updated column titles in tooltips after editing them via Visualization Options", () => { - const originalTooltipText = [ - ["Created At", "2022"], - ["Sum of Total", "42,156.87"], - ]; - - const updatedTooltipText = [ - ["Created At", "2022"], - ["Custom", "42,156.87"], - ]; + const originalName = "Sum of Total"; + const updatedName = "Custom"; chartPathWithFillColor("#88BF4D").first().realHover(); - testTooltipPairs(originalTooltipText); + assertEChartsTooltip({ + header: "2022", + rows: [ + { + color: "#88BF4D", + name: originalName, + value: "42,156.87", + }, + ], + }); openDashCardVisualizationOptions(); - updateColumnTitle(originalTooltipText[1][0], updatedTooltipText[1][0]); + updateColumnTitle(originalName, updatedName); saveDashCardVisualizationOptions(); chartPathWithFillColor("#88BF4D").first().realHover(); - testTooltipPairs(updatedTooltipText); + assertEChartsTooltip({ + header: "2022", + rows: [ + { + color: "#88BF4D", + name: updatedName, + value: "42,156.87", + }, + ], + }); }); it("should show percent change in tooltip for timeseries axis", () => { @@ -472,47 +572,70 @@ describe("scenarios > visualizations > line/bar chart > tooltips", () => { it("should show updated column titles in tooltips after editing them via Visualization Options", () => { const originalSeriesColor = "#88BF4D"; const addedSeriesColor = "#A989C5"; - const originalSeriesTooltipText = [ - ["Created At", "2022"], - ["Sum of Total", "42,156.87"], - ]; - const updatedOriginalSeriesTooltipText = [ - ["Created At", "2022"], - ["Custom Q1", "42,156.87"], - ]; - - const addedSeriesTooltipText = [ - ["Created At", "2022"], - ["Average of Total", "56.66"], - ]; - const updatedAddedSeriesTooltipText = [ - ["Created At", "2022"], - ["Custom Q2", "56.66"], - ]; + const originalSeriesName = "Q1"; + const updatedOriginalSeriesName = "Custom Q1"; + const addedSeriesName = "Q2"; + const updatedAddedSeriesName = "Custom Q2"; showTooltipForBarInSeries(originalSeriesColor, 0); - testTooltipPairs(originalSeriesTooltipText); + assertEChartsTooltip({ + header: "2022", + rows: [ + { + color: "#88BF4D", + name: originalSeriesName, + value: "42,156.87", + }, + ], + }); showTooltipForBarInSeries(addedSeriesColor, 0); - testTooltipPairs(addedSeriesTooltipText); + assertEChartsTooltip({ + header: "2022", + rows: [ + { + color: "#A989C5", + name: addedSeriesName, + value: "56.66", + }, + ], + }); openDashCardVisualizationOptions(); - updateColumnTitle("Q1", updatedOriginalSeriesTooltipText[1][0]); - updateColumnTitle("Q2", updatedAddedSeriesTooltipText[1][0]); + updateColumnTitle(originalSeriesName, updatedOriginalSeriesName); + updateColumnTitle(addedSeriesName, updatedAddedSeriesName); saveDashCardVisualizationOptions(); showTooltipForBarInSeries(originalSeriesColor, 0); - testTooltipPairs(updatedOriginalSeriesTooltipText); + assertEChartsTooltip({ + header: "2022", + rows: [ + { + color: "#88BF4D", + name: updatedOriginalSeriesName, + value: "42,156.87", + }, + ], + }); showTooltipForBarInSeries(addedSeriesColor, 0); - testTooltipPairs(updatedAddedSeriesTooltipText); + assertEChartsTooltip({ + header: "2022", + rows: [ + { + color: "#A989C5", + name: updatedAddedSeriesName, + value: "56.66", + }, + ], + }); }); it("should show percent change in tooltip for timeseries axis", () => { - testSumTotalChange(showTooltipForBarInSeries); - testAvgTotalChange(showTooltipForBarInSeries); + testSumTotalChange(showTooltipForBarInSeries, "Q1"); + testAvgTotalChange(showTooltipForBarInSeries, "Q2"); }); }); @@ -525,18 +648,30 @@ describe("scenarios > visualizations > line/bar chart > tooltips", () => { }); showTooltipForCircleInSeries("#88BF4D", 0); - testTooltipPairs([ - ["Created At", "April 2022"], - ["Sum of Total", "52.76"], - ]); + assertEChartsTooltip({ + header: "April 2022", + rows: [ + { + color: "#88BF4D", + name: "Sum of Total", + value: "52.76", + }, + ], + }); testTooltipExcludesText("Compared to previous month"); showTooltipForCircleInSeries("#88BF4D", 1); - testTooltipPairs([ - ["Created At", "May 2022"], - ["Sum of Total", "1,265.72"], - ["Compared to previous month", "+2,299.19%"], - ]); + assertEChartsTooltip({ + header: "May 2022", + rows: [ + { + color: "#88BF4D", + name: "Sum of Total", + value: "1,265.72", + secondaryValue: "+2,299.19%", + }, + ], + }); }); it("should not show percent change when previous month is missing from result data", () => { @@ -547,30 +682,54 @@ describe("scenarios > visualizations > line/bar chart > tooltips", () => { }); showTooltipForCircleInSeries("#88BF4D", 0); - testTooltipPairs([ - ["Created At", "April 2022"], - ["Sum of Total", "52.76"], - ]); + assertEChartsTooltip({ + header: "April 2022", + rows: [ + { + color: "#88BF4D", + name: "Sum of Total", + value: "52.76", + }, + ], + }); testTooltipExcludesText("Compared to previous month"); showTooltipForCircleInSeries("#88BF4D", 1); - testTooltipPairs([ - ["Created At", "June 2022"], - ["Sum of Total", "2,072.94"], - ]); + assertEChartsTooltip({ + header: "June 2022", + rows: [ + { + color: "#88BF4D", + name: "Sum of Total", + value: "2,072.94", + }, + ], + }); testTooltipExcludesText("Compared to previous month"); showTooltipForCircleInSeries("#88BF4D", 2); - testTooltipPairs([ - ["Created At", "July 2022"], - ["Sum of Total", "3,734.69"], - ["Compared to previous month", "+80.16%"], - ]); + assertEChartsTooltip({ + header: "July 2022", + rows: [ + { + color: "#88BF4D", + name: "Sum of Total", + value: "3,734.69", + secondaryValue: "+80.16%", + }, + ], + }); showTooltipForCircleInSeries("#88BF4D", 3); - testTooltipPairs([ - ["Created At", "September 2022"], - ["Sum of Total", "5,372.08"], - ]); + assertEChartsTooltip({ + header: "September 2022", + rows: [ + { + color: "#88BF4D", + name: "Sum of Total", + value: "5,372.08", + }, + ], + }); testTooltipExcludesText("Compared to previous month"); }); @@ -582,17 +741,30 @@ describe("scenarios > visualizations > line/bar chart > tooltips", () => { }); showTooltipForCircleInSeries("#88BF4D", 0); - testTooltipPairs([ - ["Created At", "April 2022"], - ["Sum of Total", "52.76"], - ]); + assertEChartsTooltip({ + header: "April 2022", + rows: [ + { + color: "#88BF4D", + name: "Sum of Total", + value: "52.76", + }, + ], + }); testTooltipExcludesText("Compared to previous month"); showTooltipForCircleInSeries("#88BF4D", 1); - testTooltipPairs([ - ["Created At", "May 2022"], - ["Sum of Total", "1,265.72"], - ]); + assertEChartsTooltip({ + header: "May 2022", + rows: [ + { + color: "#88BF4D", + name: "Sum of Total", + value: "1,265.72", + }, + ], + }); + testTooltipExcludesText("Compared to previous month"); }); }); @@ -663,7 +835,15 @@ describe("scenarios > visualizations > line/bar chart > tooltips", () => { testTooltipExcludesText("Compared to previous"); return; } - testPairedTooltipValues("Compared to previous month", change); + assertEChartsTooltip({ + rows: [ + { + color: "#88BF4D", + name: "Sum of Total", + secondaryValue: change, + }, + ], + }); }); }); @@ -678,7 +858,16 @@ describe("scenarios > visualizations > line/bar chart > tooltips", () => { testTooltipExcludesText("Compared to previous"); return; } - testPairedTooltipValues("Compared to previous week", change); + + assertEChartsTooltip({ + rows: [ + { + color: "#88BF4D", + name: "Sum of Total", + secondaryValue: change, + }, + ], + }); }); }); @@ -693,7 +882,15 @@ describe("scenarios > visualizations > line/bar chart > tooltips", () => { testTooltipExcludesText("Compared to previous"); return; } - testPairedTooltipValues("Compared to previous day", change); + assertEChartsTooltip({ + rows: [ + { + color: "#88BF4D", + name: "Sum of Total", + secondaryValue: change, + }, + ], + }); }); }); }); @@ -728,27 +925,23 @@ function setupDashboard(cardId, addedSeriesCardId) { }); }); } - function resetHoverState() { echartsTriggerBlur(); - cy.get(POPOVER_ELEMENT).should("not.exist"); cy.wait(50); } function showTooltipForCircleInSeries(seriesColor, index = 0) { resetHoverState(); - cy.get(POPOVER_ELEMENT).should("not.exist"); cartesianChartCircleWithColor(seriesColor).eq(index).realHover(); } function showTooltipForBarInSeries(seriesColor, index = 0) { resetHoverState(); - cy.get(POPOVER_ELEMENT).should("not.exist"); chartPathWithFillColor(seriesColor).eq(index).realHover(); } function testTooltipExcludesText(text) { - popover().within(() => { + echartsTooltip().within(() => { cy.contains(text).should("not.exist"); }); } diff --git a/e2e/test/scenarios/visualizations-charts/line_chart.cy.spec.js b/e2e/test/scenarios/visualizations-charts/line_chart.cy.spec.js index cf5f7f61cac24905beffce06c1c88e5cedc50c1a..c2d8a3adb2fe1bc54959327e5f8cd8037bf0f166 100644 --- a/e2e/test/scenarios/visualizations-charts/line_chart.cy.spec.js +++ b/e2e/test/scenarios/visualizations-charts/line_chart.cy.spec.js @@ -14,7 +14,7 @@ import { cartesianChartCircleWithColor, cartesianChartCircle, trendLine, - testPairedTooltipValues, + assertEChartsTooltip, } from "e2e/support/helpers"; const { ORDERS, ORDERS_ID, PRODUCTS, PRODUCTS_ID, PEOPLE, PEOPLE_ID } = @@ -286,11 +286,25 @@ describe("scenarios > visualizations > line chart", () => { }); cartesianChartCircleWithColor("#509EE3").eq(3).realHover(); - popover().within(() => { - testPairedTooltipValues("Product → Rating", "2.7"); - testPairedTooltipValues("Count", "191"); - testPairedTooltipValues("Sum of Total", "14,747.05"); - testPairedTooltipValues("Average of Quantity", "4.3"); + assertEChartsTooltip({ + header: "2.7", + rows: [ + { + color: "#509EE3", + name: "Count", + value: "191", + }, + { + color: "#88BF4D", + name: "Sum of Total", + value: "14,747.05", + }, + { + color: "#A989C5", + name: "Average of Quantity", + value: "4.3", + }, + ], }); }); @@ -562,15 +576,20 @@ describe("scenarios > visualizations > line chart", () => { assertOnYAxisValues(); showTooltipForFirstCircleInSeries("#88BF4D"); - popover().within(() => { - testPairedTooltipValues("Created At", "2022"); - testPairedTooltipValues(RENAMED_FIRST_SERIES, "42,156.87"); - }); - - showTooltipForFirstCircleInSeries("#98D9D9"); - popover().within(() => { - testPairedTooltipValues("Created At", "2022"); - testPairedTooltipValues(RENAMED_SECOND_SERIES, "54.44"); + assertEChartsTooltip({ + header: "2022", + rows: [ + { + color: "#88BF4D", + name: RENAMED_FIRST_SERIES, + value: "42,156.87", + }, + { + color: "#98D9D9", + name: RENAMED_SECOND_SERIES, + value: "54.44", + }, + ], }); }); }); @@ -611,15 +630,20 @@ describe("scenarios > visualizations > line chart", () => { assertOnYAxisValues(); showTooltipForFirstCircleInSeries("#88BF4D"); - popover().within(() => { - testPairedTooltipValues("Created At", "2022"); - testPairedTooltipValues(RENAMED_FIRST_SERIES, "42,156.87"); - }); - - showTooltipForFirstCircleInSeries("#509EE3"); - popover().within(() => { - testPairedTooltipValues("Created At", "2022"); - testPairedTooltipValues(RENAMED_SECOND_SERIES, "2,829.03"); + assertEChartsTooltip({ + header: "2022", + rows: [ + { + color: "#88BF4D", + name: RENAMED_FIRST_SERIES, + value: "42,156.87", + }, + { + color: "#509EE3", + name: RENAMED_SECOND_SERIES, + value: "2,829.03", + }, + ], }); }); }); diff --git a/e2e/test/scenarios/visualizations-charts/scatter.cy.spec.js b/e2e/test/scenarios/visualizations-charts/scatter.cy.spec.js index 483cfba50ebdb15b78ea1cf9e22d389a48f209fe..0a747efea8cdd63ef54796b7b742400c7445e51a 100644 --- a/e2e/test/scenarios/visualizations-charts/scatter.cy.spec.js +++ b/e2e/test/scenarios/visualizations-charts/scatter.cy.spec.js @@ -3,8 +3,8 @@ import { SAMPLE_DATABASE } from "e2e/support/cypress_sample_database"; import { restore, visitQuestionAdhoc, - popover, cartesianChartCircle, + assertEChartsTooltip, } from "e2e/support/helpers"; const { ORDERS, ORDERS_ID, PRODUCTS } = SAMPLE_DATABASE; @@ -42,10 +42,21 @@ describe("scenarios > visualizations > scatter", () => { }); triggerPopoverForBubble(); - popover().within(() => { - cy.findByText("Created At:"); - cy.findByText("Count:"); - cy.findByText(/Distinct values of Products? → ID:/); + assertEChartsTooltip({ + rows: [ + { + name: "Created At", + value: "May 2023", + }, + { + name: "Count", + value: "271", + }, + { + name: "Distinct values of Product → ID", + value: "137", + }, + ], }); }); @@ -68,10 +79,21 @@ describe("scenarios > visualizations > scatter", () => { }); triggerPopoverForBubble(); - popover().within(() => { - cy.findByText("Created At:"); - cy.findByText("Orders count:"); - cy.findByText("Products count:"); + assertEChartsTooltip({ + rows: [ + { + name: "Created At", + value: "May 2023", + }, + { + name: "Orders count", + value: "271", + }, + { + name: "Products count", + value: "137", + }, + ], }); }); diff --git a/e2e/test/scenarios/visualizations-charts/visualizations-charts-reproductions.cy.spec.js b/e2e/test/scenarios/visualizations-charts/visualizations-charts-reproductions.cy.spec.js index 147ee740a7b03e2f27aaa99475fe85e183564b2a..f3a9fc3be4edf35b3d00586477170ffc22cb5bbe 100644 --- a/e2e/test/scenarios/visualizations-charts/visualizations-charts-reproductions.cy.spec.js +++ b/e2e/test/scenarios/visualizations-charts/visualizations-charts-reproductions.cy.spec.js @@ -30,6 +30,7 @@ import { selectFilterOperator, saveSavedQuestion, runNativeQuery, + assertEChartsTooltip, } from "e2e/support/helpers"; const { ORDERS, ORDERS_ID } = SAMPLE_DATABASE; @@ -129,9 +130,14 @@ describe("issue 16170", { tags: "@mongo" }, () => { cartesianChartCircle().eq(-2).trigger("mousemove"); - popover().within(() => { - testPairedTooltipValues("Created At", "2019"); - testPairedTooltipValues("Count", "6,524"); + assertEChartsTooltip({ + header: "2019", + rows: [ + { + name: "Count", + value: "6,524", + }, + ], }); }); }); @@ -559,9 +565,15 @@ describe("issue 21452", () => { cartesianChartCircle().first().realHover(); - popover().within(() => { - testPairedTooltipValues("Created At", "2022"); - testPairedTooltipValues("Foo", "3,236"); + assertEChartsTooltip({ + header: "2022", + rows: [ + { + color: "#88BF4D", + name: "Foo", + value: "3,236", + }, + ], }); cy.get("@dataset.all").should("have.length", 1); @@ -853,17 +865,58 @@ describe("issue 27279", () => { // Extra step, just to be overly cautious chartPathWithFillColor("#98D9D9").realHover(); - popover().within(() => { - testPairedTooltipValues("K", "F2021"); - testPairedTooltipValues("O", "-3"); - testPairedTooltipValues("Sum of V", "1"); + + assertEChartsTooltip({ + header: "F2021", + rows: [ + { + color: "#98D9D9", + name: "-3", + value: "1", + }, + { + color: "#F2A86F", + name: "-2", + value: "(empty)", + }, + { + color: "#F9D45C", + name: "-1", + value: "(empty)", + }, + { + color: "#509EE3", + name: "0", + value: "(empty)", + }, + ], }); chartPathWithFillColor("#509EE3").realHover(); - popover().within(() => { - testPairedTooltipValues("K", "F2022"); - testPairedTooltipValues("O", "0"); - testPairedTooltipValues("Sum of V", "4"); + assertEChartsTooltip({ + header: "F2022", + rows: [ + { + color: "#98D9D9", + name: "-3", + value: "(empty)", + }, + { + color: "#F2A86F", + name: "-2", + value: "(empty)", + }, + { + color: "#F9D45C", + name: "-1", + value: "(empty)", + }, + { + color: "#509EE3", + name: "0", + value: "4", + }, + ], }); }); }); diff --git a/e2e/test/scenarios/visualizations-charts/waterfall.cy.spec.js b/e2e/test/scenarios/visualizations-charts/waterfall.cy.spec.js index 1b9b8ceced7bee93fc15f342cea74bb9c19a8fc1..e128f7b88a9819fdad0dddc66201c56f110bedb5 100644 --- a/e2e/test/scenarios/visualizations-charts/waterfall.cy.spec.js +++ b/e2e/test/scenarios/visualizations-charts/waterfall.cy.spec.js @@ -9,7 +9,7 @@ import { summarize, echartsContainer, chartPathWithFillColor, - testPairedTooltipValues, + assertEChartsTooltip, } from "e2e/support/helpers"; const { ORDERS, ORDERS_ID, PRODUCTS } = SAMPLE_DATABASE; @@ -303,7 +303,18 @@ describe("scenarios > visualizations > waterfall", () => { chartPathWithFillColor("#88BF4D").first().trigger("mousemove"); - testPairedTooltipValues("C2:", "0.2"); + assertEChartsTooltip({ + rows: [ + { + name: "C1", + value: "a", + }, + { + name: "C2", + value: "0.2", + }, + ], + }); }); describe("scenarios > visualizations > waterfall settings", () => { diff --git a/e2e/test/scenarios/visualizations-tabular/drillthroughs/chart_drill.cy.spec.js b/e2e/test/scenarios/visualizations-tabular/drillthroughs/chart_drill.cy.spec.js index 96a8391236d4c49131094971768e0769873016eb..353dd089dc516abf0c89ca25b140b7c28824ad68 100644 --- a/e2e/test/scenarios/visualizations-tabular/drillthroughs/chart_drill.cy.spec.js +++ b/e2e/test/scenarios/visualizations-tabular/drillthroughs/chart_drill.cy.spec.js @@ -21,6 +21,8 @@ import { entityPickerModalTab, tableHeaderClick, pieSliceWithColor, + assertEChartsTooltip, + echartsTriggerBlur, } from "e2e/support/helpers"; const { ORDERS, ORDERS_ID, PRODUCTS, PRODUCTS_ID, PEOPLE, PEOPLE_ID } = @@ -395,19 +397,29 @@ describe("scenarios > visualizations > drillthroughs > chart drill", () => { ); cartesianChartCircle().eq(0).realHover(); - popover().within(() => { - cy.findByText("January 1, 2026"); - cy.findByText("10"); + assertEChartsTooltip({ + header: "January 1, 2026", + rows: [ + { + color: "#EF8C8C", + name: "c", + value: "10", + }, + ], }); - queryBuilderMain() - .findByText("This question is written in SQL.") - .realHover(); + echartsTriggerBlur(); cartesianChartCircle().eq(1).realHover(); - popover().within(() => { - cy.findByText("January 2, 2026"); - cy.findByText("5"); + assertEChartsTooltip({ + header: "January 2, 2026", + rows: [ + { + color: "#EF8C8C", + name: "c", + value: "5", + }, + ], }); }); @@ -429,7 +441,21 @@ describe("scenarios > visualizations > drillthroughs > chart drill", () => { }); chartPathWithFillColor("#7172AD").first().trigger("mousemove"); - popover().findByText("12"); + assertEChartsTooltip({ + header: "2", + rows: [ + { + color: "#88BF4D", + name: "9", + value: "(empty)", + }, + { + color: "#7172AD", + name: "10", + value: "12", + }, + ], + }); }); it.skip("should drill-through a custom question that joins a native SQL question (metabase#14495)", () => { @@ -607,9 +633,30 @@ describe("scenarios > visualizations > drillthroughs > chart drill", () => { .as("doohickeyChart") .trigger("mousemove"); - popover().within(() => { - cy.findByText("Doohickey"); - cy.findByText("42"); + assertEChartsTooltip({ + header: "Category", + rows: [ + { + color: "#88BF4D", + name: "Doohickey", + value: "42", + }, + { + color: "#F9D45C", + name: "Gadget", + value: "53", + }, + { + color: "#A989C5", + name: "Gizmo", + value: "51", + }, + { + color: "#F2A86F", + name: "Widget", + value: "54", + }, + ], }); cy.get("@doohickeyChart").click(); diff --git a/e2e/test/scenarios/visualizations-tabular/visualizations-tabular-reproductions.cy.spec.js b/e2e/test/scenarios/visualizations-tabular/visualizations-tabular-reproductions.cy.spec.js index 03a490b1399a0ecd42c809a99e96e2b8c99a2639..db3cf546c6167b6d04726b079526d2047fd98e89 100644 --- a/e2e/test/scenarios/visualizations-tabular/visualizations-tabular-reproductions.cy.spec.js +++ b/e2e/test/scenarios/visualizations-tabular/visualizations-tabular-reproductions.cy.spec.js @@ -28,6 +28,7 @@ import { visualize, tableInteractive, createNativeQuestion, + assertEChartsTooltip, } from "e2e/support/helpers"; const { ORDERS, ORDERS_ID, PEOPLE, PEOPLE_ID, PRODUCTS, PRODUCTS_ID } = @@ -159,7 +160,16 @@ describe("issue 11435", () => { it("should use time formatting settings in tooltips for native questions (metabase#11435)", () => { cy.createNativeQuestion(questionDetails, { visitQuestion: true }); hoverLineDot({ index: 1 }); - popover().findByTextEnsureVisible("March 11, 2025, 8:45:17.010 PM"); + assertEChartsTooltip({ + header: "March 11, 2025, 8:45:17.010 PM", + rows: [ + { + color: "#F9D45C", + name: "TOTAL", + value: "25.03", + }, + ], + }); }); }); diff --git a/frontend/src/metabase/static-viz/components/ComboChart/ComboChart.tsx b/frontend/src/metabase/static-viz/components/ComboChart/ComboChart.tsx index 44c86efd18cce09435f05b1639b79a64a857b0ee..e8a753fdb3993949aa40e8a74b28a4b39de59eef 100644 --- a/frontend/src/metabase/static-viz/components/ComboChart/ComboChart.tsx +++ b/frontend/src/metabase/static-viz/components/ComboChart/ComboChart.tsx @@ -75,7 +75,6 @@ export const ComboChart = ({ computedVisualizationSettings, WIDTH, false, - null, renderingContext, ); diff --git a/frontend/src/metabase/visualizations/components/ChartTooltip/ChartTooltip.tsx b/frontend/src/metabase/visualizations/components/ChartTooltip/ChartTooltip.tsx index 5f965bcc129778d2ecdcb0ffd82d0a549155caa0..a4ff5178515a567832d3d26aa0133552db136e2f 100644 --- a/frontend/src/metabase/visualizations/components/ChartTooltip/ChartTooltip.tsx +++ b/frontend/src/metabase/visualizations/components/ChartTooltip/ChartTooltip.tsx @@ -18,21 +18,26 @@ export interface ChartTooltipProps { settings: VisualizationSettings; } -const ChartTooltip = ({ hovered, settings }: ChartTooltipProps) => { - const tooltip = useMemo(() => { - if (!hovered) { - return null; - } - if (!_.isEmpty(hovered.timelineEvents)) { - return <TimelineEventTooltip hovered={hovered as HoveredTimelineEvent} />; - } +export const ChartTooltipContent = ({ + hovered, + settings, +}: ChartTooltipProps) => { + if (!hovered) { + return null; + } + if (!_.isEmpty(hovered.timelineEvents)) { + return <TimelineEventTooltip hovered={hovered as HoveredTimelineEvent} />; + } - if (hovered.stackedTooltipModel) { - return <StackedDataTooltip {...hovered.stackedTooltipModel} />; - } + if (hovered.stackedTooltipModel) { + return <StackedDataTooltip {...hovered.stackedTooltipModel} />; + } + + return <KeyValuePairChartTooltip hovered={hovered} settings={settings} />; +}; - return <KeyValuePairChartTooltip hovered={hovered} settings={settings} />; - }, [hovered, settings]); +const ChartTooltip = ({ hovered, settings }: ChartTooltipProps) => { + const tooltip = <ChartTooltipContent hovered={hovered} settings={settings} />; const isNotEmpty = useMemo(() => { if (!hovered) { diff --git a/frontend/src/metabase/visualizations/components/ChartTooltip/EChartsTooltip/EChartsTooltip.module.css b/frontend/src/metabase/visualizations/components/ChartTooltip/EChartsTooltip/EChartsTooltip.module.css new file mode 100644 index 0000000000000000000000000000000000000000..293a33f1f50490845e25d1f4196748fbe84d0f99 --- /dev/null +++ b/frontend/src/metabase/visualizations/components/ChartTooltip/EChartsTooltip/EChartsTooltip.module.css @@ -0,0 +1,92 @@ +/* This class should be set to the ECharts tooltip root element via option to override ECharts defaults */ +.ChartTooltipRoot { + font: unset !important; + background-color: var(--mb-color-bg-black) !important; + border: none !important; + padding: 0 !important; + color: var(--mb-color-text-white) !important; +} + +.Table { + min-width: 240px; + border-collapse: collapse; + margin: 0.25rem 0 0.875rem 0; +} + +.TableNoHeader { + margin-top: 1rem; +} + +.Header { + display: flex; + margin: 1rem 1rem 0.25rem 1rem; + font-weight: 400; + font-size: 13px; + color: var(--mb-color-text-light); +} + +.RowFocused { + background-color: color-mix( + in srgb, + var(--mb-color-bg-black) 50%, + #000 + ) !important; +} + +.Cell { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + max-width: 240px; + padding: 0.25rem 0; + vertical-align: middle; + text-align: right; + font-weight: 600; +} + +.Cell + .Cell:not(.NameCell) { + padding-left: 0.75rem; +} + +.Cell:first-of-type { + padding-left: 1rem; +} + +.Cell:last-of-type { + padding-right: 1rem; +} + +.NameCell { + padding-left: 0.375rem; + font-weight: 400; + font-size: 14px; + text-align: left; +} + +.MainValueCell { + width: 1px; + font-size: 14px; +} + +.SecondaryValueCell { + width: 1px; + font-weight: 600; + color: var(--mb-color-text-light); +} + +.IndicatorCell { + line-height: 12px; + text-align: center; + width: 1px; +} + +.Indicator { + border-radius: 100%; + width: 12px; + height: 12px; + display: inline-block; +} + +.FooterRow .Cell { + padding-top: 0.75rem; +} diff --git a/frontend/src/metabase/visualizations/components/ChartTooltip/EChartsTooltip/EChartsTooltip.tsx b/frontend/src/metabase/visualizations/components/ChartTooltip/EChartsTooltip/EChartsTooltip.tsx new file mode 100644 index 0000000000000000000000000000000000000000..3daf0e2db1a206beb9da5eddc03b2132024d5f28 --- /dev/null +++ b/frontend/src/metabase/visualizations/components/ChartTooltip/EChartsTooltip/EChartsTooltip.tsx @@ -0,0 +1,154 @@ +import cx from "classnames"; +import type React from "react"; +import _ from "underscore"; + +import { isNotNull } from "metabase/lib/types"; + +import TooltipStyles from "./EChartsTooltip.module.css"; + +export interface EChartsTooltipRow { + /* We pass CSS class with marker colors because setting styles in tooltip rendered by ECharts violates CSP */ + markerColorClass?: string; + name: string; + isFocused?: boolean; + values: React.ReactNode[]; +} + +export interface EChartsTooltipFooter { + name: string; + values: React.ReactNode[]; +} + +export interface EChartsTooltipModel { + header?: string; + rows: EChartsTooltipRow[]; + footer?: EChartsTooltipFooter; +} + +export type EChartsTooltipProps = EChartsTooltipModel; + +export const EChartsTooltip = ({ + header, + rows, + footer, +}: EChartsTooltipProps) => { + const hasMarkers = rows.some(row => row.markerColorClass != null); + const maxValuesColumns = rows.reduce((currentMax, row) => { + return Math.max(currentMax, row.values.filter(isNotNull).length); + }, 0); + + const paddedRows = rows.map(row => { + const paddedValues = [...row.values]; + paddedValues.length = maxValuesColumns; + + return { + ...row, + values: paddedValues, + }; + }); + + return ( + <div data-testid="echarts-tooltip"> + {header != null && ( + <div + data-testid="echarts-tooltip-header" + className={TooltipStyles.Header} + > + {header} + </div> + )} + <table + className={cx(TooltipStyles.Table, { + [TooltipStyles.TableNoHeader]: header == null, + })} + > + <tbody> + {paddedRows.map((row, index) => { + return <TooltipRow key={index} {...row} />; + })} + </tbody> + {footer != null && ( + <tfoot> + <FooterRow + {...footer} + markerContent={hasMarkers ? <span /> : null} + /> + </tfoot> + )} + </table> + </div> + ); +}; + +type TooltipRowProps = EChartsTooltipRow; + +const TooltipRow = ({ + name, + values, + markerColorClass, + isFocused, +}: TooltipRowProps) => ( + <BaseRow + className={cx({ [TooltipStyles.RowFocused]: isFocused })} + name={name} + values={values} + markerContent={ + markerColorClass ? ( + <span className={cx(TooltipStyles.Indicator, markerColorClass)} /> + ) : null + } + /> +); + +const FooterRow = ({ + name, + values, + className, + markerContent, +}: BaseRowProps) => ( + <BaseRow + className={cx(TooltipStyles.FooterRow, className)} + name={name} + values={values} + markerContent={markerContent} + /> +); + +interface BaseRowProps { + className?: string; + markerContent?: React.ReactNode; + name: string; + values: React.ReactNode[]; +} + +const BaseRow = ({ className, name, values, markerContent }: BaseRowProps) => ( + <tr className={className}> + {markerContent != null ? ( + <td className={cx(TooltipStyles.Cell, TooltipStyles.IndicatorCell)}> + {markerContent} + </td> + ) : null} + {name ? ( + <td className={cx(TooltipStyles.Cell, TooltipStyles.NameCell)}>{name}</td> + ) : ( + <td className={TooltipStyles.Cell} /> + )} + {values.map((value, i) => { + const isMainValue = i === 0; + + return ( + <td + key={i} + className={cx( + TooltipStyles.Cell, + isMainValue + ? TooltipStyles.MainValueCell + : TooltipStyles.SecondaryValueCell, + )} + > + {value} + </td> + ); + })} + </tr> +); diff --git a/frontend/src/metabase/visualizations/components/ChartTooltip/EChartsTooltip/index.ts b/frontend/src/metabase/visualizations/components/ChartTooltip/EChartsTooltip/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..3d2288557d27aaade856f3740ed6b45f180c902b --- /dev/null +++ b/frontend/src/metabase/visualizations/components/ChartTooltip/EChartsTooltip/index.ts @@ -0,0 +1 @@ +export * from "./EChartsTooltip"; diff --git a/frontend/src/metabase/visualizations/components/ChartTooltip/KeyValuePairChartTooltip/KeyValuePairChartTooltip.tsx b/frontend/src/metabase/visualizations/components/ChartTooltip/KeyValuePairChartTooltip/KeyValuePairChartTooltip.tsx index 7661dbce1fff9c728ce9fd2abc9fa21b3e8d045d..29f8cc5a114d1129a56222a7218985a91fd61c8f 100644 --- a/frontend/src/metabase/visualizations/components/ChartTooltip/KeyValuePairChartTooltip/KeyValuePairChartTooltip.tsx +++ b/frontend/src/metabase/visualizations/components/ChartTooltip/KeyValuePairChartTooltip/KeyValuePairChartTooltip.tsx @@ -118,7 +118,7 @@ const getRows = (hovered: HoveredObject) => { return []; }; -const getRowFromDataPoint = (data: DataPoint) => ({ +export const getRowFromDataPoint = (data: DataPoint) => ({ ...data, key: data.key || (data.col && getFriendlyName(data.col)), }); diff --git a/frontend/src/metabase/visualizations/components/ChartTooltip/StackedDataTooltip/utils.ts b/frontend/src/metabase/visualizations/components/ChartTooltip/StackedDataTooltip/utils.ts index 9adc5f127367199a9b3e21b07c478ea240e5131c..c8fba62ef6365f6140795579270e83b2a8f5c97b 100644 --- a/frontend/src/metabase/visualizations/components/ChartTooltip/StackedDataTooltip/utils.ts +++ b/frontend/src/metabase/visualizations/components/ChartTooltip/StackedDataTooltip/utils.ts @@ -54,7 +54,7 @@ export const groupExcessiveTooltipRows = ( return [...rowsToKeep, groupedRow]; }; -export const getSortedRows = (rows: TooltipRowModel[]) => { +export const getSortedRows = <TRow extends TooltipRowModel>(rows: TRow[]) => { return [...rows].sort(({ value: leftValue }, { value: rightValue }) => { return ( (typeof rightValue === "number" ? rightValue : 0) - diff --git a/frontend/src/metabase/visualizations/components/ChartTooltip/utils.ts b/frontend/src/metabase/visualizations/components/ChartTooltip/utils.ts index 9ca56705ac71f59bae0f61f23e9e553074a5dae6..11bc261322f0edb9fbebb09fcc0d400ef550f076 100644 --- a/frontend/src/metabase/visualizations/components/ChartTooltip/utils.ts +++ b/frontend/src/metabase/visualizations/components/ChartTooltip/utils.ts @@ -1,3 +1,4 @@ +import { NULL_DISPLAY_VALUE } from "metabase/lib/constants"; import { formatValue } from "metabase/lib/formatting"; import type { OptionsType } from "metabase/lib/formatting/types"; import type { @@ -29,5 +30,5 @@ export const formatValueForTooltip = ({ options.scale = 1; } - return formatValue(value, options); + return formatValue(value, options) ?? NULL_DISPLAY_VALUE; }; diff --git a/frontend/src/metabase/visualizations/components/Visualization/Visualization.jsx b/frontend/src/metabase/visualizations/components/Visualization/Visualization.jsx index f1c4b1f4edad0ce077c7439a9fd304002bc08cab..bd42c69d3d916c4a64e314ae3d7836990d8c5a60 100644 --- a/frontend/src/metabase/visualizations/components/Visualization/Visualization.jsx +++ b/frontend/src/metabase/visualizations/components/Visualization/Visualization.jsx @@ -1,6 +1,5 @@ /* eslint-disable react/prop-types */ import cx from "classnames"; -import { assoc } from "icepick"; import { PureComponent } from "react"; import { connect } from "react-redux"; import { t } from "ttag"; @@ -81,7 +80,6 @@ class Visualization extends PureComponent { error: null, genericError: null, warnings: [], - yAxisSplit: null, series: null, visualization: null, computedSettings: {}, @@ -158,7 +156,6 @@ class Visualization extends PureComponent { error: null, genericError: null, warnings: [], - yAxisSplit: null, series: series, visualization: visualization, computedSettings: computedSettings, @@ -178,14 +175,6 @@ class Visualization extends PureComponent { handleHoverChange = hovered => { if (hovered) { - const { yAxisSplit } = this.state; - // if we have Y axis split info then find the Y axis index (0 = left, 1 = right) - if (yAxisSplit) { - const axisIndex = _.findIndex(yAxisSplit, indexes => - _.contains(indexes, hovered.index), - ); - hovered = assoc(hovered, "axisIndex", axisIndex); - } this.setState({ hovered }); // If we previously set a timeout for clearing the hover clear it now since we received // a new hover. @@ -319,8 +308,11 @@ class Visualization extends PureComponent { }); }; - onRender = ({ yAxisSplit, warnings = [] } = {}) => { - this.setState({ yAxisSplit, warnings }); + onRender = ({ warnings = [] } = {}) => { + const currentWarnings = this.state.warnings; + if (!_.isEqual(currentWarnings, warnings)) { + this.setState({ warnings }); + } }; onRenderError = error => { diff --git a/frontend/src/metabase/visualizations/echarts/cartesian/option/axis.ts b/frontend/src/metabase/visualizations/echarts/cartesian/option/axis.ts index e9f6eceb6f55b13de34acb2f31c2630d1365a010..a37d0bcbacdfd2ac12f3fd364818ab2036dbb171 100644 --- a/frontend/src/metabase/visualizations/echarts/cartesian/option/axis.ts +++ b/frontend/src/metabase/visualizations/echarts/cartesian/option/axis.ts @@ -5,7 +5,6 @@ import { parseNumberValue } from "metabase/lib/number"; import { CHART_STYLE } from "metabase/visualizations/echarts/cartesian/constants/style"; import type { BaseCartesianChartModel, - DataKey, Extent, NumericAxisScaleTransforms, NumericXAxisModel, @@ -362,23 +361,15 @@ export const buildMetricAxis = ( settings: ComputedVisualizationSettings, position: "left" | "right", hasSplitLine: boolean, - hoveredSeriesDataKey: DataKey | null, renderingContext: RenderingContext, ): YAXisOption => { const shouldFlipAxisName = position === "right"; const nameGap = getAxisNameGap(ticksWidth); const range = getYAxisRange(axisModel, yAxisScaleTransforms, settings); - let isFocused = false; - let isBlurred = false; - - if (hoveredSeriesDataKey != null) { - isFocused = axisModel.seriesKeys.includes(hoveredSeriesDataKey); - isBlurred = !isFocused; - } return { - show: !isBlurred, + show: true, scale: !!settings["graph.y_axis.unpin_from_zero"], type: "value", ...range, @@ -389,7 +380,7 @@ export const buildMetricAxis = ( shouldFlipAxisName ? -90 : undefined, ), splitLine: - (hasSplitLine || isFocused) && !!settings["graph.y_axis.axis_enabled"] + hasSplitLine && !!settings["graph.y_axis.axis_enabled"] ? { lineStyle: { type: 5, @@ -421,7 +412,6 @@ const buildMetricsAxes = ( chartModel: BaseCartesianChartModel, chartMeasurements: ChartMeasurements, settings: ComputedVisualizationSettings, - hoveredSeriesDataKey: DataKey | null, renderingContext: RenderingContext, ): YAXisOption[] => { const axes: YAXisOption[] = []; @@ -436,7 +426,6 @@ const buildMetricsAxes = ( settings, "left", true, - hoveredSeriesDataKey, renderingContext, ), ); @@ -452,7 +441,6 @@ const buildMetricsAxes = ( settings, "right", isOnlyAxis, - hoveredSeriesDataKey, renderingContext, ), ); @@ -467,7 +455,6 @@ export const buildAxes = ( chartMeasurements: ChartMeasurements, settings: ComputedVisualizationSettings, hasTimelineEvents: boolean, - hoveredSeriesDataKey: DataKey | null, renderingContext: RenderingContext, ) => { return { @@ -483,7 +470,6 @@ export const buildAxes = ( chartModel, chartMeasurements, settings, - hoveredSeriesDataKey, renderingContext, ), }; diff --git a/frontend/src/metabase/visualizations/echarts/cartesian/option/index.ts b/frontend/src/metabase/visualizations/echarts/cartesian/option/index.ts index d4b943bc67062b6e30c35deac57efec6259264cf..f75c987ae8622bfe8c508e85a2e73eb2b0caac93 100644 --- a/frontend/src/metabase/visualizations/echarts/cartesian/option/index.ts +++ b/frontend/src/metabase/visualizations/echarts/cartesian/option/index.ts @@ -6,10 +6,7 @@ import { POSITIVE_STACK_TOTAL_DATA_KEY, X_AXIS_DATA_KEY, } from "metabase/visualizations/echarts/cartesian/constants/dataset"; -import type { - DataKey, - CartesianChartModel, -} from "metabase/visualizations/echarts/cartesian/model/types"; +import type { CartesianChartModel } from "metabase/visualizations/echarts/cartesian/model/types"; import { buildAxes } from "metabase/visualizations/echarts/cartesian/option/axis"; import { buildEChartsSeries } from "metabase/visualizations/echarts/cartesian/option/series"; import { getTimelineEventsSeries } from "metabase/visualizations/echarts/cartesian/timeline-events/option"; @@ -50,7 +47,6 @@ export const getCartesianChartOption = ( settings: ComputedVisualizationSettings, chartWidth: number, isAnimated: boolean, - hoveredSeriesDataKey: DataKey | null, renderingContext: RenderingContext, ): EChartsCoreOption => { const hasTimelineEvents = timelineEventsModel != null; @@ -131,7 +127,6 @@ export const getCartesianChartOption = ( chartMeasurements, settings, hasTimelineEvents, - hoveredSeriesDataKey, renderingContext, ), }; diff --git a/frontend/src/metabase/visualizations/echarts/cartesian/option/tooltip.tsx b/frontend/src/metabase/visualizations/echarts/cartesian/option/tooltip.tsx new file mode 100644 index 0000000000000000000000000000000000000000..3f3fe90c7d8a4ea8318025ff2f34ff43c292a5eb --- /dev/null +++ b/frontend/src/metabase/visualizations/echarts/cartesian/option/tooltip.tsx @@ -0,0 +1,77 @@ +import type { TooltipOption } from "echarts/types/dist/shared"; +import { renderToString } from "react-dom/server"; + +import { EChartsTooltip } from "metabase/visualizations/components/ChartTooltip/EChartsTooltip"; +import type { ComputedVisualizationSettings } from "metabase/visualizations/types"; +import { getTooltipModel } from "metabase/visualizations/visualizations/CartesianChart/events"; + +import { TOOLTIP_BASE_OPTION } from "../../tooltip"; +import { + GOAL_LINE_SERIES_ID, + TIMELINE_EVENT_SERIES_ID, +} from "../constants/dataset"; +import type { BaseCartesianChartModel, DataKey } from "../model/types"; + +interface ChartItemTooltip { + dataIndex: number; + seriesId?: DataKey | null; + settings: ComputedVisualizationSettings; + chartModel: BaseCartesianChartModel; +} + +const ChartItemTooltip = ({ + chartModel, + settings, + dataIndex, + seriesId, +}: ChartItemTooltip) => { + if (dataIndex == null || seriesId == null) { + return null; + } + + const tooltipModel = getTooltipModel( + chartModel, + settings, + dataIndex, + seriesId, + ); + + if (!tooltipModel) { + return null; + } + + return <EChartsTooltip {...tooltipModel} />; +}; + +export const getTooltipOption = ( + chartModel: BaseCartesianChartModel, + settings: ComputedVisualizationSettings, +): TooltipOption => { + return { + trigger: "item", + ...TOOLTIP_BASE_OPTION, + formatter: params => { + if (Array.isArray(params)) { + return ""; + } + + const { dataIndex, seriesId } = params; + + if ( + seriesId === TIMELINE_EVENT_SERIES_ID || + seriesId === GOAL_LINE_SERIES_ID + ) { + return ""; + } + + return renderToString( + <ChartItemTooltip + settings={settings} + chartModel={chartModel} + dataIndex={dataIndex} + seriesId={seriesId} + />, + ); + }, + }; +}; diff --git a/frontend/src/metabase/visualizations/echarts/cartesian/scatter/option/index.ts b/frontend/src/metabase/visualizations/echarts/cartesian/scatter/option/index.ts index 377e987858cfcf7352d77914a0af63e11c6fb63b..bfe92da43f4f47559e4d2d9ec3c8e4ef3000f50f 100644 --- a/frontend/src/metabase/visualizations/echarts/cartesian/scatter/option/index.ts +++ b/frontend/src/metabase/visualizations/echarts/cartesian/scatter/option/index.ts @@ -104,7 +104,6 @@ export function getScatterPlotOption( chartMeasurements, settings, hasTimelineEvents, - null, renderingContext, ), }; diff --git a/frontend/src/metabase/visualizations/echarts/cartesian/waterfall/option/index.ts b/frontend/src/metabase/visualizations/echarts/cartesian/waterfall/option/index.ts index 9e45b0f7a7d6f734e52c4a49c351545f720b90ab..6c54fb34e853f27a2c0472b537ba83b38dbf8346 100644 --- a/frontend/src/metabase/visualizations/echarts/cartesian/waterfall/option/index.ts +++ b/frontend/src/metabase/visualizations/echarts/cartesian/waterfall/option/index.ts @@ -255,7 +255,6 @@ export const getWaterfallChartOption = ( chartMeasurements, settings, hasTimelineEvents, - null, renderingContext, ), }; diff --git a/frontend/src/metabase/visualizations/echarts/index.ts b/frontend/src/metabase/visualizations/echarts/index.ts index 5c923798eaadb7d1d15815d0f07c4f5943c8dd76..76961d1ca2c90aae938807b5d50cb20cbb105302 100644 --- a/frontend/src/metabase/visualizations/echarts/index.ts +++ b/frontend/src/metabase/visualizations/echarts/index.ts @@ -13,6 +13,7 @@ import { ToolboxComponent, DatasetComponent, GraphicComponent, + TooltipComponent, } from "echarts/components"; import { use } from "echarts/core"; import { LabelLayout } from "echarts/features"; @@ -35,5 +36,6 @@ export const registerEChartsModules = () => { BrushComponent, DatasetComponent, LabelLayout, + TooltipComponent, ]); }; diff --git a/frontend/src/metabase/visualizations/echarts/pie/tooltip.tsx b/frontend/src/metabase/visualizations/echarts/pie/tooltip.tsx new file mode 100644 index 0000000000000000000000000000000000000000..56bccf9526c1a2751df9198fec4f1b81eccab563 --- /dev/null +++ b/frontend/src/metabase/visualizations/echarts/pie/tooltip.tsx @@ -0,0 +1,47 @@ +import type { TooltipOption } from "echarts/types/dist/shared"; +import { renderToString } from "react-dom/server"; + +import { EChartsTooltip } from "metabase/visualizations/components/ChartTooltip/EChartsTooltip"; +import { getTooltipModel } from "metabase/visualizations/visualizations/PieChart/use-chart-events"; + +import { TOOLTIP_BASE_OPTION } from "../tooltip"; + +import type { PieChartFormatters } from "./format"; +import type { PieChartModel } from "./model/types"; + +interface ChartItemTooltip { + chartModel: PieChartModel; + formatters: PieChartFormatters; + dataIndex: number; +} + +const ChartItemTooltip = ({ + chartModel, + formatters, + dataIndex, +}: ChartItemTooltip) => { + const tooltipModel = getTooltipModel(dataIndex, chartModel, formatters); + return <EChartsTooltip {...tooltipModel} />; +}; + +export const getTooltipOption = ( + chartModel: PieChartModel, + formatters: PieChartFormatters, +): TooltipOption => { + return { + ...TOOLTIP_BASE_OPTION, + trigger: "item", + formatter: params => { + if (Array.isArray(params) || typeof params.dataIndex !== "number") { + return ""; + } + return renderToString( + <ChartItemTooltip + formatters={formatters} + chartModel={chartModel} + dataIndex={params.dataIndex} + />, + ); + }, + }; +}; diff --git a/frontend/src/metabase/visualizations/echarts/tooltip/index.tsx b/frontend/src/metabase/visualizations/echarts/tooltip/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..0922192eb402fed062bcc7d32b67abe945b29f81 --- /dev/null +++ b/frontend/src/metabase/visualizations/echarts/tooltip/index.tsx @@ -0,0 +1,83 @@ +import { useMemo } from "react"; + +import { isNotNull } from "metabase/lib/types"; +import TooltipStyles from "metabase/visualizations/components/ChartTooltip/EChartsTooltip/EChartsTooltip.module.css"; + +import type { BaseCartesianChartModel } from "../cartesian/model/types"; +import type { PieChartModel } from "../pie/model/types"; + +export const TOOLTIP_BASE_OPTION = { + confine: true, + appendTo: () => { + let container = document.querySelector( + ".echarts-tooltip-container", + ) as HTMLDivElement; + if (!container) { + container = document.createElement("div"); + container.classList.add("echarts-tooltip-container"); + container.style.setProperty("overflow", "hidden"); + container.style.setProperty("height", "100%"); + container.style.setProperty("position", "relative"); + container.style.setProperty("pointer-events", "none"); + + document.body.append(container); + } + + return container; + }, + className: TooltipStyles.ChartTooltipRoot, +}; + +export const getMarkerColorClass = (hexColor: string) => { + return `marker-${hexColor.slice(1, 7)}`; +}; + +export const useInjectSeriesColorsClasses = (hexColors: string[]) => { + const cssString = useMemo(() => { + if (hexColors.length === 0) { + return null; + } + + return hexColors + .map(color => { + const cssClassName = getMarkerColorClass(color); + return ` + .${cssClassName} { + background-color: ${color}; + }`; + }) + .join("\n"); + }, [hexColors]); + + const style = useMemo( + () => + cssString !== null ? ( + <style nonce={window.MetabaseNonce}>{cssString}</style> + ) : null, + [cssString], + ); + + return style; +}; + +export const useCartesianChartSeriesColorsClasses = ( + chartModel: BaseCartesianChartModel, +) => { + const hexColors = useMemo( + () => + chartModel.seriesModels + .map(seriesModel => seriesModel.color) + .filter(isNotNull), + [chartModel], + ); + + return useInjectSeriesColorsClasses(hexColors); +}; + +export const usePieChartValuesColorsClasses = (chartModel: PieChartModel) => { + const hexColors = useMemo(() => { + return chartModel.slices.map(slice => slice.data.color); + }, [chartModel.slices]); + + return useInjectSeriesColorsClasses(hexColors); +}; diff --git a/frontend/src/metabase/visualizations/lib/settings/graph.js b/frontend/src/metabase/visualizations/lib/settings/graph.js index aeaeb84d2d84f939d94bca1417eb35e16ee75ea8..86bc88e32838dd72da11866abdbd2d1f88b42cdc 100644 --- a/frontend/src/metabase/visualizations/lib/settings/graph.js +++ b/frontend/src/metabase/visualizations/lib/settings/graph.js @@ -262,9 +262,10 @@ export const LEGEND_SETTINGS = { export const TOOLTIP_SETTINGS = { "graph.tooltip_type": { - getDefault: (series, settings) => { - const shouldShowComparisonTooltip = - settings["stackable.stack_type"] != null; + getDefault: ([{ card }]) => { + const shouldShowComparisonTooltip = !["waterfall", "scatter"].includes( + card.display, + ); return shouldShowComparisonTooltip ? "series_comparison" : "default"; }, hidden: true, diff --git a/frontend/src/metabase/visualizations/types/hover.ts b/frontend/src/metabase/visualizations/types/hover.ts index 897f76a3e6221cf4786eaa0bb9afd6c50c683a42..f59ffa6ed7d8a70cb3ea49a801f3b764e4032a2d 100644 --- a/frontend/src/metabase/visualizations/types/hover.ts +++ b/frontend/src/metabase/visualizations/types/hover.ts @@ -1,5 +1,5 @@ import type { ClickObjectDataRow } from "metabase-lib"; -import type { TimelineEvent } from "metabase-types/api"; +import type { RowValue, TimelineEvent } from "metabase-types/api"; import type { RemappingHydratedDatasetColumn } from "./columns"; import type { ComputedVisualizationSettings } from "./visualization"; @@ -21,8 +21,8 @@ export interface HoveredTimelineEvent { export interface TooltipRowModel { color?: string; name: string; - value: unknown; - formatter?: (value: unknown) => string; + value: RowValue; + formatter?: (value: RowValue) => string; } export interface StackedTooltipModel { @@ -37,7 +37,6 @@ export interface StackedTooltipModel { export interface HoveredObject { index?: number; - axisIndex?: number; seriesIndex?: number; seriesId?: number; datumIndex?: number; diff --git a/frontend/src/metabase/visualizations/visualizations/CartesianChart/CartesianChart.tsx b/frontend/src/metabase/visualizations/visualizations/CartesianChart/CartesianChart.tsx index d4af656f391e92e018e60deb3c7bfe0638f365f4..ceb756357c4b3e1956411f7a3c0bab9d1dd0fb36 100644 --- a/frontend/src/metabase/visualizations/visualizations/CartesianChart/CartesianChart.tsx +++ b/frontend/src/metabase/visualizations/visualizations/CartesianChart/CartesianChart.tsx @@ -4,6 +4,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { ChartRenderingErrorBoundary } from "metabase/visualizations/components/ChartRenderingErrorBoundary"; import LegendCaption from "metabase/visualizations/components/legend/LegendCaption"; import { getLegendItems } from "metabase/visualizations/echarts/cartesian/model/legend"; +import { useCartesianChartSeriesColorsClasses } from "metabase/visualizations/echarts/tooltip"; import type { VisualizationProps } from "metabase/visualizations/types"; import { CartesianChartLegendLayout, @@ -88,6 +89,7 @@ function _CartesianChart(props: VisualizationProps) { }, []); const canSelectTitle = !!onChangeCardAndRun; + const seriesColorsCss = useCartesianChartSeriesColorsClasses(chartModel); return ( <CartesianChartRoot isQueryBuilder={isQueryBuilder}> @@ -129,6 +131,7 @@ function _CartesianChart(props: VisualizationProps) { onInit={handleInit} /> </CartesianChartLegendLayout> + {seriesColorsCss} </CartesianChartRoot> ); } diff --git a/frontend/src/metabase/visualizations/visualizations/CartesianChart/constants.ts b/frontend/src/metabase/visualizations/visualizations/CartesianChart/constants.ts deleted file mode 100644 index 1e59032646c9fe2e3afa47fdb20bdf9057a7b411..0000000000000000000000000000000000000000 --- a/frontend/src/metabase/visualizations/visualizations/CartesianChart/constants.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { t } from "ttag"; - -import type { CartesianChartDateTimeAbsoluteUnit } from "metabase/visualizations/echarts/cartesian/model/types"; - -export const DATETIME_ABSOLUTE_UNIT_COMPARISON: Record< - CartesianChartDateTimeAbsoluteUnit, - string -> = { - year: t`Compared to previous year`, - quarter: t`Compared to previous quarter`, - month: t`Compared to previous month`, - week: t`Compared to previous week`, - day: t`Compared to previous day`, - hour: t`Compared to previous hour`, - minute: t`Compared to previous minute`, - second: t`Compared to previous second`, - ms: t`Compared to previous millisecond`, -}; diff --git a/frontend/src/metabase/visualizations/visualizations/CartesianChart/events.ts b/frontend/src/metabase/visualizations/visualizations/CartesianChart/events.ts index 5fcfbf05c78dfe829f1d26edc200384be475337c..a5ffb96b558c03271bd6899ee2fdaff2d376fc17 100644 --- a/frontend/src/metabase/visualizations/visualizations/CartesianChart/events.ts +++ b/frontend/src/metabase/visualizations/visualizations/CartesianChart/events.ts @@ -1,3 +1,4 @@ +import { t } from "ttag"; import _ from "underscore"; import { NULL_DISPLAY_VALUE } from "metabase/lib/constants"; @@ -8,6 +9,17 @@ import { parseTimestamp, } from "metabase/lib/time-dayjs"; import { checkNumber, isNotNull } from "metabase/lib/types"; +import { formatPercent } from "metabase/static-viz/lib/numbers"; +import type { + EChartsTooltipModel, + EChartsTooltipRow, +} from "metabase/visualizations/components/ChartTooltip/EChartsTooltip"; +import { getRowFromDataPoint } from "metabase/visualizations/components/ChartTooltip/KeyValuePairChartTooltip/KeyValuePairChartTooltip"; +import { + getPercent, + getTotalValue, +} from "metabase/visualizations/components/ChartTooltip/StackedDataTooltip/utils"; +import { formatValueForTooltip } from "metabase/visualizations/components/ChartTooltip/utils"; import { ORIGINAL_INDEX_DATA_KEY, X_AXIS_DATA_KEY, @@ -24,8 +36,10 @@ import type { Datum, DimensionModel, SeriesModel, + StackModel, } from "metabase/visualizations/echarts/cartesian/model/types"; import type { TimelineEventsModel } from "metabase/visualizations/echarts/cartesian/timeline-events/types"; +import { getMarkerColorClass } from "metabase/visualizations/echarts/tooltip"; import type { EChartsSeriesMouseEvent, EChartsSeriesBrushEndEvent, @@ -36,13 +50,11 @@ import { isRemappedToString, } from "metabase/visualizations/lib/renderer_utils"; import { dimensionIsTimeseries } from "metabase/visualizations/lib/timeseries"; -import { formatValueForTooltip } from "metabase/visualizations/lib/tooltip"; import { getFriendlyName } from "metabase/visualizations/lib/utils"; import type { ComputedVisualizationSettings, DataPoint, OnChangeCardAndRun, - TooltipRowModel, } from "metabase/visualizations/types"; import type { ClickObject, ClickObjectDimension } from "metabase-lib"; import * as Lib from "metabase-lib"; @@ -56,8 +68,6 @@ import type { TimelineEventId, } from "metabase-types/api"; -import { DATETIME_ABSOLUTE_UNIT_COMPARISON } from "./constants"; - export const parseDataKey = (dataKey: DataKey) => { let cardId: Nullable<CardId> = null; @@ -191,18 +201,13 @@ const getEventColumnsData = ( return dataPoints; }; -const getTooltipFooterData = ( +const computeDiffWithPreviousPeriod = ( chartModel: BaseCartesianChartModel, - display: string, seriesIndex: number, dataIndex: number, -): DataPoint[] => { - if ( - display === "scatter" || - display === "waterfall" || - !isTimeSeriesAxis(chartModel.xAxisModel) - ) { - return []; +): string | null => { + if (!isTimeSeriesAxis(chartModel.xAxisModel)) { + return null; } const datum = chartModel.dataset[dataIndex]; @@ -213,8 +218,8 @@ const getTooltipFooterData = ( const previousValue = chartModel.dataset[dataIndex - 1]?.[seriesModel.dataKey]; - if (previousValue == null) { - return []; + if (previousValue == null || currentValue == null) { + return null; } const previousDate = parseTimestamp( chartModel.dataset[dataIndex - 1][X_AXIS_DATA_KEY], @@ -246,84 +251,12 @@ const getTooltipFooterData = ( } if (!isOneIntervalAgo) { - return []; + return null; } const change = computeChange(previousValue, currentValue); - return [ - { - key: DATETIME_ABSOLUTE_UNIT_COMPARISON[unit], - col: seriesModel.column, - value: formatChangeWithSign(change), - }, - ]; -}; - -const getStackedTooltipModel = ( - chartModel: BaseCartesianChartModel, - settings: ComputedVisualizationSettings, - seriesIndex: number, - dataIndex: number, -) => { - const hoveredSeries = chartModel.seriesModels[seriesIndex]; - const seriesStack = chartModel.stackModels.find(stackModel => - stackModel.seriesKeys.includes(hoveredSeries.dataKey), - ); - - if (!seriesStack) { - return undefined; - } - - const column = - chartModel.leftAxisModel?.column ?? chartModel.rightAxisModel?.column; - - const formatter = (value: unknown) => - String( - formatValueForTooltip({ - value, - settings, - column, - }), - ); - - const rows: (TooltipRowModel & { dataKey: DataKey })[] = - chartModel.seriesModels - .filter(seriesModel => - seriesStack?.seriesKeys.includes(seriesModel.dataKey), - ) - .map(seriesModel => { - return { - dataKey: seriesModel.dataKey, - name: seriesModel.name, - color: seriesModel.color, - value: chartModel.dataset[dataIndex][seriesModel.dataKey], - formatter, - }; - }); - const [headerRows, bodyRows] = _.partition( - rows, - row => row.dataKey === hoveredSeries.dataKey, - ); - - const dimensionValue = chartModel.dataset[dataIndex][X_AXIS_DATA_KEY]; - - const headerTitle = String( - formatValueForTooltip({ - value: dimensionValue, - column: chartModel.dimensionModel.column, - settings, - }), - ); - - return { - headerTitle, - headerRows, - bodyRows: bodyRows.filter(row => row.value != null), - totalFormatter: formatter, - showTotal: true, - showPercentages: true, - }; + return formatChangeWithSign(change); }; export const canBrush = ( @@ -359,31 +292,33 @@ function getDataIndex( return originalDataIndex ?? echartsDataIndex; } -const CIRCLE_PATH = "M1 0A1 1 0 1 1 1 -0.0001"; - -// HACK: Native events may wrongly have the entire series path or the entire svg as target when hovering a single datum -const isValidDatumElement = ( - element: SVGElement | undefined, - seriesType: string, +export const getSeriesHovered = ( + chartModel: BaseCartesianChartModel, + event: EChartsSeriesMouseEvent, ) => { - if (element?.nodeName === "svg") { - return false; - } + const { dataIndex: echartsDataIndex, seriesId } = event; + const dataIndex = getDataIndex( + chartModel.transformedDataset, + echartsDataIndex, + ); + const seriesIndex = findSeriesModelIndexById(chartModel, seriesId); - if (seriesType !== "line") { - return true; + if (seriesIndex < 0 || dataIndex == null) { + return; } - return element?.getAttribute("d") === CIRCLE_PATH; + return { + index: seriesIndex, + datumIndex: dataIndex, + }; }; export const getSeriesHoverData = ( chartModel: BaseCartesianChartModel, settings: ComputedVisualizationSettings, - display: string, - event: EChartsSeriesMouseEvent, + echartsDataIndex: number, + seriesId: DataKey, ) => { - const { dataIndex: echartsDataIndex, seriesId } = event; const dataIndex = getDataIndex( chartModel.transformedDataset, echartsDataIndex, @@ -394,37 +329,218 @@ export const getSeriesHoverData = ( return; } - const target = event.event.event.target as SVGElement | undefined; + return { + settings, + isAlreadyScaled: true, + index: seriesIndex, + datumIndex: dataIndex, + }; +}; - // TODO: For some reason ECharts sometimes trigger series mouse move element with the root SVG as target - // Find a better fix - if (!isValidDatumElement(target, event.seriesType)) { - return; +export const getTooltipModel = ( + chartModel: BaseCartesianChartModel, + settings: ComputedVisualizationSettings, + echartsDataIndex: number, + seriesDataKey: DataKey, +): EChartsTooltipModel | null => { + const dataIndex = getDataIndex( + chartModel.transformedDataset, + echartsDataIndex, + ); + + if (dataIndex == null) { + return null; + } + const datum = chartModel.dataset[dataIndex]; + const seriesIndex = chartModel.seriesModels.findIndex( + seriesModel => seriesModel.dataKey === seriesDataKey, + ); + const hoveredSeries = chartModel.seriesModels[seriesIndex]; + const seriesStack = chartModel.stackModels.find(stackModel => + stackModel.seriesKeys.includes(hoveredSeries.dataKey), + ); + + const shouldShowAllColumnValuesTooltip = + settings["graph.tooltip_type"] === "default"; + if (shouldShowAllColumnValuesTooltip) { + return getAllColumnsTooltipModel( + chartModel, + settings, + dataIndex, + seriesDataKey, + ); } - const data = getEventColumnsData(chartModel, seriesIndex, dataIndex); - const footerData = getTooltipFooterData( + const shouldShowStackedTooltip = seriesStack != null; + if (shouldShowStackedTooltip) { + return getStackedTooltipModel( + chartModel, + settings, + seriesStack, + seriesDataKey, + dataIndex, + datum, + ); + } + + return getSeriesOnlyTooltipModel( chartModel, - display, - seriesIndex, + settings, + datum, dataIndex, + seriesDataKey, ); +}; - const stackedTooltipModel = - settings["graph.tooltip_type"] === "series_comparison" - ? getStackedTooltipModel(chartModel, settings, seriesIndex, dataIndex) - : undefined; +const getAllColumnsTooltipModel = ( + chartModel: BaseCartesianChartModel, + settings: ComputedVisualizationSettings, + dataIndex: number, + seriesDataKey: DataKey, +): EChartsTooltipModel | null => { + const seriesIndex = findSeriesModelIndexById(chartModel, seriesDataKey); + const rows = getEventColumnsData(chartModel, seriesIndex, dataIndex) + .map(getRowFromDataPoint) + .map(dataPoint => { + return { + name: dataPoint.key, + values: [ + formatValueForTooltip({ + isAlreadyScaled: true, + value: dataPoint.value, + column: dataPoint.col, + settings, + }), + ], + }; + }); return { - settings, - isAlreadyScaled: true, - index: seriesIndex, - datumIndex: dataIndex, - event: event.event.event, - element: target, - data, - footerData, - stackedTooltipModel, + rows, + }; +}; + +export const getSeriesOnlyTooltipModel = ( + chartModel: BaseCartesianChartModel, + settings: ComputedVisualizationSettings, + datum: Datum, + dataIndex: number, + seriesDataKey: DataKey, +): EChartsTooltipModel | null => { + const header = String( + formatValueForTooltip({ + value: datum[X_AXIS_DATA_KEY], + column: chartModel.dimensionModel.column, + settings, + }), + ); + + const rows: EChartsTooltipRow[] = chartModel.seriesModels.map( + (seriesModel, seriesIndex) => { + const prevValue = computeDiffWithPreviousPeriod( + chartModel, + seriesIndex, + dataIndex, + ); + return { + isFocused: + chartModel.seriesModels.length > 1 && + seriesModel.dataKey === seriesDataKey, + name: seriesModel.name, + markerColorClass: getMarkerColorClass(seriesModel.color), + values: [ + formatValueForTooltip({ + value: datum[seriesModel.dataKey], + column: seriesModel.column, + settings, + isAlreadyScaled: true, + }), + prevValue, + ], + }; + }, + ); + + return { + header, + rows, + }; +}; + +export const getStackedTooltipModel = ( + chartModel: BaseCartesianChartModel, + settings: ComputedVisualizationSettings, + seriesStack: StackModel, + seriesDataKey: DataKey, + dataIndex: number, + datum: Datum, +): EChartsTooltipModel | null => { + const stackSeriesRows = chartModel.seriesModels + .filter(seriesModel => + seriesStack?.seriesKeys.includes(seriesModel.dataKey), + ) + .map(seriesModel => { + return { + isFocused: seriesModel.dataKey === seriesDataKey, + name: seriesModel.name, + color: seriesModel.color, + value: chartModel.dataset[dataIndex][seriesModel.dataKey], + dataKey: seriesModel.dataKey, + }; + }); + + // Reverse rows as they appear reversed on the stacked chart to match the order + stackSeriesRows.reverse(); + + const formatter = (value: unknown) => + String( + formatValueForTooltip({ + isAlreadyScaled: true, + value, + settings, + column: + chartModel.leftAxisModel?.column ?? chartModel.rightAxisModel?.column, + }), + ); + + const rowsTotal = getTotalValue(stackSeriesRows); + const isShowingTotalSensible = stackSeriesRows.length > 1; + const header = String( + formatValueForTooltip({ + value: datum[X_AXIS_DATA_KEY], + column: chartModel.dimensionModel.column, + settings, + }), + ); + + const formattedTooltipRows: EChartsTooltipRow[] = stackSeriesRows + .filter(row => row.value != null) + .map(tooltipRow => { + return { + isFocused: tooltipRow.isFocused, + name: tooltipRow.name, + markerColorClass: tooltipRow.color + ? getMarkerColorClass(tooltipRow.color) + : undefined, + values: [ + formatter(tooltipRow.value), + formatPercent(getPercent(rowsTotal, tooltipRow.value) ?? 0), + ], + }; + }); + + return { + header, + rows: formattedTooltipRows, + footer: isShowingTotalSensible + ? { + name: t`Total`, + values: [ + formatter(rowsTotal), + formatPercent(getPercent(rowsTotal, rowsTotal) ?? 0), + ], + } + : undefined, }; }; diff --git a/frontend/src/metabase/visualizations/visualizations/CartesianChart/use-chart-events.ts b/frontend/src/metabase/visualizations/visualizations/CartesianChart/use-chart-events.ts index 0b9f7e27a72564d95436ee6e5ac8831ad5d71b10..07d2ea7f9a937f599eea52ca47f8b839e7cb2dc4 100644 --- a/frontend/src/metabase/visualizations/visualizations/CartesianChart/use-chart-events.ts +++ b/frontend/src/metabase/visualizations/visualizations/CartesianChart/use-chart-events.ts @@ -23,14 +23,17 @@ import { getBrushData, getGoalLineHoverData, getSeriesClickData, - getSeriesHoverData, + getSeriesHovered, getTimelineEventsForEvent, getTimelineEventsHoverData, hasSelectedTimelineEvents, } from "metabase/visualizations/visualizations/CartesianChart/events"; import type { CardId } from "metabase-types/api"; -import { getHoveredEChartsSeriesDataKeyAndIndex } from "./utils"; +import { + getHoveredEChartsSeriesDataKeyAndIndex, + getHoveredSeriesDataKey, +} from "./utils"; export const useChartEvents = ( chartRef: React.MutableRefObject<EChartsType | undefined>, @@ -69,6 +72,42 @@ export const useChartEvents = ( [card, onChangeCardAndRun, rawSeries], ); + const hoveredSeriesDataKey = useMemo( + () => getHoveredSeriesDataKey(chartModel.seriesModels, hovered), + [chartModel.seriesModels, hovered], + ); + + useEffect( + function updateYAxisVisibility() { + const hasSingleYAxis = !( + chartModel.leftAxisModel != null && chartModel.rightAxisModel != null + ); + + if (hasSingleYAxis) { + return; + } + + const yAxisShowOption = [{ show: true }, { show: true }]; + if (hoveredSeriesDataKey != null) { + const hiddenYAxisIndex = chartModel.leftAxisModel?.seriesKeys.includes( + hoveredSeriesDataKey, + ) + ? 0 + : 1; + + yAxisShowOption[hiddenYAxisIndex].show = false; + } + + chartRef.current?.setOption({ yAxis: yAxisShowOption }, false, true); + }, + [ + chartModel.leftAxisModel, + chartModel.rightAxisModel, + chartRef, + hoveredSeriesDataKey, + ], + ); + const eventHandlers: EChartsEventHandler[] = useMemo( () => [ { @@ -103,22 +142,14 @@ export const useChartEvents = ( return; } - const hoveredData = getSeriesHoverData( - chartModel, - settings, - rawSeries[0].card.display, - event, - ); - + const hoveredObject = getSeriesHovered(chartModel, event); const isSameDatumHovered = - hoveredData?.index === hovered?.index && - hoveredData?.datumIndex === hovered?.datumIndex; + hoveredObject?.index === hovered?.index && + hoveredObject?.datumIndex === hovered?.datumIndex; - if (isSameDatumHovered) { - return; + if (!isSameDatumHovered) { + onHoverChange?.(hoveredObject); } - - onHoverChange?.(hoveredData); }, }, { @@ -182,21 +213,21 @@ export const useChartEvents = ( }, ], [ + onHoverChange, + timelineEventsModel, chartModel, - onOpenQuestion, - rawSeries, - metadata, hovered, - selectedTimelineEventIds, settings, - timelineEventsModel, visualizationIsClickable, - onChangeCardAndRun, onVisualizationClick, - onHoverChange, onOpenTimelines, + selectedTimelineEventIds, onSelectTimelineEvents, onDeselectTimelineEvents, + onOpenQuestion, + rawSeries, + metadata, + onChangeCardAndRun, ], ); diff --git a/frontend/src/metabase/visualizations/visualizations/CartesianChart/use-models-and-option.ts b/frontend/src/metabase/visualizations/visualizations/CartesianChart/use-models-and-option.ts index 2b052053fe83019d01d0b756ec33e7a1f57761bb..34a22a6b0f67823f4aca0b84979d040a7f59f97a 100644 --- a/frontend/src/metabase/visualizations/visualizations/CartesianChart/use-models-and-option.ts +++ b/frontend/src/metabase/visualizations/visualizations/CartesianChart/use-models-and-option.ts @@ -10,6 +10,7 @@ import type { WaterfallChartModel, } from "metabase/visualizations/echarts/cartesian/model/types"; import { getCartesianChartOption } from "metabase/visualizations/echarts/cartesian/option"; +import { getTooltipOption } from "metabase/visualizations/echarts/cartesian/option/tooltip"; import { getScatterPlotModel } from "metabase/visualizations/echarts/cartesian/scatter/model"; import { getScatterPlotOption } from "metabase/visualizations/echarts/cartesian/scatter/option"; import { getTimelineEventsModel } from "metabase/visualizations/echarts/cartesian/timeline-events/model"; @@ -18,8 +19,6 @@ import { getWaterfallChartOption } from "metabase/visualizations/echarts/cartesi import { useBrowserRenderingContext } from "metabase/visualizations/hooks/use-browser-rendering-context"; import type { VisualizationProps } from "metabase/visualizations/types"; -import { getHoveredSeriesDataKey } from "./utils"; - export function useModelsAndOption({ rawSeries, series: transformedSeries, @@ -92,11 +91,6 @@ export function useModelsAndOption({ [chartModel, chartMeasurements, timelineEvents, renderingContext], ); - const hoveredSeriesDataKey = useMemo( - () => getHoveredSeriesDataKey(chartModel.seriesModels, hovered), - [chartModel.seriesModels, hovered], - ); - const selectedOrHoveredTimelineEventIds = useMemo(() => { const ids = []; @@ -110,6 +104,10 @@ export function useModelsAndOption({ return ids; }, [selectedTimelineEventIds, hovered?.timelineEvents]); + const tooltipOption = useMemo(() => { + return getTooltipOption(chartModel, settings); + }, [chartModel, settings]); + const option = useMemo(() => { if (width === 0 || height === 0) { return {}; @@ -117,9 +115,10 @@ export function useModelsAndOption({ const shouldAnimate = !isPlaceholder && !isReducedMotionPreferred(); + let baseOption; switch (card.display) { case "waterfall": - return getWaterfallChartOption( + baseOption = getWaterfallChartOption( chartModel as WaterfallChartModel, width, chartMeasurements, @@ -129,8 +128,9 @@ export function useModelsAndOption({ shouldAnimate, renderingContext, ); + break; case "scatter": - return getScatterPlotOption( + baseOption = getScatterPlotOption( chartModel as ScatterPlotModel, chartMeasurements, timelineEventsModel, @@ -140,8 +140,9 @@ export function useModelsAndOption({ shouldAnimate, renderingContext, ); + break; default: - return getCartesianChartOption( + baseOption = getCartesianChartOption( chartModel as CartesianChartModel, chartMeasurements, timelineEventsModel, @@ -149,22 +150,26 @@ export function useModelsAndOption({ settings, width, shouldAnimate, - hoveredSeriesDataKey, renderingContext, ); } + + return { + ...baseOption, + tooltip: tooltipOption, + }; }, [ + width, + height, + isPlaceholder, card.display, + tooltipOption, chartModel, chartMeasurements, - renderingContext, - settings, timelineEventsModel, - hoveredSeriesDataKey, - width, - height, - isPlaceholder, selectedOrHoveredTimelineEventIds, + settings, + renderingContext, ]); return { chartModel, timelineEventsModel, option }; diff --git a/frontend/src/metabase/visualizations/visualizations/PieChart/PieChart.tsx b/frontend/src/metabase/visualizations/visualizations/PieChart/PieChart.tsx index 17eb9770707fbf5eda2c6612737d06b656401e01..fd4901e3b76a7688663b7756ac75e793eb26623d 100644 --- a/frontend/src/metabase/visualizations/visualizations/PieChart/PieChart.tsx +++ b/frontend/src/metabase/visualizations/visualizations/PieChart/PieChart.tsx @@ -5,12 +5,14 @@ import ChartWithLegend from "metabase/visualizations/components/ChartWithLegend" import { getPieChartFormatters } from "metabase/visualizations/echarts/pie/format"; import { getPieChartModel } from "metabase/visualizations/echarts/pie/model"; import { getPieChartOption } from "metabase/visualizations/echarts/pie/option"; +import { getTooltipOption } from "metabase/visualizations/echarts/pie/tooltip"; +import { usePieChartValuesColorsClasses } from "metabase/visualizations/echarts/tooltip"; import { useBrowserRenderingContext } from "metabase/visualizations/hooks/use-browser-rendering-context"; import type { VisualizationProps } from "metabase/visualizations/types"; import { ChartRenderer } from "./PieChart.styled"; import { PIE_CHART_DEFINITION } from "./chart-definition"; -import { getTooltipModel, useChartEvents } from "./use-chart-events"; +import { useChartEvents } from "./use-chart-events"; Object.assign(PieChart, PIE_CHART_DEFINITION); @@ -47,8 +49,8 @@ export function PieChart(props: VisualizationProps) { [chartModel, settings, renderingContext], ); const option = useMemo( - () => - getPieChartOption( + () => ({ + ...getPieChartOption( chartModel, formatters, settings, @@ -56,6 +58,8 @@ export function PieChart(props: VisualizationProps) { sideLength, hoveredIndex, ), + tooltip: getTooltipOption(chartModel, formatters), + }), [ chartModel, formatters, @@ -66,6 +70,8 @@ export function PieChart(props: VisualizationProps) { ], ); + const valuesColorsCss = usePieChartValuesColorsClasses(chartModel); + const handleInit = useCallback((chart: EChartsType) => { chartRef.current = chart; }, []); @@ -75,7 +81,7 @@ export function PieChart(props: VisualizationProps) { [], ); - const eventHandlers = useChartEvents(props, chartRef, chartModel, formatters); + const eventHandlers = useChartEvents(props, chartRef, chartModel); const legendTitles = chartModel.slices .filter(s => s.data.includeInLegend) @@ -103,11 +109,6 @@ export function PieChart(props: VisualizationProps) { props.onHoverChange( hoverData && { ...hoverData, - stackedTooltipModel: getTooltipModel( - hoverData.index, - chartModel, - formatters, - ), }, ); @@ -137,6 +138,7 @@ export function PieChart(props: VisualizationProps) { notMerge={false} style={null} /> + {valuesColorsCss} </ChartWithLegend> ); } diff --git a/frontend/src/metabase/visualizations/visualizations/PieChart/use-chart-events.ts b/frontend/src/metabase/visualizations/visualizations/PieChart/use-chart-events.ts index 7291da7c39d75f2ef8a4006f6e1f42460d64aada..c5d01d081b71907a9edc7df306d380cd3829bb7c 100644 --- a/frontend/src/metabase/visualizations/visualizations/PieChart/use-chart-events.ts +++ b/frontend/src/metabase/visualizations/visualizations/PieChart/use-chart-events.ts @@ -1,23 +1,34 @@ import type { EChartsType } from "echarts/core"; import { type MutableRefObject, useEffect, useMemo } from "react"; +import { t } from "ttag"; import _ from "underscore"; +import { formatPercent } from "metabase/static-viz/lib/numbers"; +import type { + EChartsTooltipModel, + EChartsTooltipRow, +} from "metabase/visualizations/components/ChartTooltip/EChartsTooltip"; +import { + getPercent, + getTotalValue, +} from "metabase/visualizations/components/ChartTooltip/StackedDataTooltip/utils"; import type { PieChartFormatters } from "metabase/visualizations/echarts/pie/format"; import type { PieChartModel } from "metabase/visualizations/echarts/pie/model/types"; +import { getMarkerColorClass } from "metabase/visualizations/echarts/tooltip"; import type { EChartsSeriesMouseEvent } from "metabase/visualizations/echarts/types"; import { getFriendlyName } from "metabase/visualizations/lib/utils"; import type { ClickObject, - StackedTooltipModel, VisualizationProps, } from "metabase/visualizations/types"; import type { EChartsEventHandler } from "metabase/visualizations/types/echarts"; export const getTooltipModel = ( - hoveredIndex: number, + dataIndex: number, chartModel: PieChartModel, formatters: PieChartFormatters, -): StackedTooltipModel => { +): EChartsTooltipModel => { + const hoveredIndex = dataIndexToHoveredIndex(dataIndex); const hoveredOther = chartModel.slices[hoveredIndex].data.isOther && chartModel.otherSlices.length > 1; @@ -31,19 +42,36 @@ export const getTooltipModel = ( }), ); - const [headerRows, bodyRows] = _.partition( - rows, - (_, index) => index === (hoveredOther ? null : hoveredIndex), - ); + const rowsTotal = getTotalValue(rows); + const isShowingTotalSensible = rows.length > 1; + + const formattedRows: EChartsTooltipRow[] = rows.map((row, index) => { + const markerColorClass = row.color + ? getMarkerColorClass(row.color) + : undefined; + return { + isFocused: !hoveredOther && index === hoveredIndex, + markerColorClass, + name: row.name, + values: [ + row.formatter(row.value), + formatPercent(getPercent(chartModel.total, row.value) ?? 0), + ], + }; + }); return { - headerTitle: getFriendlyName(chartModel.colDescs.dimensionDesc.column), - headerRows, - bodyRows, - totalFormatter: formatters.formatMetric, - grandTotal: chartModel.total, - showTotal: true, - showPercentages: true, + header: getFriendlyName(chartModel.colDescs.dimensionDesc.column), + rows: formattedRows, + footer: isShowingTotalSensible + ? { + name: t`Total`, + values: [ + formatters.formatMetric(rowsTotal), + formatPercent(getPercent(chartModel.total, rowsTotal) ?? 0), + ], + } + : undefined, }; }; @@ -53,7 +81,6 @@ const hoveredIndexToDataIndex = (index: number) => index + 1; function getHoverData( event: EChartsSeriesMouseEvent, chartModel: PieChartModel, - formatters: PieChartFormatters, ) { if (event.dataIndex == null) { return null; @@ -68,7 +95,6 @@ function getHoverData( return { index, event: event.event.event, - stackedTooltipModel: getTooltipModel(index, chartModel, formatters), }; } @@ -115,7 +141,6 @@ export function useChartEvents( props: VisualizationProps, chartRef: MutableRefObject<EChartsType | undefined>, chartModel: PieChartModel, - formatters: PieChartFormatters, ) { const { onHoverChange, @@ -163,7 +188,7 @@ export function useChartEvents( eventName: "mousemove", query: "series", handler: (event: EChartsSeriesMouseEvent) => { - onHoverChange?.(getHoverData(event, chartModel, formatters)); + onHoverChange?.(getHoverData(event, chartModel)); }, }, { @@ -188,7 +213,6 @@ export function useChartEvents( visualizationIsClickable, onVisualizationClick, chartModel, - formatters, ], ); diff --git a/frontend/src/metabase/visualizations/visualizations/ScatterPlot/ScatterPlot.tsx b/frontend/src/metabase/visualizations/visualizations/ScatterPlot/ScatterPlot.tsx index 65e7fbba735cbbe4fb01e58974a85e42b986cf85..f840b2fcb777444b9838528d2a8c10bc9cdac90e 100644 --- a/frontend/src/metabase/visualizations/visualizations/ScatterPlot/ScatterPlot.tsx +++ b/frontend/src/metabase/visualizations/visualizations/ScatterPlot/ScatterPlot.tsx @@ -14,6 +14,7 @@ import { GRAPH_COLORS_SETTINGS, GRAPH_AXIS_SETTINGS, GRAPH_BUBBLE_SETTINGS, + TOOLTIP_SETTINGS, } from "../../lib/settings/graph"; import type { VisualizationProps, @@ -36,6 +37,7 @@ Object.assign( ...GRAPH_COLORS_SETTINGS, ...GRAPH_AXIS_SETTINGS, ...GRAPH_DATA_SETTINGS, + ...TOOLTIP_SETTINGS, } as any as VisualizationSettingsDefinitions, }), ); diff --git a/frontend/src/metabase/visualizations/visualizations/WaterfallChart/WaterfallChart.tsx b/frontend/src/metabase/visualizations/visualizations/WaterfallChart/WaterfallChart.tsx index 84992b8f89b8ce61ca3cbc17d7af1fe60be66990..d6b94decbdb4d7ae003f6764994020f704a45e59 100644 --- a/frontend/src/metabase/visualizations/visualizations/WaterfallChart/WaterfallChart.tsx +++ b/frontend/src/metabase/visualizations/visualizations/WaterfallChart/WaterfallChart.tsx @@ -5,6 +5,7 @@ import { GRAPH_AXIS_SETTINGS, GRAPH_DISPLAY_VALUES_SETTINGS, GRAPH_DATA_SETTINGS, + TOOLTIP_SETTINGS, } from "metabase/visualizations/lib/settings/graph"; import { getDefaultSize, @@ -62,6 +63,7 @@ Object.assign( }, ...GRAPH_DISPLAY_VALUES_SETTINGS, ...GRAPH_DATA_SETTINGS, + ...TOOLTIP_SETTINGS, } as any as VisualizationSettingsDefinitions, }), );