Table: Migrate to field-level wrapText toggle, use standard hideFrom.viz for hidden fields (#109297)
* Added wrap text to table options and removed from multiple cell options * Removed wrap text from cell options shared file * Edited * Edited * Table: Migrate to field-level wrapText toggle * migrate hidden -> hideFrom.viz as well * more cleanup from rebase * restore options that got killed in the rebase * when wrap text is enabled for the whole table, exclude columns that do not make sense * fix TableNG unit tests * fix i18n * unit tests for the migrations * sort out e2e issue * fix migration unit test * fix backend migration test as well * add a dashboard for the v12.2 table migrations * update dev-dashboards.lisonnet * make gen-jsonnet * one of the panel versions didnt get updated --------- Co-authored-by: Isabel Matwawana <isabel.matwawana@grafana.com>
This commit is contained in:
co-authored by
Isabel Matwawana
parent
699bffc9e4
commit
76b1e5e389
@@ -3988,9 +3988,6 @@ exports[`better eslint`] = {
|
||||
"public/app/plugins/panel/table/cells/SparklineCellOptionsEditor.tsx:5381": [
|
||||
[0, 0, 0, "Add noMargin prop to Field components to remove built-in margins. Use layout components like Stack or Grid with the gap prop instead for consistent spacing.", "0"]
|
||||
],
|
||||
"public/app/plugins/panel/table/cells/TextWrapOptionsEditor.tsx:5381": [
|
||||
[0, 0, 0, "Add noMargin prop to Field components to remove built-in margins. Use layout components like Stack or Grid with the gap prop instead for consistent spacing.", "0"]
|
||||
],
|
||||
"public/app/plugins/panel/table/migrations.ts:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],
|
||||
|
||||
@@ -165,7 +165,7 @@ import (
|
||||
// {
|
||||
// "matcher": { "id": "byName", "options": "Hidden" },
|
||||
// "properties": [
|
||||
// { "id": "custom.hidden", "value": true }
|
||||
// { "id": "custom.hideFrom.viz", "value": true }
|
||||
// ]
|
||||
// }
|
||||
// ]
|
||||
@@ -436,7 +436,7 @@ func migrateTableStyleToOverride(style map[string]interface{}) map[string]interf
|
||||
// Handle hidden type
|
||||
if styleType, ok := style["type"].(string); ok && styleType == "hidden" {
|
||||
properties = append(properties, map[string]interface{}{
|
||||
"id": "custom.hidden",
|
||||
"id": "custom.hideFrom.viz",
|
||||
"value": true,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -216,7 +216,7 @@ func TestV24(t *testing.T) {
|
||||
"options": "Hidden",
|
||||
},
|
||||
"properties": []interface{}{
|
||||
map[string]interface{}{"id": "custom.hidden", "value": true},
|
||||
map[string]interface{}{"id": "custom.hideFrom.viz", "value": true},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -192,7 +192,7 @@
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "custom.hidden",
|
||||
"id": "custom.hideFrom.viz",
|
||||
"value": true
|
||||
}
|
||||
]
|
||||
|
||||
@@ -452,7 +452,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"pluginVersion": "12.2.0-pre",
|
||||
"pluginVersion": "12.1.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
@@ -602,7 +602,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"pluginVersion": "12.2.0-pre",
|
||||
"pluginVersion": "12.1.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
@@ -821,7 +821,7 @@
|
||||
"showHeader": true,
|
||||
"sortBy": []
|
||||
},
|
||||
"pluginVersion": "12.2.0-pre",
|
||||
"pluginVersion": "12.1.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"csvContent": "auto,link,links,bg,bg-link,bg-links,color,color-link,color-links,bg-row,bg-row-link,bg-row-links,color-row,color-row-link,color-row-links,links-cellType\na,a,a,a,a,a,a,a,a,1,1,1,1,1,1,1\nb,b,b,b,b,b,b,b,b,2,2,2,2,2,2,2\nc,c,c,c,c,c,c,c,c,3,3,3,3,3,3,3\nd,d,d,d,d,d,d,d,d,4,4,4,4,4,4,4",
|
||||
@@ -984,7 +984,7 @@
|
||||
"showHeader": true,
|
||||
"sortBy": []
|
||||
},
|
||||
"pluginVersion": "12.2.0-pre",
|
||||
"pluginVersion": "12.1.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"csvContent": "use-case,normal,color-text,color-bg,highlight\n\"color bg and apply to row\",1,0,1,1\n\"color text and apply to row\",1,1,0,1\n\"color text + color bg + apply to row\",1,1,1,1\n\"only apply to row\",1,0,0,1\n\"only color bg\",1,0,1,0\n\"only color text\",1,1,0,0\n\"color text + color bg\",1,1,1,0\n\"no colorization\",1,0,0,0",
|
||||
@@ -1132,7 +1132,7 @@
|
||||
},
|
||||
"showHeader": true
|
||||
},
|
||||
"pluginVersion": "12.2.0-pre",
|
||||
"pluginVersion": "12.1.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"rawFrameContent": "[\n {\n \"schema\": {\n \"refId\": \"A\",\n \"name\": \"A\",\n \"fields\": [\n {\n \"name\": \"Time\",\n \"type\": \"time\",\n \"typeInfo\": {\n \"frame\": \"time.Time\",\n \"nullable\": true\n },\n \"config\": {}\n },\n {\n \"name\": \"Value\",\n \"type\": \"number\",\n \"typeInfo\": {\n \"frame\": \"float64\",\n \"nullable\": true\n },\n \"config\": {}\n },\n {\n \"name\": \"Min\",\n \"type\": \"number\",\n \"typeInfo\": {\n \"frame\": \"float64\",\n \"nullable\": true\n },\n \"config\": {}\n },\n {\n \"name\": \"Max\",\n \"type\": \"number\",\n \"typeInfo\": {\n \"frame\": \"float64\",\n \"nullable\": true\n },\n \"config\": {}\n },\n {\n \"name\": \"Info\",\n \"type\": \"string\",\n \"typeInfo\": {\n \"frame\": \"string\",\n \"nullable\": true\n },\n \"config\": {}\n },\n {\n \"name\": \"State\",\n \"type\": \"enum\",\n \"typeInfo\": {\n \"frame\": \"enum\"\n },\n \"config\": {\n \"type\": {\n \"enum\": {\n \"text\": [\n \"Unknown\",\n \"Up\",\n \"Down\"\n ]\n }\n }\n }\n }\n ]\n },\n \"data\": {\n \"values\": [\n [\n 1754578636810,\n 1754580436810,\n 1754582236810,\n 1754584036810,\n 1754585836810,\n 1754587636810,\n 1754589436810,\n 1754591236810,\n 1754593036810,\n 1754594836810\n ],\n [\n 68.67815082171406,\n 68.21038738705283,\n 67.85748579518524,\n 67.48088827530566,\n 67.36362085363314,\n 67.75399477824531,\n 67.9006935145112,\n 68.2893033558627,\n 68.20547872017494,\n 67.96251158324088\n ],\n [\n 67.52655915076163,\n 68.03367017865995,\n 65.44308825471086,\n 66.94142900198796,\n 66.33531057489242,\n 66.97007154625013,\n 67.88134129373145,\n 65.92102089546943,\n 65.7896781452792,\n 67.77680599320166\n ],\n [\n 68.78026730954913,\n 68.46495903270079,\n 68.29118217530531,\n 67.90561937677037,\n 68.05316512901861,\n 70.26033810424696,\n 68.05691975265877,\n 68.76874724839202,\n 70.02772232081647,\n 70.38628221361253\n ],\n [\n \"up\",\n \"down fast\",\n \"down\",\n \"down\",\n \"down\",\n \"up\",\n \"up\",\n \"up\",\n \"down\",\n \"down\"\n ],\n [\n 1,\n 2,\n 2,\n 2,\n 2,\n 1,\n 1,\n 1,\n 2,\n 2\n ]\n ]\n }\n }\n]",
|
||||
@@ -1279,7 +1279,7 @@
|
||||
},
|
||||
"showHeader": true
|
||||
},
|
||||
"pluginVersion": "12.2.0-pre",
|
||||
"pluginVersion": "12.1.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"rawFrameContent": "[\n {\n \"schema\": {\n \"refId\": \"A\",\n \"name\": \"A\",\n \"fields\": [\n {\n \"name\": \"Time\",\n \"type\": \"time\",\n \"typeInfo\": {\n \"frame\": \"time.Time\",\n \"nullable\": true\n },\n \"config\": {}\n },\n {\n \"name\": \"Value\",\n \"type\": \"number\",\n \"typeInfo\": {\n \"frame\": \"float64\",\n \"nullable\": true\n },\n \"config\": {}\n },\n {\n \"name\": \"Min\",\n \"type\": \"number\",\n \"typeInfo\": {\n \"frame\": \"float64\",\n \"nullable\": true\n },\n \"config\": {}\n },\n {\n \"name\": \"Max\",\n \"type\": \"number\",\n \"typeInfo\": {\n \"frame\": \"float64\",\n \"nullable\": true\n },\n \"config\": {}\n },\n {\n \"name\": \"Info\",\n \"type\": \"string\",\n \"typeInfo\": {\n \"frame\": \"string\",\n \"nullable\": true\n },\n \"config\": {}\n },\n {\n \"name\": \"State\",\n \"type\": \"enum\",\n \"typeInfo\": {\n \"frame\": \"enum\"\n },\n \"config\": {\n \"type\": {\n \"enum\": {\n \"text\": [\n \"Unknown\",\n \"Up\",\n \"Down\"\n ]\n }\n }\n }\n }\n ]\n },\n \"data\": {\n \"values\": [\n [\n 1754579008785,\n 1754580808785,\n 1754582608785,\n 1754584408785,\n 1754586208785,\n 1754588008785,\n 1754589808785,\n 1754591608785,\n 1754593408785,\n 1754595208785\n ],\n [\n 89.82213040422468,\n 89.53763263564208,\n 90.03103064454615,\n 90.51535567776907,\n 90.88960652895187,\n 91.30921636258488,\n 91.12427953645643,\n 91.1507153149385,\n 90.81021008780039,\n 91.11327042147582\n ],\n [\n 87.33191559754641,\n 88.46410173314496,\n 88.06920794235972,\n 88.98473401700574,\n 90.60349141857057,\n 90.5858441719162,\n 90.42154517148411,\n 90.32413455176213,\n 90.72055904641739,\n 88.74774424339796\n ],\n [\n 90.58845140604446,\n 90.08173133413374,\n 90.58230197880795,\n 92.55531809442493,\n 93.09165646181742,\n 93.38354884838586,\n 92.68544239576967,\n 92.15770413350477,\n 92.77335012158814,\n 92.52115072193222\n ],\n [\n \"down\",\n \"down\",\n \"up fast\",\n \"up fast\",\n \"up\",\n \"up fast\",\n \"down\",\n \"up\",\n \"down\",\n \"up\"\n ],\n [\n 2,\n 2,\n 1,\n 1,\n 1,\n 1,\n 2,\n 1,\n 2,\n 1\n ]\n ]\n }\n }\n]",
|
||||
@@ -1426,7 +1426,7 @@
|
||||
},
|
||||
"showHeader": true
|
||||
},
|
||||
"pluginVersion": "12.2.0-pre",
|
||||
"pluginVersion": "12.1.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"rawFrameContent": "[\n {\n \"schema\": {\n \"refId\": \"A\",\n \"name\": \"A\",\n \"fields\": [\n {\n \"name\": \"Time\",\n \"type\": \"time\",\n \"typeInfo\": {\n \"frame\": \"time.Time\",\n \"nullable\": true\n },\n \"config\": {}\n },\n {\n \"name\": \"Value\",\n \"type\": \"number\",\n \"typeInfo\": {\n \"frame\": \"float64\",\n \"nullable\": true\n },\n \"config\": {}\n },\n {\n \"name\": \"Min\",\n \"type\": \"number\",\n \"typeInfo\": {\n \"frame\": \"float64\",\n \"nullable\": true\n },\n \"config\": {}\n },\n {\n \"name\": \"Max\",\n \"type\": \"number\",\n \"typeInfo\": {\n \"frame\": \"float64\",\n \"nullable\": true\n },\n \"config\": {}\n },\n {\n \"name\": \"Info\",\n \"type\": \"string\",\n \"typeInfo\": {\n \"frame\": \"string\",\n \"nullable\": true\n },\n \"config\": {}\n },\n {\n \"name\": \"State\",\n \"type\": \"enum\",\n \"typeInfo\": {\n \"frame\": \"enum\"\n },\n \"config\": {\n \"type\": {\n \"enum\": {\n \"text\": [\n \"Unknown\",\n \"Up\",\n \"Down\"\n ]\n }\n }\n }\n }\n ]\n },\n \"data\": {\n \"values\": [\n [\n 1754579078813,\n 1754580878813,\n 1754582678813,\n 1754584478813,\n 1754586278813,\n 1754588078813,\n 1754589878813,\n 1754591678813,\n 1754593478813,\n 1754595278813\n ],\n [\n 77.30289281564126,\n 87.14357945690202,\n 76.67466266903213,\n 76.27969352662608,\n 95.80292639037513,\n 75.68396049965999,\n 75.76117912054544,\n 76.05073308839697,\n 75.93744737071192,\n 75.82930696129104\n ],\n [\n 76.58900057075734,\n 76.01493865596112,\n 75.25501274661029,\n 75.52871130918913,\n 73.53324017648568,\n 74.74670600818675,\n 73.4627470190636,\n 75.38455781635166,\n 74.04318166296315,\n 74.79620005730261\n ],\n [\n 77.58417866514938,\n 77.9390885538468,\n 78.37258492198521,\n 76.82242506518101,\n 75.81423643776408,\n 75.86349731305505,\n 76.79031910137064,\n 77.71934637974913,\n 76.11981207380533,\n 77.29746416618009\n ],\n [\n \"down fast\",\n \"down\",\n \"down fast\",\n \"down\",\n \"down fast\",\n \"down\",\n \"up\",\n \"up\",\n \"down\",\n \"down\"\n ],\n [\n 2,\n 2,\n 2,\n 2,\n 2,\n 2,\n 1,\n 1,\n 2,\n 2\n ]\n ]\n }\n }\n]",
|
||||
@@ -1573,7 +1573,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"pluginVersion": "12.2.0-pre",
|
||||
"pluginVersion": "12.1.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"rawFrameContent": "[\n {\n \"schema\": {\n \"refId\": \"A\",\n \"name\": \"A\",\n \"fields\": [\n {\n \"name\": \"Time\",\n \"type\": \"time\",\n \"typeInfo\": {\n \"frame\": \"time.Time\",\n \"nullable\": true\n },\n \"config\": {}\n },\n {\n \"name\": \"Value\",\n \"type\": \"number\",\n \"typeInfo\": {\n \"frame\": \"float64\",\n \"nullable\": true\n },\n \"config\": {}\n },\n {\n \"name\": \"Min\",\n \"type\": \"number\",\n \"typeInfo\": {\n \"frame\": \"float64\",\n \"nullable\": true\n },\n \"config\": {}\n },\n {\n \"name\": \"Max\",\n \"type\": \"number\",\n \"typeInfo\": {\n \"frame\": \"float64\",\n \"nullable\": true\n },\n \"config\": {}\n },\n {\n \"name\": \"Info\",\n \"type\": \"string\",\n \"typeInfo\": {\n \"frame\": \"string\",\n \"nullable\": true\n },\n \"config\": {}\n },\n {\n \"name\": \"State\",\n \"type\": \"enum\",\n \"typeInfo\": {\n \"frame\": \"enum\"\n },\n \"config\": {\n \"type\": {\n \"enum\": {\n \"text\": [\n \"Unknown\",\n \"Up\",\n \"Down\"\n ]\n }\n }\n }\n }\n ]\n },\n \"data\": {\n \"values\": [\n [\n 1754579078813,\n 1754580878813,\n 1754582678813,\n 1754584478813,\n 1754586278813,\n 1754588078813,\n 1754589878813,\n 1754591678813,\n 1754593478813,\n 1754595278813\n ],\n [\n 77.30289281564126,\n 87.14357945690202,\n 76.67466266903213,\n 76.27969352662608,\n 95.80292639037513,\n 75.68396049965999,\n 75.76117912054544,\n 76.05073308839697,\n 75.93744737071192,\n 75.82930696129104\n ],\n [\n 76.58900057075734,\n 76.01493865596112,\n 75.25501274661029,\n 75.52871130918913,\n 73.53324017648568,\n 74.74670600818675,\n 73.4627470190636,\n 75.38455781635166,\n 74.04318166296315,\n 74.79620005730261\n ],\n [\n 77.58417866514938,\n 77.9390885538468,\n 78.37258492198521,\n 76.82242506518101,\n 75.81423643776408,\n 75.86349731305505,\n 76.79031910137064,\n 77.71934637974913,\n 76.11981207380533,\n 77.29746416618009\n ],\n [\n \"down fast\",\n \"down\",\n \"down fast\",\n \"down\",\n \"down fast\",\n \"down\",\n \"up\",\n \"up\",\n \"down\",\n \"down\"\n ],\n [\n 2,\n 2,\n 2,\n 2,\n 2,\n 2,\n 1,\n 1,\n 2,\n 2\n ]\n ]\n }\n }\n]",
|
||||
@@ -1755,7 +1755,7 @@
|
||||
"showHeader": true,
|
||||
"sortBy": []
|
||||
},
|
||||
"pluginVersion": "12.2.0-pre",
|
||||
"pluginVersion": "12.1.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"rawFrameContent": "[\n {\n \"schema\": {\n \"refId\": \"A\",\n \"name\": \"A\",\n \"fields\": [\n {\n \"name\": \"Time\",\n \"type\": \"time\",\n \"typeInfo\": {\n \"frame\": \"time.Time\",\n \"nullable\": true\n },\n \"config\": {}\n },\n {\n \"name\": \"Value\",\n \"type\": \"number\",\n \"typeInfo\": {\n \"frame\": \"float64\",\n \"nullable\": true\n },\n \"config\": {}\n },\n {\n \"name\": \"Min\",\n \"type\": \"number\",\n \"typeInfo\": {\n \"frame\": \"float64\",\n \"nullable\": true\n },\n \"config\": {}\n },\n {\n \"name\": \"Max\",\n \"type\": \"number\",\n \"typeInfo\": {\n \"frame\": \"float64\",\n \"nullable\": true\n },\n \"config\": {}\n },\n {\n \"name\": \"Info\",\n \"type\": \"string\",\n \"typeInfo\": {\n \"frame\": \"string\",\n \"nullable\": true\n },\n \"config\": {}\n },\n {\n \"name\": \"State\",\n \"type\": \"enum\",\n \"typeInfo\": {\n \"frame\": \"enum\"\n },\n \"config\": {\n \"type\": {\n \"enum\": {\n \"text\": [\n \"Unknown\",\n \"Up\",\n \"Down\"\n ]\n }\n }\n }\n }\n ]\n },\n \"data\": {\n \"values\": [\n [\n 1754579078813,\n 1754580878813,\n 1754582678813,\n 1754584478813,\n 1754586278813,\n 1754588078813,\n 1754589878813,\n 1754591678813,\n 1754593478813,\n 1754595278813\n ],\n [\n 77.30289281564126,\n 87.14357945690202,\n 76.67466266903213,\n 76.27969352662608,\n 95.80292639037513,\n 75.68396049965999,\n 75.76117912054544,\n 76.05073308839697,\n 75.93744737071192,\n 75.82930696129104\n ],\n [\n 76.58900057075734,\n 76.01493865596112,\n 75.25501274661029,\n 75.52871130918913,\n 73.53324017648568,\n 74.74670600818675,\n 73.4627470190636,\n 75.38455781635166,\n 74.04318166296315,\n 74.79620005730261\n ],\n [\n 77.58417866514938,\n 77.9390885538468,\n 78.37258492198521,\n 76.82242506518101,\n 75.81423643776408,\n 75.86349731305505,\n 76.79031910137064,\n 77.71934637974913,\n 76.11981207380533,\n 77.29746416618009\n ],\n [\n \"down fast\",\n \"down\",\n \"down fast\",\n \"down\",\n \"down fast\",\n \"down\",\n \"up\",\n \"up\",\n \"down\",\n \"down\"\n ],\n [\n 2,\n 2,\n 2,\n 2,\n 2,\n 2,\n 1,\n 1,\n 2,\n 2\n ]\n ]\n }\n }\n]",
|
||||
@@ -1816,7 +1816,7 @@
|
||||
},
|
||||
"showHeader": true
|
||||
},
|
||||
"pluginVersion": "12.2.0-pre",
|
||||
"pluginVersion": "12.1.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"csvContent": "a,b,c",
|
||||
@@ -1852,5 +1852,5 @@
|
||||
"timezone": "",
|
||||
"title": "Panel Tests - Table - Kitchen Sink",
|
||||
"uid": "dcb9f5e9-8066-4397-889e-864b99555dbb",
|
||||
"version": 32
|
||||
"version": 33
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -100,6 +100,7 @@
|
||||
"table_sparkline_cell": (import '../dev-dashboards/panel-table/table_sparkline_cell.json'),
|
||||
"table_tests": (import '../dev-dashboards/panel-table/table_tests.json'),
|
||||
"table_tests_new": (import '../dev-dashboards/panel-table/table_tests_new.json'),
|
||||
"table_v12_2_migrations": (import '../dev-dashboards/panel-table/table_v12_2_migrations.json'),
|
||||
"tall_dashboard": (import '../dev-dashboards/scenarios/tall_dashboard.json'),
|
||||
"templating-dashboard-links-and-variables": (import '../dev-dashboards/feature-templating/templating-dashboard-links-and-variables.json'),
|
||||
"templating-repeating-panels": (import '../dev-dashboards/feature-templating/templating-repeating-panels.json'),
|
||||
|
||||
@@ -209,6 +209,7 @@ This option is only available when you're editing the panel.
|
||||
| Column width | Define a column width, in pixels, rather than allowing the width to be set automatically. By default, Grafana calculates the column width based on the table size and the minimum column width. |
|
||||
| Column alignment | Set how Grafana should align cell contents. Choose from: **Auto** (default), **Left**, **Center**, or **Right**. |
|
||||
| Column filter | Temporarily change how column data is displayed. For example, show or hide specific values. For more information, refer to [Column filtering](#column-filtering). |
|
||||
| Wrap text | Enables text wrapping for cell content. |
|
||||
| Wrap header text | Enables text wrapping for column headers. |
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
@@ -288,24 +289,17 @@ The colored background cell type has the following options:
|
||||
| ------ | ----------- |
|
||||
| Background display mode | Choose between **Basic** and **Gradient**. |
|
||||
| Apply to entire row | Toggle the switch on to apply the background color that's configured for the cell to the whole row. |
|
||||
| Wrap text | Toggle the **Wrap text** switch to wrap text in the cell that contains the longest content in your table. To wrap the text _in a specific column only_, use a **Fields with name** [field override](ref:field-override), select the **Cell options > Cell type** override property, and toggle on the **Wrap text** switch. |
|
||||
| Cell value inspect | <p>Enables value inspection from table cells. When the switch is toggled on, clicking the inspect icon in a cell opens the **Inspect value** drawer which contains two tabs: **Plain text** and **Code editor**.</p><p>Grafana attempts to automatically detect the type of data in the cell and opens the drawer with the associated tab showing. However, you can switch back and forth between tabs.</p> |
|
||||
| Tooltip from field | Toggle on the **Tooltip from field** switch to use the values from another field (or column) in a tooltip. For more information, refer to the [Tooltip from field](#tooltip-from-field). |
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
<!-- The wrap text, cell value inspect, and tooltip from field descriptions above should be copied from docs/sources/shared/visualizations/cell-options.md -->
|
||||
<!-- The cell value inspect and tooltip from field descriptions above should be copied from docs/sources/shared/visualizations/cell-options.md -->
|
||||
|
||||
#### Data links
|
||||
|
||||
If you've configured data links, when the cell type is **Auto**, the cell text becomes clickable.
|
||||
If you change the cell type to **Data links**, the cell text reflects the titles of the configured data links. To control the application of data link text more granularly, use a **Cell option > Cell type > Data links** field override.
|
||||
|
||||
Data links cells also support text wrapping.
|
||||
Toggle the **Wrap text** switch to wrap text in the cell that contains the longest content in your table.
|
||||
To wrap the text _in a specific column only_, use a **Fields with name** [field override](ref:field-override), select the **Cell options > Cell type** override property, and toggle on the **Wrap text** switch.
|
||||
|
||||
<!-- The wrap text description above should be copied from docs/sources/shared/visualizations/cell-options.md -->
|
||||
|
||||
#### Gauge
|
||||
|
||||
With this cell type, cells can be displayed as a graphical gauge, with several different presentation types.
|
||||
@@ -402,12 +396,6 @@ The **Pill** cell type displays each item in a comma-separated string in a color
|
||||
The colors applied to each piece of text are maintained throughout the table.
|
||||
For example, if the word "test" is first displayed in a red pill, it will always be displayed in a red pill.
|
||||
|
||||
Pill cells also support text wrapping.
|
||||
Toggle the **Wrap text** switch to wrap text in the cell that contains the longest content in your table.
|
||||
To wrap the text _in a specific column only_, use a **Fields with name** [field override](ref:field-override), select the **Cell options > Cell type** override property, and toggle on the **Wrap text** switch.
|
||||
|
||||
<!-- The wrap text description above should be copied from docs/sources/shared/visualizations/cell-options.md -->
|
||||
|
||||
The following data formats are supported for the pill cell type:
|
||||
|
||||
- Comma-separated values (`cows,chickens,goats`)
|
||||
|
||||
@@ -5,7 +5,6 @@ title: Cell options
|
||||
<!-- prettier-ignore-start -->
|
||||
| Option | Description |
|
||||
| ------ | ----------- |
|
||||
| Wrap text | Toggle the **Wrap text** switch to wrap text in the cell that contains the longest content in your table. To wrap the text _in a specific column only_, use a **Fields with name** [field override](https://grafana.com/docs/grafana/<GRAFANA_VERSION>/panels-visualizations/configure-overrides/), select the **Cell options > Cell type** override property, and toggle on the **Wrap text** switch. |
|
||||
| Cell value inspect | <p>Enables value inspection from table cells. When the switch is toggled on, clicking the inspect icon in a cell opens the **Inspect value** drawer which contains two tabs: **Plain text** and **Code editor**.</p><p>Grafana attempts to automatically detect the type of data in the cell and opens the drawer with the associated tab showing. However, you can switch back and forth between tabs.</p> |
|
||||
| Tooltip from field | Toggle on the **Tooltip from field** switch to use the values from another field (or column) in a tooltip. For more information, refer to [Tooltip from field](#tooltip-from-field). |
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
@@ -43,15 +43,13 @@ const getColumnIdx = async (loc: Page | Locator, columnName: string) => {
|
||||
|
||||
const disableAllTextWrap = async (loc: Page | Locator, selectors: E2ESelectorGroups) => {
|
||||
// disable text wrapping for all of the columns, since long text with links in them can push the links off the screen.
|
||||
const wrapTextToggle = loc.locator(
|
||||
`[aria-label="${selectors.components.PanelEditor.OptionsPane.fieldLabel('Wrap text')}"]`
|
||||
);
|
||||
const wrapTextToggle = loc.getByLabel('Wrap text');
|
||||
const count = await wrapTextToggle.count();
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
const toggle = wrapTextToggle.nth(i);
|
||||
if ((await toggle.locator('//preceding-sibling::input').getAttribute('checked')) !== null) {
|
||||
await toggle.click();
|
||||
if ((await toggle.getAttribute('checked')) !== null) {
|
||||
await toggle.click({ force: true });
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -77,7 +75,7 @@ test.describe('Panels test: Table - Kitchen Sink', { tag: ['@panels', '@table']
|
||||
|
||||
await dashboardPage
|
||||
.getByGrafanaSelector(selectors.components.OptionsGroup.group('panel-options-override-12'))
|
||||
.getByLabel(selectors.components.PanelEditor.OptionsPane.fieldLabel('Wrap text'))
|
||||
.getByText('Wrap text')
|
||||
.click();
|
||||
await expect(getCellHeight(page, 1, longTextColIdx)).resolves.toBeLessThan(100);
|
||||
|
||||
|
||||
@@ -745,16 +745,6 @@ export enum TableCellBackgroundDisplayMode {
|
||||
Gradient = 'gradient',
|
||||
}
|
||||
|
||||
/**
|
||||
* Whenever we add text wrapping, we should add all text wrapping options at once
|
||||
*/
|
||||
export interface TableWrapTextOptions {
|
||||
/**
|
||||
* if true, wrap the text content of the cell
|
||||
*/
|
||||
wrapText?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort by field state
|
||||
*/
|
||||
@@ -788,14 +778,14 @@ export const defaultTableFooterOptions: Partial<TableFooterOptions> = {
|
||||
/**
|
||||
* Auto mode table cell options
|
||||
*/
|
||||
export interface TableAutoCellOptions extends TableWrapTextOptions {
|
||||
export interface TableAutoCellOptions {
|
||||
type: TableCellDisplayMode.Auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* Colored text cell options
|
||||
*/
|
||||
export interface TableColorTextCellOptions extends TableWrapTextOptions {
|
||||
export interface TableColorTextCellOptions {
|
||||
type: TableCellDisplayMode.ColorText;
|
||||
}
|
||||
|
||||
@@ -818,7 +808,7 @@ export interface TableImageCellOptions {
|
||||
/**
|
||||
* Show data links in the cell
|
||||
*/
|
||||
export interface TableDataLinksCellOptions extends TableWrapTextOptions {
|
||||
export interface TableDataLinksCellOptions {
|
||||
type: TableCellDisplayMode.DataLinks;
|
||||
}
|
||||
|
||||
@@ -849,13 +839,13 @@ export interface TableSparklineCellOptions extends GraphFieldConfig {
|
||||
/**
|
||||
* Colored background cell options
|
||||
*/
|
||||
export interface TableColoredBackgroundCellOptions extends TableWrapTextOptions {
|
||||
export interface TableColoredBackgroundCellOptions {
|
||||
applyToRow?: boolean;
|
||||
mode?: TableCellBackgroundDisplayMode;
|
||||
type: TableCellDisplayMode.ColorBackground;
|
||||
}
|
||||
|
||||
export interface TablePillCellOptions extends TableWrapTextOptions {
|
||||
export interface TablePillCellOptions {
|
||||
type: TableCellDisplayMode.Pill;
|
||||
}
|
||||
|
||||
@@ -1006,7 +996,7 @@ export enum TableCellTooltipPlacement {
|
||||
* Field options for each field within a table (e.g 10, "The String", 64.20, etc.)
|
||||
* Generally defines alignment, filtering capabilties, display options, etc.
|
||||
*/
|
||||
export interface TableFieldOptions {
|
||||
export interface TableFieldOptions extends HideableFieldConfig {
|
||||
align: FieldTextAlignment;
|
||||
cellOptions: TableCellOptions;
|
||||
/**
|
||||
@@ -1014,7 +1004,6 @@ export interface TableFieldOptions {
|
||||
*/
|
||||
displayMode?: TableCellDisplayMode;
|
||||
filterable?: boolean;
|
||||
hidden?: boolean; // ?? default is missing or false ??
|
||||
/**
|
||||
* Hides any header for a column, useful for columns that show some static content or buttons.
|
||||
*/
|
||||
@@ -1039,6 +1028,10 @@ export interface TableFieldOptions {
|
||||
* Enables text wrapping for column headers
|
||||
*/
|
||||
wrapHeaderText?: boolean;
|
||||
/**
|
||||
* if true, wrap the text content of the cell
|
||||
*/
|
||||
wrapText?: boolean;
|
||||
}
|
||||
|
||||
export const defaultTableFieldOptions: Partial<TableFieldOptions> = {
|
||||
|
||||
@@ -11,12 +11,6 @@ TableCellDisplayMode: "auto" | "color-text" | "color-background" | "color-backgr
|
||||
// or a gradient.
|
||||
TableCellBackgroundDisplayMode: "basic" | "gradient" @cuetsy(kind="enum",memberNames="Basic|Gradient")
|
||||
|
||||
// Whenever we add text wrapping, we should add all text wrapping options at once
|
||||
TableWrapTextOptions: {
|
||||
// if true, wrap the text content of the cell
|
||||
wrapText?: bool
|
||||
} @cuetsy(kind="interface")
|
||||
|
||||
// Sort by field state
|
||||
TableSortByFieldState: {
|
||||
// Sets the display name of the field to sort by
|
||||
@@ -37,12 +31,12 @@ TableFooterOptions: {
|
||||
// Auto mode table cell options
|
||||
TableAutoCellOptions: {
|
||||
type: TableCellDisplayMode & "auto"
|
||||
} & TableWrapTextOptions @cuetsy(kind="interface")
|
||||
} @cuetsy(kind="interface")
|
||||
|
||||
// Colored text cell options
|
||||
TableColorTextCellOptions: {
|
||||
type: TableCellDisplayMode & "color-text"
|
||||
} & TableWrapTextOptions @cuetsy(kind="interface")
|
||||
} @cuetsy(kind="interface")
|
||||
|
||||
// Json view cell options
|
||||
TableJsonViewCellOptions: {
|
||||
@@ -59,7 +53,7 @@ TableImageCellOptions: {
|
||||
// Show data links in the cell
|
||||
TableDataLinksCellOptions: {
|
||||
type: TableCellDisplayMode & "data-links"
|
||||
} & TableWrapTextOptions @cuetsy(kind="interface")
|
||||
} @cuetsy(kind="interface")
|
||||
|
||||
// Show actions in the cell
|
||||
TableActionsCellOptions: {
|
||||
@@ -85,11 +79,11 @@ TableColoredBackgroundCellOptions: {
|
||||
type: TableCellDisplayMode & "color-background"
|
||||
mode?: TableCellBackgroundDisplayMode
|
||||
applyToRow?: bool
|
||||
} & TableWrapTextOptions @cuetsy(kind="interface")
|
||||
} @cuetsy(kind="interface")
|
||||
|
||||
TablePillCellOptions: {
|
||||
type: TableCellDisplayMode & "pill"
|
||||
} & TableWrapTextOptions @cuetsy(kind="interface")
|
||||
} @cuetsy(kind="interface")
|
||||
|
||||
TableMarkdownCellOptions: {
|
||||
type: TableCellDisplayMode & "markdown"
|
||||
@@ -131,13 +125,14 @@ TableFieldOptions: {
|
||||
// This field is deprecated in favor of using cellOptions
|
||||
displayMode?: TableCellDisplayMode
|
||||
cellOptions: TableCellOptions
|
||||
hidden?: bool // ?? default is missing or false ??
|
||||
inspect: bool | *false
|
||||
filterable?: bool
|
||||
// Hides any header for a column, useful for columns that show some static content or buttons.
|
||||
hideHeader?: bool
|
||||
// if true, wrap the text content of the cell
|
||||
wrapText?: bool
|
||||
// Enables text wrapping for column headers
|
||||
wrapHeaderText?: bool
|
||||
// Selecting or hovering this field will show a tooltip containing the content within the target field
|
||||
tooltip?: TableCellTooltipOptions
|
||||
} @cuetsy(kind="interface")
|
||||
} & HideableFieldConfig @cuetsy(kind="interface")
|
||||
|
||||
@@ -17,7 +17,7 @@ import { MarkdownCell, getStyles as getMarkdownCellStyles } from './MarkdownCell
|
||||
import { PillCell, getStyles as getPillStyles } from './PillCell';
|
||||
import { SparklineCell, getStyles as getSparklineCellStyles } from './SparklineCell';
|
||||
|
||||
const AutoCellRenderer = memo((props: TableCellRendererProps) => (
|
||||
export const AutoCellRenderer = memo((props: TableCellRendererProps) => (
|
||||
<AutoCell value={props.value} field={props.field} rowIdx={props.rowIdx} />
|
||||
));
|
||||
AutoCellRenderer.displayName = 'AutoCellRenderer';
|
||||
|
||||
@@ -143,13 +143,13 @@ const createNestedDataFrame = (): DataFrame => {
|
||||
name: '__depth',
|
||||
type: FieldType.number,
|
||||
values: [0, 0],
|
||||
config: { custom: { hidden: true } },
|
||||
config: { custom: { hideFrom: { viz: true } } },
|
||||
},
|
||||
{
|
||||
name: '__index',
|
||||
type: FieldType.number,
|
||||
values: [0, 1],
|
||||
config: { custom: { hidden: true } },
|
||||
config: { custom: { hideFrom: { viz: true } } },
|
||||
},
|
||||
{
|
||||
name: '__nestedFrames',
|
||||
@@ -1258,10 +1258,7 @@ describe('TableNG', () => {
|
||||
const frame = createBasicDataFrame();
|
||||
frame.fields.forEach((field) => {
|
||||
if (field.config?.custom) {
|
||||
field.config.custom.cellOptions = {
|
||||
...field.config.custom.cellOptions,
|
||||
wrapText: true,
|
||||
};
|
||||
field.config.custom.wrapText = true;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1274,9 +1271,7 @@ describe('TableNG', () => {
|
||||
fieldConfig={{
|
||||
defaults: {
|
||||
custom: {
|
||||
cellOptions: {
|
||||
wrapText: true,
|
||||
},
|
||||
wrapText: true,
|
||||
},
|
||||
},
|
||||
overrides: [],
|
||||
|
||||
@@ -719,9 +719,9 @@ describe('TableNG hooks', () => {
|
||||
...field.config,
|
||||
custom: {
|
||||
...field.config?.custom,
|
||||
wrapText: true,
|
||||
cellOptions: {
|
||||
cellType: TableCellDisplayMode.Auto,
|
||||
wrapText: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -547,14 +547,14 @@ describe('TableNG utils', () => {
|
||||
name: 'test',
|
||||
type: FieldType.string,
|
||||
config: {
|
||||
custom: { cellOptions: { type: TableCellDisplayMode.ColorText, inspectEnabled: false, wrapText: true } },
|
||||
custom: { cellOptions: { type: TableCellDisplayMode.ColorText, inspectEnabled: false } },
|
||||
},
|
||||
values: [],
|
||||
};
|
||||
|
||||
const options = getCellOptions(field);
|
||||
|
||||
expect(options).toEqual({ type: TableCellDisplayMode.ColorText, inspectEnabled: false, wrapText: true });
|
||||
expect(options).toEqual({ type: TableCellDisplayMode.ColorText, inspectEnabled: false });
|
||||
});
|
||||
|
||||
it('should handle legacy displayMode property', () => {
|
||||
@@ -1074,12 +1074,12 @@ describe('TableNG utils', () => {
|
||||
|
||||
it('sets up text height measurers for each text column if wrapping is on', () => {
|
||||
const fields: Field[] = [
|
||||
{ name: 'Name', type: FieldType.string, values: [], config: { custom: { cellOptions: { wrapText: true } } } },
|
||||
{ name: 'Name', type: FieldType.string, values: [], config: { custom: { wrapText: true } } },
|
||||
{
|
||||
name: 'Address',
|
||||
type: FieldType.string,
|
||||
values: [],
|
||||
config: { custom: { cellOptions: { wrapText: true } } },
|
||||
config: { custom: { wrapText: true } },
|
||||
},
|
||||
];
|
||||
const measurers = buildCellHeightMeasurers(fields, ctx);
|
||||
@@ -1094,7 +1094,7 @@ describe('TableNG utils', () => {
|
||||
name: 'Address',
|
||||
type: FieldType.string,
|
||||
values: [],
|
||||
config: { custom: { cellOptions: { wrapText: true } } },
|
||||
config: { custom: { wrapText: true } },
|
||||
},
|
||||
];
|
||||
|
||||
@@ -1108,7 +1108,7 @@ describe('TableNG utils', () => {
|
||||
name: 'Tags',
|
||||
type: FieldType.string,
|
||||
values: ['tag1,tag2', 'tag3', '["tag4","tag5","tag6"]'],
|
||||
config: { custom: { cellOptions: { type: TableCellDisplayMode.Pill, wrapText: true } } },
|
||||
config: { custom: { wrapText: true, cellOptions: { type: TableCellDisplayMode.Pill } } },
|
||||
},
|
||||
];
|
||||
const measurers = buildCellHeightMeasurers(fields, ctx);
|
||||
@@ -1125,7 +1125,7 @@ describe('TableNG utils', () => {
|
||||
name: 'Links',
|
||||
type: FieldType.string,
|
||||
values: ['http://example.com/1', 'http://example.com/2'],
|
||||
config: { custom: { cellOptions: { type: TableCellDisplayMode.DataLinks, wrapText: true } } },
|
||||
config: { custom: { wrapText: true, cellOptions: { type: TableCellDisplayMode.DataLinks } } },
|
||||
getLinks: jest.fn((): LinkModel[] => [
|
||||
{ title: 'Link 1', href: 'http://example.com/1', target: '_blank', origin: { datasourceUid: 'test' } },
|
||||
{ title: 'Link 2', href: 'http://example.com/2', target: '_self', origin: { datasourceUid: 'test' } },
|
||||
@@ -1141,12 +1141,12 @@ describe('TableNG utils', () => {
|
||||
it('does not enable text counting for non-string fields', () => {
|
||||
const fields: Field[] = [
|
||||
{ name: 'Name', type: FieldType.string, values: [], config: { custom: {} } },
|
||||
{ name: 'Age', type: FieldType.number, values: [], config: { custom: { cellOptions: { wrapText: true } } } },
|
||||
{ name: 'Age', type: FieldType.number, values: [], config: { custom: { wrapText: true } } },
|
||||
];
|
||||
|
||||
const measurers = buildCellHeightMeasurers(fields, ctx);
|
||||
// empty array - we had one column that indicated it wraps, but it was numeric, so we just ignore it
|
||||
expect(measurers).toEqual([]);
|
||||
expect(measurers).toBeUndefined();
|
||||
});
|
||||
|
||||
it('returns an undefined if no columns are wrapped', () => {
|
||||
@@ -1170,13 +1170,13 @@ describe('TableNG utils', () => {
|
||||
name: 'Name',
|
||||
type: FieldType.string,
|
||||
values: ['foo', 'bar', 'baz', 'longer one here', 'shorter'],
|
||||
config: { custom: { cellOptions: { wrapText: true } } },
|
||||
config: { custom: { wrapText: true } },
|
||||
},
|
||||
{
|
||||
name: 'Age',
|
||||
type: FieldType.number,
|
||||
values: [1, 2, 3, 123456, 789122349932],
|
||||
config: { custom: { cellOptions: { wrapText: true } } },
|
||||
config: { custom: { wrapText: true } },
|
||||
},
|
||||
];
|
||||
measurers = [
|
||||
|
||||
@@ -28,6 +28,7 @@ import { getTextColorForAlphaBackground } from '../../../utils/colors';
|
||||
import { TableCellOptions } from '../types';
|
||||
|
||||
import { inferPills } from './Cells/PillCell';
|
||||
import { AutoCellRenderer, getCellRenderer } from './Cells/renderers';
|
||||
import { COLUMN, TABLE } from './constants';
|
||||
import {
|
||||
TableRow,
|
||||
@@ -80,12 +81,7 @@ export function isCellInspectEnabled(field: Field): boolean {
|
||||
* Returns true if text wrapping should be applied to the cell.
|
||||
*/
|
||||
export function shouldTextWrap(field: Field): boolean {
|
||||
const cellOptions = getCellOptions(field);
|
||||
// @ts-ignore - a handful of cellTypes have boolean wrapText, but not all of them.
|
||||
// we should be very careful to only use boolean type for cellOptions.wrapText.
|
||||
// TBH we will probably move this up to a field option which is showIf rendered anyway,
|
||||
// but that'll be a migration to do, so it needs to happen post-GA.
|
||||
return Boolean(cellOptions?.wrapText);
|
||||
return Boolean(field.config.custom?.wrapText);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -301,8 +297,14 @@ export function buildCellHeightMeasurers(
|
||||
setupMeasurerForIdx(TableCellDisplayMode.DataLinks, fieldIdx);
|
||||
} else if (cellType === TableCellDisplayMode.Pill) {
|
||||
setupMeasurerForIdx(TableCellDisplayMode.Pill, fieldIdx);
|
||||
} else if (field.type === FieldType.string) {
|
||||
} else if (
|
||||
field.type === FieldType.string &&
|
||||
getCellRenderer(field, getCellOptions(field)) === AutoCellRenderer
|
||||
) {
|
||||
setupMeasurerForIdx(TableCellDisplayMode.Auto, fieldIdx);
|
||||
} else {
|
||||
// no measurer was configured for this cell type
|
||||
wrappedFields--;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -849,7 +851,7 @@ export const predicateByName = (name: string) => (f: Field) => f.name === name |
|
||||
* returns only fields that are not nested tables and not explicitly hidden
|
||||
*/
|
||||
export function getVisibleFields(fields: Field[]): Field[] {
|
||||
return fields.filter((field) => field.type !== FieldType.nestedFrames && field.config.custom?.hidden !== true);
|
||||
return fields.filter((field) => field.type !== FieldType.nestedFrames && field.config.custom?.hideFrom?.viz !== true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -114,7 +114,12 @@ export function getColumns(
|
||||
|
||||
for (const [fieldIndex, field] of data.fields.entries()) {
|
||||
const fieldTableOptions: TableFieldOptions = field.config.custom || {};
|
||||
if (fieldTableOptions.hidden || field.type === FieldType.nestedFrames) {
|
||||
if (
|
||||
// @ts-ignore this was the former hidden option; we support it for legacy use cases while TableRT is being sunset.
|
||||
fieldTableOptions.hidden ||
|
||||
fieldTableOptions.hideFrom?.viz ||
|
||||
field.type === FieldType.nestedFrames
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -112,7 +112,9 @@ export function getMostFiredInstancesScene(datasource: DataSourceRef, panelTitle
|
||||
.setHeaderActions([new InsightsMenuButton({ panel: panelTitle })])
|
||||
.setOverrides((builder) =>
|
||||
// Hide the rule UID field, if we omit it in a transformation the custom cell renderer will not work
|
||||
builder.matchFieldsWithName(RULE_UID_FIELD_NAME).overrideCustomFieldConfig('hidden', true)
|
||||
builder
|
||||
.matchFieldsWithName(RULE_UID_FIELD_NAME)
|
||||
.overrideCustomFieldConfig('hideFrom', { viz: true, legend: false, tooltip: false })
|
||||
)
|
||||
.build(),
|
||||
});
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useState } from 'react';
|
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { t } from '@grafana/i18n';
|
||||
import { TableCellOptions, TableWrapTextOptions } from '@grafana/schema';
|
||||
import { TableCellOptions } from '@grafana/schema';
|
||||
import { Combobox, ComboboxOption, Field, TableCellDisplayMode, useStyles2 } from '@grafana/ui';
|
||||
|
||||
import { BarGaugeCellOptionsEditor } from './cells/BarGaugeCellOptionsEditor';
|
||||
@@ -12,7 +12,6 @@ import { ColorBackgroundCellOptionsEditor } from './cells/ColorBackgroundCellOpt
|
||||
import { ImageCellOptionsEditor } from './cells/ImageCellOptionsEditor';
|
||||
import { MarkdownCellOptionsEditor } from './cells/MarkdownCellOptionsEditor';
|
||||
import { SparklineCellOptionsEditor } from './cells/SparklineCellOptionsEditor';
|
||||
import { TextWrapOptionsEditor } from './cells/TextWrapOptionsEditor';
|
||||
|
||||
// The props that any cell type editor are expected
|
||||
// to handle. In this case the generic type should
|
||||
@@ -28,19 +27,6 @@ interface Props {
|
||||
id?: string;
|
||||
}
|
||||
|
||||
const TEXT_WRAP_CELL_TYPES = new Set([
|
||||
TableCellDisplayMode.Auto,
|
||||
TableCellDisplayMode.Sparkline,
|
||||
TableCellDisplayMode.ColorText,
|
||||
TableCellDisplayMode.ColorBackground,
|
||||
TableCellDisplayMode.DataLinks,
|
||||
TableCellDisplayMode.Pill,
|
||||
]);
|
||||
|
||||
function isTextWrapCellType(value: TableCellOptions): value is TableCellOptions & TableWrapTextOptions {
|
||||
return TEXT_WRAP_CELL_TYPES.has(value.type);
|
||||
}
|
||||
|
||||
export const TableCellOptionEditor = ({ value, onChange, id }: Props) => {
|
||||
const cellType = value.type;
|
||||
const styles = useStyles2(getStyles);
|
||||
@@ -95,7 +81,6 @@ export const TableCellOptionEditor = ({ value, onChange, id }: Props) => {
|
||||
<Field>
|
||||
<Combobox id={id} options={cellDisplayModeOptions} value={currentMode} onChange={onCellTypeChange} />
|
||||
</Field>
|
||||
{isTextWrapCellType(value) && <TextWrapOptionsEditor cellOptions={value} onChange={onCellOptionsChange} />}
|
||||
{cellType === TableCellDisplayMode.Gauge && (
|
||||
<BarGaugeCellOptionsEditor cellOptions={value} onChange={onCellOptionsChange} />
|
||||
)}
|
||||
|
||||
@@ -8,8 +8,6 @@ import { Field, RadioButtonGroup, Switch } from '@grafana/ui';
|
||||
|
||||
import { TableCellEditorProps } from '../TableCellOptionEditor';
|
||||
|
||||
import { TextWrapOptionsEditor } from './TextWrapOptionsEditor';
|
||||
|
||||
const colorBackgroundOpts: Array<SelectableValue<TableCellBackgroundDisplayMode>> = [
|
||||
{ value: TableCellBackgroundDisplayMode.Basic, label: 'Basic' },
|
||||
{ value: TableCellBackgroundDisplayMode.Gradient, label: 'Gradient' },
|
||||
@@ -57,14 +55,6 @@ export const ColorBackgroundCellOptionsEditor = ({
|
||||
onChange={onColorRowChange}
|
||||
/>
|
||||
</Field>
|
||||
|
||||
<TextWrapOptionsEditor
|
||||
cellOptions={cellOptions}
|
||||
onChange={(updatedCellOptions) => {
|
||||
cellOptions.wrapText = updatedCellOptions.wrapText;
|
||||
onChange(cellOptions);
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
import { useId } from 'react';
|
||||
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import { t } from '@grafana/i18n';
|
||||
import { TableCellOptions, TableWrapTextOptions } from '@grafana/schema';
|
||||
import { Field, Switch } from '@grafana/ui';
|
||||
|
||||
import { TableCellEditorProps } from '../TableCellOptionEditor';
|
||||
|
||||
export const TextWrapOptionsEditor = ({
|
||||
cellOptions,
|
||||
onChange,
|
||||
}: TableCellEditorProps<TableCellOptions & TableWrapTextOptions>) => {
|
||||
// Handle row coloring changes
|
||||
const onWrapTextChange = () => {
|
||||
cellOptions.wrapText = !cellOptions.wrapText;
|
||||
onChange(cellOptions);
|
||||
};
|
||||
|
||||
const htmlId = useId();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Field label={t('table.text-wrap-options.label-wrap-text', 'Wrap text')}>
|
||||
<Switch
|
||||
id={htmlId}
|
||||
label={selectors.components.PanelEditor.OptionsPane.fieldLabel(`Wrap text`)}
|
||||
value={cellOptions.wrapText}
|
||||
onChange={onWrapTextChange}
|
||||
/>
|
||||
</Field>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -1,6 +1,12 @@
|
||||
import { createDataFrame, FieldType, PanelModel } from '@grafana/data';
|
||||
import { TableCellDisplayMode } from '@grafana/ui';
|
||||
|
||||
import { migrateFromParentRowIndexToNestedFrames, tablePanelChangedHandler } from './migrations';
|
||||
import {
|
||||
migrateFromParentRowIndexToNestedFrames,
|
||||
migrateHiddenFields,
|
||||
migrateTextWrapToFieldLevel,
|
||||
tablePanelChangedHandler,
|
||||
} from './migrations';
|
||||
|
||||
describe('Table Migrations', () => {
|
||||
it('migrates transform out to core transforms', () => {
|
||||
@@ -361,4 +367,111 @@ describe('Table Migrations', () => {
|
||||
expect(newFormat[1].fields[1].values[0][0].fields[0].values[0]).toBe('0_subA');
|
||||
expect(newFormat[1].fields[1].values[1][0].fields[0].values[0]).toBe('1_subA');
|
||||
});
|
||||
|
||||
describe('migrateTextWrapToFieldLevel', () => {
|
||||
it('migrates a top-level config.custom.cellOptions.wrapText to a config.custom.wrapText', () => {
|
||||
const panel = {
|
||||
fieldConfig: {
|
||||
defaults: {
|
||||
custom: {
|
||||
cellOptions: {
|
||||
wrapText: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
overrides: [],
|
||||
},
|
||||
} as unknown as PanelModel;
|
||||
|
||||
migrateTextWrapToFieldLevel(panel);
|
||||
expect(panel.fieldConfig.defaults.custom.wrapText).toBe(true);
|
||||
expect(panel.fieldConfig.defaults.custom.cellOptions.wrapText).toBeUndefined();
|
||||
});
|
||||
|
||||
it('migrates field override config.custom.cellOptions.wrapTexts to a field override config.custom.wrapTexts', () => {
|
||||
const panel = {
|
||||
fieldConfig: {
|
||||
defaults: {
|
||||
custom: {},
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
matcher: { id: 'byName', options: 'field1' },
|
||||
properties: [
|
||||
{
|
||||
id: 'custom.cellOptions',
|
||||
value: { wrapText: true, type: TableCellDisplayMode.Pill },
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
} as unknown as PanelModel;
|
||||
|
||||
migrateTextWrapToFieldLevel(panel);
|
||||
expect(panel.fieldConfig.overrides[0].properties).toEqual(
|
||||
expect.arrayContaining([
|
||||
{ id: 'custom.wrapText', value: true },
|
||||
{ id: 'custom.cellOptions', value: { type: TableCellDisplayMode.Pill } },
|
||||
])
|
||||
);
|
||||
});
|
||||
|
||||
it('does not overwrite field overrides for cellOptions which do not have wrapText set', () => {
|
||||
const panel = {
|
||||
fieldConfig: {
|
||||
defaults: {
|
||||
custom: {},
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
matcher: { id: 'byName', options: 'field1' },
|
||||
properties: [
|
||||
{
|
||||
id: 'custom.cellOptions',
|
||||
value: { type: TableCellDisplayMode.Pill },
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
} as unknown as PanelModel;
|
||||
|
||||
migrateTextWrapToFieldLevel(panel);
|
||||
// passes the override through with no changes
|
||||
expect(panel.fieldConfig.overrides[0]).toBe(panel.fieldConfig.overrides[0]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('migrateHiddenFields', () => {
|
||||
it('migrates fields with config.custom.hidden=true to config.custom.hideFrom.viz=true', () => {
|
||||
const panel = {
|
||||
fieldConfig: {
|
||||
defaults: {
|
||||
custom: {},
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
matcher: { id: 'byName', options: 'field1' },
|
||||
properties: [
|
||||
{
|
||||
id: 'custom.hidden',
|
||||
value: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
} as unknown as PanelModel;
|
||||
|
||||
migrateHiddenFields(panel);
|
||||
|
||||
expect(panel.fieldConfig.overrides[0].properties).toEqual(
|
||||
expect.arrayContaining([{ id: 'custom.hideFrom.viz', value: true }])
|
||||
);
|
||||
expect(panel.fieldConfig.overrides[0].properties).not.toEqual(
|
||||
expect.arrayContaining([{ id: 'custom.hidden', value: true }])
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { omitBy, isNil, isNumber, defaultTo, groupBy } from 'lodash';
|
||||
import { omitBy, isNil, isNumber, defaultTo, groupBy, omit } from 'lodash';
|
||||
|
||||
import {
|
||||
PanelModel,
|
||||
@@ -25,6 +25,9 @@ export const tableMigrationHandler = (panel: PanelModel<Options>): Partial<Optio
|
||||
console.log('Was angular table', panel);
|
||||
}
|
||||
|
||||
migrateTextWrapToFieldLevel(panel);
|
||||
migrateHiddenFields(panel);
|
||||
|
||||
// Nothing changed
|
||||
return panel.options;
|
||||
};
|
||||
@@ -297,3 +300,49 @@ export const migrateFromParentRowIndexToNestedFrames = (frames: DataFrame[] | nu
|
||||
export const hasDeprecatedParentRowIndex = (frames: DataFrame[] | null) => {
|
||||
return frames?.some((df) => df.meta?.custom?.parentRowIndex !== undefined);
|
||||
};
|
||||
|
||||
export const migrateTextWrapToFieldLevel = (panel: PanelModel<Partial<Options>>) => {
|
||||
if (panel.fieldConfig?.defaults.custom?.wrapText !== undefined) {
|
||||
// already migrated
|
||||
return;
|
||||
}
|
||||
|
||||
const legacyDefaultWrapText: boolean | undefined = panel.fieldConfig?.defaults.custom?.cellOptions?.wrapText;
|
||||
|
||||
panel.fieldConfig.overrides = panel.fieldConfig.overrides.map((override) => {
|
||||
if (override.properties) {
|
||||
override.properties = override.properties.flatMap((property) => {
|
||||
if (property.id === 'custom.cellOptions' && property.value && property.value.wrapText !== undefined) {
|
||||
return [
|
||||
{ ...property, value: { ...omit(property.value, 'wrapText') } },
|
||||
{ id: 'custom.wrapText', value: property.value.wrapText },
|
||||
];
|
||||
}
|
||||
return [property];
|
||||
});
|
||||
}
|
||||
return override;
|
||||
});
|
||||
|
||||
panel.fieldConfig.defaults.custom = panel.fieldConfig.defaults.custom ?? {};
|
||||
panel.fieldConfig.defaults.custom.wrapText = legacyDefaultWrapText;
|
||||
delete panel.fieldConfig.defaults.custom.cellOptions?.wrapText;
|
||||
|
||||
return panel;
|
||||
};
|
||||
|
||||
export const migrateHiddenFields = (panel: PanelModel<Partial<Options>>) => {
|
||||
panel.fieldConfig.overrides = panel.fieldConfig.overrides.map((override) => {
|
||||
if (override.properties) {
|
||||
override.properties = override.properties.map((property) => {
|
||||
if (property.id === 'custom.hidden') {
|
||||
return { ...property, id: 'custom.hideFrom.viz' };
|
||||
}
|
||||
return property;
|
||||
});
|
||||
}
|
||||
return override;
|
||||
});
|
||||
|
||||
return panel;
|
||||
};
|
||||
|
||||
@@ -10,9 +10,9 @@ import {
|
||||
} from '@grafana/data';
|
||||
import { t } from '@grafana/i18n';
|
||||
import {
|
||||
defaultTableFieldOptions,
|
||||
TableCellOptions,
|
||||
TableCellDisplayMode,
|
||||
defaultTableFieldOptions,
|
||||
TableCellHeight,
|
||||
TableCellTooltipPlacement,
|
||||
} from '@grafana/schema';
|
||||
@@ -109,14 +109,17 @@ export const plugin = new PanelPlugin<Options, FieldConfig>(TablePanel)
|
||||
defaultValue: defaultTableFieldOptions.filterable,
|
||||
})
|
||||
.addBooleanSwitch({
|
||||
path: 'wrapHeaderText',
|
||||
name: t('table.name-wrap-header-text', 'Wrap header text'),
|
||||
description: t('table.description-wrap-header-text', 'Enables text wrapping for column headers'),
|
||||
path: 'wrapText',
|
||||
name: t('table.name-wrap-text', 'Wrap text'),
|
||||
category,
|
||||
defaultValue: undefined,
|
||||
})
|
||||
.addBooleanSwitch({
|
||||
path: 'hidden',
|
||||
path: 'wrapHeaderText',
|
||||
name: t('table.name-wrap-header-text', 'Wrap header text'),
|
||||
category,
|
||||
})
|
||||
.addBooleanSwitch({
|
||||
path: 'hideFrom.viz',
|
||||
name: t('table.name-hide-in-table', 'Hide in table'),
|
||||
category,
|
||||
defaultValue: undefined,
|
||||
|
||||
@@ -12771,7 +12771,6 @@
|
||||
"description-frozen-columns": "Columns are frozen from the left side of the table",
|
||||
"description-min-column-width": "The minimum width for column auto resizing",
|
||||
"description-tooltip-from-field": "Render a cell from a field (hidden or visible) in a tooltip",
|
||||
"description-wrap-header-text": "Enables text wrapping for column headers",
|
||||
"image-cell-options-editor": {
|
||||
"description-alt-text": "Alternative text that will be displayed if an image can't be displayed or for users who use a screen reader",
|
||||
"description-title-text": "Text that will be displayed when the image is hovered by a cursor",
|
||||
@@ -12806,11 +12805,9 @@
|
||||
"name-tooltip-from-field": "Tooltip from field",
|
||||
"name-tooltip-placement": "Tooltip placement",
|
||||
"name-wrap-header-text": "Wrap header text",
|
||||
"name-wrap-text": "Wrap text",
|
||||
"placeholder-column-width": "auto",
|
||||
"placeholder-fields": "All Numeric Fields",
|
||||
"text-wrap-options": {
|
||||
"label-wrap-text": "Wrap text"
|
||||
},
|
||||
"tooltip-placement-options": {
|
||||
"label-auto": "Auto",
|
||||
"label-bottom": "Bottom",
|
||||
|
||||
Reference in New Issue
Block a user