mirror of https://github.com/grafana/grafana.git
Canvas: Dynamic connection direction (#108423)
This commit is contained in:
parent
e49230d3eb
commit
25c13c55c0
|
@ -25,7 +25,6 @@
|
|||
"fiscalYearStartMonth": 0,
|
||||
"graphTooltip": 0,
|
||||
"links": [],
|
||||
"liveNow": false,
|
||||
"panels": [
|
||||
{
|
||||
"datasource": {
|
||||
|
@ -42,7 +41,7 @@
|
|||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
|
@ -156,11 +155,19 @@
|
|||
"x": -0.8229007633587786,
|
||||
"y": 0.27741935483870966
|
||||
},
|
||||
"sourceOriginal": {
|
||||
"x": 1223.8335877862596,
|
||||
"y": 300
|
||||
},
|
||||
"target": {
|
||||
"x": 1.0112359550561798,
|
||||
"y": -0.012987012987012988
|
||||
},
|
||||
"targetName": "Element 20",
|
||||
"targetOriginal": {
|
||||
"x": 990,
|
||||
"y": 474
|
||||
},
|
||||
"vertices": [
|
||||
{
|
||||
"x": -0.18181818181818182,
|
||||
|
@ -191,11 +198,19 @@
|
|||
"x": -0.3068702290076336,
|
||||
"y": -0.47419354838709676
|
||||
},
|
||||
"sourceOriginal": {
|
||||
"x": 1401.090076335878,
|
||||
"y": 533
|
||||
},
|
||||
"target": {
|
||||
"x": 1.0112359550561798,
|
||||
"y": -0.4805194805194805
|
||||
},
|
||||
"targetName": "Element 20",
|
||||
"targetOriginal": {
|
||||
"x": 990,
|
||||
"y": 492
|
||||
},
|
||||
"vertices": [
|
||||
{
|
||||
"x": 0.415,
|
||||
|
@ -227,11 +242,19 @@
|
|||
"x": 0.7903930131004366,
|
||||
"y": -0.36935483870967745
|
||||
},
|
||||
"sourceOriginal": {
|
||||
"x": 1778,
|
||||
"y": 500.5
|
||||
},
|
||||
"target": {
|
||||
"x": 1.0120481927710843,
|
||||
"y": 0.024691358024691357
|
||||
},
|
||||
"targetName": "Element 35",
|
||||
"targetOriginal": {
|
||||
"x": 1523,
|
||||
"y": 177
|
||||
},
|
||||
"vertices": [
|
||||
{
|
||||
"x": -0.1607843137254902,
|
||||
|
@ -518,11 +541,19 @@
|
|||
"x": 0.8876404494382022,
|
||||
"y": 0.2597402597402597
|
||||
},
|
||||
"sourceOriginal": {
|
||||
"x": 741,
|
||||
"y": 356.5
|
||||
},
|
||||
"target": {
|
||||
"x": -0.9775280898876404,
|
||||
"y": -0.012987012987012988
|
||||
},
|
||||
"targetName": "Element 19"
|
||||
"targetName": "Element 19",
|
||||
"targetOriginal": {
|
||||
"x": 813,
|
||||
"y": 358
|
||||
}
|
||||
}
|
||||
],
|
||||
"constraint": {
|
||||
|
@ -614,11 +645,19 @@
|
|||
"x": 0.8876404494382022,
|
||||
"y": 0.2597402597402597
|
||||
},
|
||||
"sourceOriginal": {
|
||||
"x": 741,
|
||||
"y": 239.5
|
||||
},
|
||||
"target": {
|
||||
"x": -0.9887640449438202,
|
||||
"y": -0.06493506493506493
|
||||
},
|
||||
"targetName": "Element 18"
|
||||
"targetName": "Element 18",
|
||||
"targetOriginal": {
|
||||
"x": 812,
|
||||
"y": 242
|
||||
}
|
||||
}
|
||||
],
|
||||
"constraint": {
|
||||
|
@ -673,11 +712,19 @@
|
|||
"x": -0.2247191011235955,
|
||||
"y": -0.4805194805194805
|
||||
},
|
||||
"sourceOriginal": {
|
||||
"x": 342,
|
||||
"y": 395
|
||||
},
|
||||
"target": {
|
||||
"x": 0.011235955056179775,
|
||||
"y": 0.922077922077922
|
||||
},
|
||||
"targetName": "Element 12"
|
||||
"targetName": "Element 12",
|
||||
"targetOriginal": {
|
||||
"x": 343,
|
||||
"y": 458
|
||||
}
|
||||
},
|
||||
{
|
||||
"color": {
|
||||
|
@ -693,11 +740,19 @@
|
|||
"x": 0.7752808988764045,
|
||||
"y": 0.5194805194805194
|
||||
},
|
||||
"sourceOriginal": {
|
||||
"x": 431,
|
||||
"y": 356.5
|
||||
},
|
||||
"target": {
|
||||
"x": -1.0833333333333333,
|
||||
"y": 0.020618556701030927
|
||||
},
|
||||
"targetName": "Element 15"
|
||||
"targetName": "Element 15",
|
||||
"targetOriginal": {
|
||||
"x": 526,
|
||||
"y": 356
|
||||
}
|
||||
}
|
||||
],
|
||||
"constraint": {
|
||||
|
@ -888,11 +943,19 @@
|
|||
"x": 1,
|
||||
"y": 0.5
|
||||
},
|
||||
"sourceOriginal": {
|
||||
"x": 431,
|
||||
"y": 337.25
|
||||
},
|
||||
"target": {
|
||||
"x": -1.0112359550561798,
|
||||
"y": -0.012987012987012988
|
||||
},
|
||||
"targetName": "Element 16",
|
||||
"targetOriginal": {
|
||||
"x": 562,
|
||||
"y": 240
|
||||
},
|
||||
"vertices": [
|
||||
{
|
||||
"x": 0.42748091603053434,
|
||||
|
@ -963,11 +1026,19 @@
|
|||
"x": 0,
|
||||
"y": -1
|
||||
},
|
||||
"sourceOriginal": {
|
||||
"x": 150,
|
||||
"y": 223
|
||||
},
|
||||
"target": {
|
||||
"x": -0.5168539325842697,
|
||||
"y": 1
|
||||
},
|
||||
"targetName": "Element 6",
|
||||
"targetOriginal": {
|
||||
"x": 296,
|
||||
"y": 318
|
||||
},
|
||||
"vertices": [
|
||||
{
|
||||
"x": 0,
|
||||
|
@ -996,11 +1067,19 @@
|
|||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
"sourceOriginal": {
|
||||
"x": 150,
|
||||
"y": 148
|
||||
},
|
||||
"target": {
|
||||
"x": -1.0112359550561798,
|
||||
"y": -0.012987012987012988
|
||||
},
|
||||
"targetName": "Element 30",
|
||||
"targetOriginal": {
|
||||
"x": 563,
|
||||
"y": 82
|
||||
},
|
||||
"vertices": [
|
||||
{
|
||||
"x": 0,
|
||||
|
@ -1062,11 +1141,19 @@
|
|||
"x": 1,
|
||||
"y": 0
|
||||
},
|
||||
"sourceOriginal": {
|
||||
"x": 216,
|
||||
"y": 356.5
|
||||
},
|
||||
"target": {
|
||||
"x": -1.0112359550561798,
|
||||
"y": -0.012987012987012988
|
||||
},
|
||||
"targetName": "Element 6"
|
||||
"targetName": "Element 6",
|
||||
"targetOriginal": {
|
||||
"x": 252,
|
||||
"y": 357
|
||||
}
|
||||
}
|
||||
],
|
||||
"constraint": {
|
||||
|
@ -1121,11 +1208,19 @@
|
|||
"x": 0,
|
||||
"y": -1
|
||||
},
|
||||
"sourceOriginal": {
|
||||
"x": 342,
|
||||
"y": 223
|
||||
},
|
||||
"target": {
|
||||
"x": 0.011235955056179775,
|
||||
"y": 1.025974025974026
|
||||
},
|
||||
"targetName": "Element 6"
|
||||
"targetName": "Element 6",
|
||||
"targetOriginal": {
|
||||
"x": 343,
|
||||
"y": 317
|
||||
}
|
||||
}
|
||||
],
|
||||
"constraint": {
|
||||
|
@ -1218,11 +1313,19 @@
|
|||
"x": -1,
|
||||
"y": 0
|
||||
},
|
||||
"sourceOriginal": {
|
||||
"x": 38,
|
||||
"y": 493.5
|
||||
},
|
||||
"target": {
|
||||
"x": -1.0224719101123596,
|
||||
"y": 0.013333333333333334
|
||||
},
|
||||
"targetName": "Element 9",
|
||||
"targetOriginal": {
|
||||
"x": 59,
|
||||
"y": 185
|
||||
},
|
||||
"vertices": [
|
||||
{
|
||||
"x": -0.9523809523809523,
|
||||
|
@ -1399,11 +1502,19 @@
|
|||
"x": -1,
|
||||
"y": 0
|
||||
},
|
||||
"sourceOriginal": {
|
||||
"x": 563,
|
||||
"y": 473.5
|
||||
},
|
||||
"target": {
|
||||
"x": 1.0224719101123596,
|
||||
"y": -0.45454545454545453
|
||||
},
|
||||
"targetName": "Element 6",
|
||||
"targetOriginal": {
|
||||
"x": 433,
|
||||
"y": 374
|
||||
},
|
||||
"vertices": [
|
||||
{
|
||||
"x": 0.5692307692307692,
|
||||
|
@ -1468,11 +1579,19 @@
|
|||
"x": 1,
|
||||
"y": 0
|
||||
},
|
||||
"sourceOriginal": {
|
||||
"x": 989,
|
||||
"y": 239.5
|
||||
},
|
||||
"target": {
|
||||
"x": -0.96,
|
||||
"y": 0.4583333333333333
|
||||
},
|
||||
"targetName": "Element 2",
|
||||
"targetOriginal": {
|
||||
"x": 1392,
|
||||
"y": 487
|
||||
},
|
||||
"vertices": [
|
||||
{
|
||||
"x": 0.3349875930521092,
|
||||
|
@ -1506,11 +1625,19 @@
|
|||
"x": 1,
|
||||
"y": -0.5
|
||||
},
|
||||
"sourceOriginal": {
|
||||
"x": 989,
|
||||
"y": 258.75
|
||||
},
|
||||
"target": {
|
||||
"x": -0.9761904761904762,
|
||||
"y": 0.5263157894736842
|
||||
},
|
||||
"targetName": "Element 34",
|
||||
"targetOriginal": {
|
||||
"x": 1138,
|
||||
"y": 290
|
||||
},
|
||||
"vertices": [
|
||||
{
|
||||
"x": 0.5033557046979866,
|
||||
|
@ -1612,11 +1739,19 @@
|
|||
"x": -1,
|
||||
"y": 0
|
||||
},
|
||||
"sourceOriginal": {
|
||||
"x": 811,
|
||||
"y": 473.5
|
||||
},
|
||||
"target": {
|
||||
"x": 1.0112359550561798,
|
||||
"y": 0.012987012987012988
|
||||
},
|
||||
"targetName": "Element 17"
|
||||
"targetName": "Element 17",
|
||||
"targetOriginal": {
|
||||
"x": 742,
|
||||
"y": 473
|
||||
}
|
||||
}
|
||||
],
|
||||
"constraint": {
|
||||
|
@ -1671,11 +1806,19 @@
|
|||
"x": 1,
|
||||
"y": -0.5
|
||||
},
|
||||
"sourceOriginal": {
|
||||
"x": 1025.5,
|
||||
"y": 382.25
|
||||
},
|
||||
"target": {
|
||||
"x": -1.0238095238095237,
|
||||
"y": 0.10526315789473684
|
||||
},
|
||||
"targetName": "Element 33"
|
||||
"targetName": "Element 33",
|
||||
"targetOriginal": {
|
||||
"x": 1136,
|
||||
"y": 384
|
||||
}
|
||||
},
|
||||
{
|
||||
"color": {
|
||||
|
@ -1691,11 +1834,19 @@
|
|||
"x": 1,
|
||||
"y": 0.5
|
||||
},
|
||||
"sourceOriginal": {
|
||||
"x": 1025.5,
|
||||
"y": 333.75
|
||||
},
|
||||
"target": {
|
||||
"x": -1,
|
||||
"y": 0.05263157894736842
|
||||
},
|
||||
"targetName": "Element 34",
|
||||
"targetOriginal": {
|
||||
"x": 1137,
|
||||
"y": 299
|
||||
},
|
||||
"vertices": [
|
||||
{
|
||||
"x": 0.5246636771300448,
|
||||
|
@ -1721,11 +1872,19 @@
|
|||
"x": 1,
|
||||
"y": 0
|
||||
},
|
||||
"sourceOriginal": {
|
||||
"x": 1025.5,
|
||||
"y": 358
|
||||
},
|
||||
"target": {
|
||||
"x": -0.98,
|
||||
"y": -0.10416666666666667
|
||||
},
|
||||
"targetName": "Element 2",
|
||||
"targetOriginal": {
|
||||
"x": 1391,
|
||||
"y": 514
|
||||
},
|
||||
"vertices": [
|
||||
{
|
||||
"x": 0.7564979480164159,
|
||||
|
@ -1792,11 +1951,19 @@
|
|||
"x": 1,
|
||||
"y": 0
|
||||
},
|
||||
"sourceOriginal": {
|
||||
"x": 742,
|
||||
"y": 81.5
|
||||
},
|
||||
"target": {
|
||||
"x": -1.0112359550561798,
|
||||
"y": -0.012987012987012988
|
||||
},
|
||||
"targetName": "Element 31"
|
||||
"targetName": "Element 31",
|
||||
"targetOriginal": {
|
||||
"x": 811,
|
||||
"y": 82
|
||||
}
|
||||
},
|
||||
{
|
||||
"color": {
|
||||
|
@ -1818,11 +1985,19 @@
|
|||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
"sourceOriginal": {
|
||||
"x": 653,
|
||||
"y": 43
|
||||
},
|
||||
"target": {
|
||||
"x": -0.029411764705882353,
|
||||
"y": 1
|
||||
},
|
||||
"targetName": "Element 38",
|
||||
"targetOriginal": {
|
||||
"x": 1673,
|
||||
"y": 249
|
||||
},
|
||||
"vertices": [
|
||||
{
|
||||
"x": 0,
|
||||
|
@ -1892,11 +2067,19 @@
|
|||
"x": 1,
|
||||
"y": 0
|
||||
},
|
||||
"sourceOriginal": {
|
||||
"x": 990,
|
||||
"y": 81.5
|
||||
},
|
||||
"target": {
|
||||
"x": -0.9939759036144579,
|
||||
"y": 0.5061728395061729
|
||||
},
|
||||
"targetName": "Element 35",
|
||||
"targetOriginal": {
|
||||
"x": 1190,
|
||||
"y": 138
|
||||
},
|
||||
"vertices": [
|
||||
{
|
||||
"x": 0.48,
|
||||
|
@ -1961,11 +2144,19 @@
|
|||
"x": 1,
|
||||
"y": 0
|
||||
},
|
||||
"sourceOriginal": {
|
||||
"x": 1221,
|
||||
"y": 386
|
||||
},
|
||||
"target": {
|
||||
"x": 1.0337078651685394,
|
||||
"y": 0.45454545454545453
|
||||
},
|
||||
"targetName": "Element 20",
|
||||
"targetOriginal": {
|
||||
"x": 992,
|
||||
"y": 456
|
||||
},
|
||||
"vertices": [
|
||||
{
|
||||
"x": -0.05240174672489083,
|
||||
|
@ -2067,11 +2258,19 @@
|
|||
"x": -1,
|
||||
"y": 0
|
||||
},
|
||||
"sourceOriginal": {
|
||||
"x": 1189,
|
||||
"y": 179
|
||||
},
|
||||
"target": {
|
||||
"x": 0.19444444444444445,
|
||||
"y": 0.9896907216494846
|
||||
},
|
||||
"targetName": "Element 29",
|
||||
"targetOriginal": {
|
||||
"x": 1011,
|
||||
"y": 310
|
||||
},
|
||||
"vertices": [
|
||||
{
|
||||
"x": 1,
|
||||
|
@ -2169,11 +2368,19 @@
|
|||
"x": -1,
|
||||
"y": 0
|
||||
},
|
||||
"sourceOriginal": {
|
||||
"x": 1574,
|
||||
"y": 308
|
||||
},
|
||||
"target": {
|
||||
"x": -0.4977168949771689,
|
||||
"y": 1.017467248908297
|
||||
},
|
||||
"targetName": "Element 36",
|
||||
"targetOriginal": {
|
||||
"x": 1450,
|
||||
"y": 384
|
||||
},
|
||||
"vertices": [
|
||||
{
|
||||
"x": 1,
|
||||
|
@ -2208,7 +2415,7 @@
|
|||
},
|
||||
"showAdvancedTypes": true
|
||||
},
|
||||
"pluginVersion": "11.1.0-pre",
|
||||
"pluginVersion": "12.1.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
|
@ -2236,7 +2443,8 @@
|
|||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green"
|
||||
"color": "green",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"color": "#6ED0E0",
|
||||
|
@ -2260,7 +2468,7 @@
|
|||
"h": 11,
|
||||
"w": 15,
|
||||
"x": 5,
|
||||
"y": 22
|
||||
"y": 36
|
||||
},
|
||||
"id": 4,
|
||||
"options": {
|
||||
|
@ -2320,11 +2528,19 @@
|
|||
"x": 1,
|
||||
"y": 0
|
||||
},
|
||||
"sourceOriginal": {
|
||||
"x": 216,
|
||||
"y": 192
|
||||
},
|
||||
"target": {
|
||||
"x": -1.02020202020202,
|
||||
"y": 0.041666666666666664
|
||||
},
|
||||
"targetName": "Element 2"
|
||||
"targetName": "Element 2",
|
||||
"targetOriginal": {
|
||||
"x": 326,
|
||||
"y": 191
|
||||
}
|
||||
}
|
||||
],
|
||||
"constraint": {
|
||||
|
@ -2377,11 +2593,19 @@
|
|||
"x": 1,
|
||||
"y": 1
|
||||
},
|
||||
"sourceOriginal": {
|
||||
"x": 426,
|
||||
"y": 168
|
||||
},
|
||||
"target": {
|
||||
"x": -0.9797979797979798,
|
||||
"y": 0
|
||||
},
|
||||
"targetName": "Element 3"
|
||||
"targetName": "Element 3",
|
||||
"targetOriginal": {
|
||||
"x": 549,
|
||||
"y": 93
|
||||
}
|
||||
},
|
||||
{
|
||||
"color": {
|
||||
|
@ -2398,11 +2622,19 @@
|
|||
"x": 1,
|
||||
"y": -1
|
||||
},
|
||||
"sourceOriginal": {
|
||||
"x": 426,
|
||||
"y": 216
|
||||
},
|
||||
"target": {
|
||||
"x": -1,
|
||||
"y": 0.041666666666666664
|
||||
},
|
||||
"targetName": "Element 4"
|
||||
"targetName": "Element 4",
|
||||
"targetOriginal": {
|
||||
"x": 549,
|
||||
"y": 297
|
||||
}
|
||||
}
|
||||
],
|
||||
"constraint": {
|
||||
|
@ -2455,11 +2687,19 @@
|
|||
"x": 1,
|
||||
"y": 0
|
||||
},
|
||||
"sourceOriginal": {
|
||||
"x": 647,
|
||||
"y": 93
|
||||
},
|
||||
"target": {
|
||||
"x": -0.9595959595959596,
|
||||
"y": -0.041666666666666664
|
||||
},
|
||||
"targetName": "Element 11"
|
||||
"targetName": "Element 11",
|
||||
"targetOriginal": {
|
||||
"x": 799,
|
||||
"y": 94
|
||||
}
|
||||
}
|
||||
],
|
||||
"constraint": {
|
||||
|
@ -2512,11 +2752,19 @@
|
|||
"x": 1,
|
||||
"y": 0
|
||||
},
|
||||
"sourceOriginal": {
|
||||
"x": 648,
|
||||
"y": 298
|
||||
},
|
||||
"target": {
|
||||
"x": -0.9797979797979798,
|
||||
"y": 0.041666666666666664
|
||||
},
|
||||
"targetName": "Element 5"
|
||||
"targetName": "Element 5",
|
||||
"targetOriginal": {
|
||||
"x": 798,
|
||||
"y": 299
|
||||
}
|
||||
}
|
||||
],
|
||||
"constraint": {
|
||||
|
@ -2838,7 +3086,7 @@
|
|||
},
|
||||
"showAdvancedTypes": false
|
||||
},
|
||||
"pluginVersion": "11.1.0-pre",
|
||||
"pluginVersion": "12.1.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"csvContent": "gateway, product-details, product-reviews, reviews-ratings, details-checkout\n100, 56, 44, 22, 28",
|
||||
|
@ -2873,7 +3121,8 @@
|
|||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green"
|
||||
"color": "green",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"color": "blue",
|
||||
|
@ -2897,7 +3146,7 @@
|
|||
"h": 15,
|
||||
"w": 15,
|
||||
"x": 5,
|
||||
"y": 33
|
||||
"y": 47
|
||||
},
|
||||
"id": 2,
|
||||
"options": {
|
||||
|
@ -2949,6 +3198,10 @@
|
|||
"field": "server_database2",
|
||||
"fixed": "white"
|
||||
},
|
||||
"direction": {
|
||||
"field": "server_database2",
|
||||
"mode": "field"
|
||||
},
|
||||
"path": "straight",
|
||||
"size": {
|
||||
"fixed": 2,
|
||||
|
@ -2959,17 +3212,29 @@
|
|||
"x": -1,
|
||||
"y": -1
|
||||
},
|
||||
"sourceOriginal": {
|
||||
"x": 468,
|
||||
"y": 125
|
||||
},
|
||||
"target": {
|
||||
"x": 0.030303030303030304,
|
||||
"y": 0
|
||||
},
|
||||
"targetName": "Element 11"
|
||||
"targetName": "Element 11",
|
||||
"targetOriginal": {
|
||||
"x": 285,
|
||||
"y": 170
|
||||
}
|
||||
},
|
||||
{
|
||||
"color": {
|
||||
"field": "server_database",
|
||||
"fixed": "white"
|
||||
},
|
||||
"direction": {
|
||||
"field": "server_database",
|
||||
"mode": "field"
|
||||
},
|
||||
"path": "straight",
|
||||
"size": {
|
||||
"fixed": 2,
|
||||
|
@ -2980,17 +3245,29 @@
|
|||
"x": -1,
|
||||
"y": -1
|
||||
},
|
||||
"sourceOriginal": {
|
||||
"x": 468,
|
||||
"y": 125
|
||||
},
|
||||
"target": {
|
||||
"x": 0.09090909090909091,
|
||||
"y": 0.16666666666666666
|
||||
},
|
||||
"targetName": "Element 12"
|
||||
"targetName": "Element 12",
|
||||
"targetOriginal": {
|
||||
"x": 390,
|
||||
"y": 264
|
||||
}
|
||||
},
|
||||
{
|
||||
"color": {
|
||||
"field": "server_region",
|
||||
"fixed": "white"
|
||||
},
|
||||
"direction": {
|
||||
"field": "server_region",
|
||||
"mode": "field"
|
||||
},
|
||||
"path": "straight",
|
||||
"size": {
|
||||
"fixed": 2,
|
||||
|
@ -3001,11 +3278,19 @@
|
|||
"x": 1,
|
||||
"y": -1
|
||||
},
|
||||
"sourceOriginal": {
|
||||
"x": 588.9921875,
|
||||
"y": 125
|
||||
},
|
||||
"target": {
|
||||
"x": -0.2727272727272727,
|
||||
"y": 0.4166666666666667
|
||||
},
|
||||
"targetName": "Element 13"
|
||||
"targetName": "Element 13",
|
||||
"targetOriginal": {
|
||||
"x": 658,
|
||||
"y": 259
|
||||
}
|
||||
}
|
||||
],
|
||||
"constraint": {
|
||||
|
@ -3050,6 +3335,10 @@
|
|||
"field": "database_server",
|
||||
"fixed": "white"
|
||||
},
|
||||
"direction": {
|
||||
"field": "database_server",
|
||||
"mode": "field"
|
||||
},
|
||||
"path": "straight",
|
||||
"size": {
|
||||
"fixed": 2,
|
||||
|
@ -3060,11 +3349,19 @@
|
|||
"x": 1,
|
||||
"y": 1
|
||||
},
|
||||
"sourceOriginal": {
|
||||
"x": 328,
|
||||
"y": 367
|
||||
},
|
||||
"target": {
|
||||
"x": -0.15151515151515152,
|
||||
"y": -0.16666666666666666
|
||||
},
|
||||
"targetName": "Element 12"
|
||||
"targetName": "Element 12",
|
||||
"targetOriginal": {
|
||||
"x": 386,
|
||||
"y": 268
|
||||
}
|
||||
}
|
||||
],
|
||||
"constraint": {
|
||||
|
@ -3109,6 +3406,10 @@
|
|||
"field": "region_server",
|
||||
"fixed": "white"
|
||||
},
|
||||
"direction": {
|
||||
"field": "region_server",
|
||||
"mode": "field"
|
||||
},
|
||||
"path": "straight",
|
||||
"size": {
|
||||
"fixed": 2,
|
||||
|
@ -3119,11 +3420,19 @@
|
|||
"x": -1,
|
||||
"y": 1
|
||||
},
|
||||
"sourceOriginal": {
|
||||
"x": 699,
|
||||
"y": 365
|
||||
},
|
||||
"target": {
|
||||
"x": -0.21212121212121213,
|
||||
"y": 0.08333333333333333
|
||||
},
|
||||
"targetName": "Element 13"
|
||||
"targetName": "Element 13",
|
||||
"targetOriginal": {
|
||||
"x": 659,
|
||||
"y": 263
|
||||
}
|
||||
}
|
||||
],
|
||||
"constraint": {
|
||||
|
@ -3212,6 +3521,10 @@
|
|||
"field": "database2_server",
|
||||
"fixed": "white"
|
||||
},
|
||||
"direction": {
|
||||
"field": "database2_server",
|
||||
"mode": "field"
|
||||
},
|
||||
"path": "straight",
|
||||
"size": {
|
||||
"fixed": 2,
|
||||
|
@ -3222,11 +3535,19 @@
|
|||
"x": 1,
|
||||
"y": 1
|
||||
},
|
||||
"sourceOriginal": {
|
||||
"x": 172,
|
||||
"y": 191
|
||||
},
|
||||
"target": {
|
||||
"x": -0.3333333333333333,
|
||||
"y": 0
|
||||
},
|
||||
"targetName": "Element 11"
|
||||
"targetName": "Element 11",
|
||||
"targetOriginal": {
|
||||
"x": 279,
|
||||
"y": 170
|
||||
}
|
||||
}
|
||||
],
|
||||
"constraint": {
|
||||
|
@ -3605,7 +3926,7 @@
|
|||
},
|
||||
"showAdvancedTypes": false
|
||||
},
|
||||
"pluginVersion": "11.1.0-pre",
|
||||
"pluginVersion": "12.1.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"csvContent": "database_server, server_database, server_region, region_server, database2_server, server_database2\n10, 53, 35, 12, 22, 81",
|
||||
|
@ -3620,9 +3941,9 @@
|
|||
"type": "canvas"
|
||||
}
|
||||
],
|
||||
"preload": false,
|
||||
"refresh": "",
|
||||
"revision": 1,
|
||||
"schemaVersion": 39,
|
||||
"schemaVersion": 41,
|
||||
"tags": ["gdev", "panel-tests", "canvas"],
|
||||
"templating": {
|
||||
"list": []
|
||||
|
@ -3631,11 +3952,9 @@
|
|||
"from": "now-6h",
|
||||
"to": "now"
|
||||
},
|
||||
"timeRangeUpdatedDuringEditOrView": false,
|
||||
"timepicker": {},
|
||||
"timezone": "",
|
||||
"title": "Panel Tests - Canvas Connection Examples",
|
||||
"uid": "Pu8lwQAVz",
|
||||
"version": 6,
|
||||
"weekStart": ""
|
||||
"version": 15
|
||||
}
|
||||
|
|
|
@ -481,12 +481,19 @@ You can style the selected connection using the following options:
|
|||
- **Color** - Set the connection color.
|
||||
- **Size** - Control the size of the connection by entering a number in the **Value** field.
|
||||
- **Radius** - Add curve to the connection by entering a value to represent the degree.
|
||||
- **Arrow Direction** - Control the appearance of the arrow head. Choose from:
|
||||
- **Direction** - Control the appearance of the arrow head. Choose your source from **Fixed** or **Field**. The default value is **Forward** regardless of the source type.
|
||||
|
||||
If the direction source is **Fixed**, choose from:
|
||||
- **Forward** - The arrow head points in the direction in which the connection was drawn.
|
||||
- **Reverse** - The arrow head points in the opposite direction of which the connection was drawn.
|
||||
- **Both** - Adds arrow heads to both ends of the connection.
|
||||
- **None** - Removes the arrow head.
|
||||
|
||||
If the direction source is **Field**, select a field that contains numeric values:
|
||||
- **Positive values** - Display forward arrows.
|
||||
- **Negative values** - Display reverse arrows.
|
||||
- **Zero** - Display no arrow heads.
|
||||
|
||||
- **Line style** - Choose from the following line styles: **Solid**, **Dashed**, and **Dotted**.
|
||||
|
||||
### Standard options
|
||||
|
|
|
@ -111,6 +111,26 @@ export enum ResourceDimensionMode {
|
|||
Mapping = 'mapping',
|
||||
}
|
||||
|
||||
/**
|
||||
* Links to a resource (image/svg path)
|
||||
*/
|
||||
export interface ResourceDimensionConfig extends BaseDimensionConfig {
|
||||
fixed?: string;
|
||||
mode: ResourceDimensionMode;
|
||||
}
|
||||
|
||||
export enum ConnectionDirection {
|
||||
Both = 'both',
|
||||
Forward = 'forward',
|
||||
None = 'none',
|
||||
Reverse = 'reverse',
|
||||
}
|
||||
|
||||
export enum DirectionDimensionMode {
|
||||
Field = 'field',
|
||||
Fixed = 'fixed',
|
||||
}
|
||||
|
||||
export interface MapLayerOptions {
|
||||
/**
|
||||
* Custom options depending on the type
|
||||
|
@ -899,12 +919,9 @@ export interface DataSourceRef {
|
|||
uid?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Links to a resource (image/svg path)
|
||||
*/
|
||||
export interface ResourceDimensionConfig extends BaseDimensionConfig {
|
||||
fixed?: string;
|
||||
mode: ResourceDimensionMode;
|
||||
export interface DirectionDimensionConfig extends BaseDimensionConfig {
|
||||
fixed?: ConnectionDirection;
|
||||
mode: DirectionDimensionMode;
|
||||
}
|
||||
|
||||
export interface FrameGeometrySource {
|
||||
|
|
|
@ -47,3 +47,12 @@ ResourceDimensionConfig: {
|
|||
fixed?: string
|
||||
}@cuetsy(kind="interface")
|
||||
|
||||
ConnectionDirection: "forward" | "reverse" | "both" | "none" @cuetsy(kind="enum", memberNames="Forward|Reverse|Both|None")
|
||||
|
||||
DirectionDimensionMode: "fixed" | "field" @cuetsy(kind="enum")
|
||||
|
||||
DirectionDimensionConfig: {
|
||||
BaseDimensionConfig
|
||||
mode: DirectionDimensionMode
|
||||
fixed?: ConnectionDirection
|
||||
}@cuetsy(kind="interface")
|
||||
|
|
|
@ -80,6 +80,7 @@ export enum ConnectionPath {
|
|||
|
||||
export interface CanvasConnection {
|
||||
color?: ui.ColorDimensionConfig;
|
||||
direction?: ui.DirectionDimensionConfig;
|
||||
path: ConnectionPath;
|
||||
size?: ui.ScaleDimensionConfig;
|
||||
source: ConnectionCoordinates;
|
||||
|
|
|
@ -2,7 +2,7 @@ import { ComponentType } from 'react';
|
|||
|
||||
import { DataLink, RegistryItem, Action } from '@grafana/data';
|
||||
import { PanelOptionsSupplier } from '@grafana/data/internal';
|
||||
import { ColorDimensionConfig, ScaleDimensionConfig } from '@grafana/schema';
|
||||
import { ColorDimensionConfig, ScaleDimensionConfig, DirectionDimensionConfig } from '@grafana/schema';
|
||||
import { config } from 'app/core/config';
|
||||
import { BackgroundConfig, Constraint, LineConfig, Placement } from 'app/plugins/panel/canvas/panelcfg.gen';
|
||||
|
||||
|
@ -64,7 +64,7 @@ export interface CanvasConnection {
|
|||
lineStyle?: LineStyleConfig;
|
||||
vertices?: ConnectionCoordinates[];
|
||||
radius?: ScaleDimensionConfig;
|
||||
direction?: ConnectionDirection;
|
||||
direction?: DirectionDimensionConfig;
|
||||
sourceOriginal?: ConnectionCoordinates;
|
||||
targetOriginal?: ConnectionCoordinates;
|
||||
// See https://github.com/anseki/leader-line#options for more examples of more properties
|
||||
|
|
|
@ -14,6 +14,7 @@ import {
|
|||
ScaleDimensionConfig,
|
||||
TextDimensionConfig,
|
||||
TooltipDisplayMode,
|
||||
DirectionDimensionConfig,
|
||||
} from '@grafana/schema';
|
||||
import { Portal } from '@grafana/ui';
|
||||
import { config } from 'app/core/config';
|
||||
|
@ -24,6 +25,7 @@ import {
|
|||
getScalarDimensionFromData,
|
||||
getScaleDimensionFromData,
|
||||
getTextDimensionFromData,
|
||||
getDirectionDimensionFromData,
|
||||
} from 'app/features/dimensions/utils';
|
||||
import { CanvasContextMenu } from 'app/plugins/panel/canvas/components/CanvasContextMenu';
|
||||
import { CanvasTooltip } from 'app/plugins/panel/canvas/components/CanvasTooltip';
|
||||
|
@ -207,6 +209,7 @@ export class Scene {
|
|||
getScalar: (scalar: ScalarDimensionConfig) => getScalarDimensionFromData(this.data, scalar),
|
||||
getText: (text: TextDimensionConfig) => getTextDimensionFromData(this.data, text),
|
||||
getResource: (res: ResourceDimensionConfig) => getResourceDimensionFromData(this.data, res),
|
||||
getDirection: (direction: DirectionDimensionConfig) => getDirectionDimensionFromData(this.data, direction),
|
||||
getPanelData: () => this.data,
|
||||
};
|
||||
|
||||
|
|
|
@ -5,15 +5,24 @@ import {
|
|||
ScalarDimensionConfig,
|
||||
ScaleDimensionConfig,
|
||||
TextDimensionConfig,
|
||||
DirectionDimensionConfig,
|
||||
ConnectionDirection,
|
||||
} from '@grafana/schema';
|
||||
|
||||
import { DimensionSupplier } from './types';
|
||||
|
||||
export interface DimensionContext {
|
||||
getColor(color: ColorDimensionConfig): DimensionSupplier<string>;
|
||||
|
||||
getScale(scale: ScaleDimensionConfig): DimensionSupplier<number>;
|
||||
|
||||
getScalar(scalar: ScalarDimensionConfig): DimensionSupplier<number>;
|
||||
|
||||
getText(text: TextDimensionConfig): DimensionSupplier<string>;
|
||||
|
||||
getResource(resource: ResourceDimensionConfig): DimensionSupplier<string>;
|
||||
|
||||
getDirection(direction: DirectionDimensionConfig): DimensionSupplier<ConnectionDirection>;
|
||||
|
||||
getPanelData(): PanelData | undefined;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
import { DataFrame, Field } from '@grafana/data';
|
||||
import { ConnectionDirection, DirectionDimensionConfig, DirectionDimensionMode } from '@grafana/schema';
|
||||
|
||||
import { DimensionSupplier } from './types';
|
||||
import { findField, getLastNotNullFieldValue } from './utils';
|
||||
|
||||
//---------------------------------------------------------
|
||||
// Direction dimension
|
||||
//---------------------------------------------------------
|
||||
|
||||
export function getDirectionDimension(
|
||||
frame: DataFrame | undefined,
|
||||
config: DirectionDimensionConfig
|
||||
): DimensionSupplier<ConnectionDirection> {
|
||||
return getDirectionDimensionForField(findField(frame, config.field), config);
|
||||
}
|
||||
|
||||
export function getDirectionDimensionForField(
|
||||
field: Field | undefined,
|
||||
config: DirectionDimensionConfig
|
||||
): DimensionSupplier<ConnectionDirection> {
|
||||
const mode = config.mode ?? DirectionDimensionMode.Fixed;
|
||||
|
||||
if (mode === DirectionDimensionMode.Fixed || !field) {
|
||||
const v = config.fixed ?? ConnectionDirection.Forward;
|
||||
return {
|
||||
isAssumed: Boolean(config.field?.length) || !config.fixed,
|
||||
fixed: v,
|
||||
value: () => v,
|
||||
get: () => v,
|
||||
};
|
||||
}
|
||||
|
||||
const getDirectionFromValue = (value: unknown): ConnectionDirection => {
|
||||
if (value == null) {
|
||||
return ConnectionDirection.Forward;
|
||||
}
|
||||
|
||||
const numValue = Number(value);
|
||||
if (isNaN(numValue)) {
|
||||
return ConnectionDirection.Forward;
|
||||
}
|
||||
|
||||
if (numValue > 0) {
|
||||
return ConnectionDirection.Forward;
|
||||
} else if (numValue < 0) {
|
||||
return ConnectionDirection.Reverse;
|
||||
} else {
|
||||
return ConnectionDirection.None;
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
field,
|
||||
get: (index: number): ConnectionDirection => getDirectionFromValue(field.values[index]),
|
||||
value: () => getDirectionFromValue(getLastNotNullFieldValue(field)),
|
||||
};
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
import { useCallback } from 'react';
|
||||
|
||||
import {
|
||||
FieldNamePickerConfigSettings,
|
||||
SelectableValue,
|
||||
StandardEditorProps,
|
||||
StandardEditorsRegistryItem,
|
||||
} from '@grafana/data';
|
||||
import { t } from '@grafana/i18n';
|
||||
import { DirectionDimensionMode, DirectionDimensionConfig, ConnectionDirection } from '@grafana/schema';
|
||||
import { InlineField, InlineFieldRow, RadioButtonGroup, Select } from '@grafana/ui';
|
||||
import { FieldNamePicker } from '@grafana/ui/internal';
|
||||
|
||||
import { DirectionDimensionOptions } from '../types';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
const dummyFieldSettings = {
|
||||
settings: {},
|
||||
} as StandardEditorsRegistryItem<string, FieldNamePickerConfigSettings>;
|
||||
|
||||
type Props = StandardEditorProps<DirectionDimensionConfig, DirectionDimensionOptions>;
|
||||
|
||||
export const DirectionDimensionEditor = ({ value, context, onChange }: Props) => {
|
||||
const directionOptions = [
|
||||
{
|
||||
label: t('dimensions.direction-dimension-editor.label-fixed', 'Fixed'),
|
||||
value: DirectionDimensionMode.Fixed,
|
||||
description: t('dimensions.direction-dimension-editor.description-fixed', 'Fixed direction value'),
|
||||
},
|
||||
{
|
||||
label: t('dimensions.direction-dimension-editor.label-field', 'Field'),
|
||||
value: DirectionDimensionMode.Field,
|
||||
description: t('dimensions.direction-dimension-editor.description-field', 'Direction based on field value'),
|
||||
},
|
||||
];
|
||||
|
||||
const fixedDirectionOptions: Array<SelectableValue<ConnectionDirection>> = [
|
||||
{ value: ConnectionDirection.Forward, label: t('canvas.connection.direction-options.label-forward', 'Forward') },
|
||||
{ value: ConnectionDirection.Reverse, label: t('canvas.connection.direction-options.label-reverse', 'Reverse') },
|
||||
{ value: ConnectionDirection.Both, label: t('canvas.connection.direction-options.label-both', 'Both') },
|
||||
{ value: ConnectionDirection.None, label: t('canvas.connection.direction-options.label-none', 'None') },
|
||||
];
|
||||
|
||||
const labelWidth = 9;
|
||||
|
||||
const onModeChange = useCallback(
|
||||
(mode: DirectionDimensionMode) => {
|
||||
onChange({
|
||||
...value,
|
||||
mode,
|
||||
});
|
||||
},
|
||||
[onChange, value]
|
||||
);
|
||||
|
||||
const onFieldChange = useCallback(
|
||||
(field?: string) => {
|
||||
onChange({
|
||||
...value,
|
||||
field,
|
||||
});
|
||||
},
|
||||
[onChange, value]
|
||||
);
|
||||
|
||||
const onFixedChange = useCallback(
|
||||
(selection: SelectableValue<ConnectionDirection>) => {
|
||||
onChange({
|
||||
...value,
|
||||
field: undefined,
|
||||
fixed: selection.value ?? ConnectionDirection.Forward,
|
||||
});
|
||||
},
|
||||
[onChange, value]
|
||||
);
|
||||
|
||||
const mode = value?.mode ?? DirectionDimensionMode.Fixed;
|
||||
const selectedDirection = fixedDirectionOptions.find((opt) => opt.value === value?.fixed) || fixedDirectionOptions[0];
|
||||
|
||||
return (
|
||||
<>
|
||||
<InlineFieldRow>
|
||||
<InlineField
|
||||
label={t('dimensions.direction-dimension-editor.label-source', 'Source')}
|
||||
labelWidth={labelWidth}
|
||||
grow={true}
|
||||
>
|
||||
<RadioButtonGroup value={mode} options={directionOptions} onChange={onModeChange} fullWidth />
|
||||
</InlineField>
|
||||
</InlineFieldRow>
|
||||
|
||||
{mode === DirectionDimensionMode.Field && (
|
||||
<InlineFieldRow>
|
||||
<InlineField
|
||||
label={t('dimensions.direction-dimension-editor.label-field', 'Field')}
|
||||
labelWidth={labelWidth}
|
||||
grow={true}
|
||||
>
|
||||
<FieldNamePicker
|
||||
context={context}
|
||||
value={value?.field ?? ''}
|
||||
onChange={onFieldChange}
|
||||
item={dummyFieldSettings}
|
||||
/>
|
||||
</InlineField>
|
||||
</InlineFieldRow>
|
||||
)}
|
||||
|
||||
{mode === DirectionDimensionMode.Fixed && (
|
||||
<InlineFieldRow>
|
||||
<InlineField
|
||||
label={t('dimensions.direction-dimension-editor.label-direction', 'Direction')}
|
||||
labelWidth={labelWidth}
|
||||
grow={true}
|
||||
>
|
||||
<Select value={selectedDirection} options={fixedDirectionOptions} onChange={onFixedChange} />
|
||||
</InlineField>
|
||||
</InlineFieldRow>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
|
@ -85,3 +85,5 @@ export enum ResourcePickerSize {
|
|||
SMALL = 'small',
|
||||
NORMAL = 'normal',
|
||||
}
|
||||
|
||||
export interface DirectionDimensionOptions {}
|
||||
|
|
|
@ -6,9 +6,12 @@ import {
|
|||
TextDimensionConfig,
|
||||
ColorDimensionConfig,
|
||||
ScalarDimensionConfig,
|
||||
DirectionDimensionConfig,
|
||||
ConnectionDirection,
|
||||
} from '@grafana/schema';
|
||||
|
||||
import { getColorDimension } from './color';
|
||||
import { getDirectionDimension } from './direction';
|
||||
import { getResourceDimension } from './resource';
|
||||
import { getScalarDimension } from './scalar';
|
||||
import { getScaledDimension } from './scale';
|
||||
|
@ -30,6 +33,21 @@ export function getColorDimensionFromData(
|
|||
return getColorDimension(undefined, cfg, config.theme2);
|
||||
}
|
||||
|
||||
export function getDirectionDimensionFromData(
|
||||
data: PanelData | undefined,
|
||||
cfg: DirectionDimensionConfig
|
||||
): DimensionSupplier<ConnectionDirection> {
|
||||
if (data?.series && cfg.field) {
|
||||
for (const frame of data.series) {
|
||||
const d = getDirectionDimension(frame, cfg);
|
||||
if (!d.isAssumed || data.series.length === 1) {
|
||||
return d;
|
||||
}
|
||||
}
|
||||
}
|
||||
return getDirectionDimension(undefined, cfg);
|
||||
}
|
||||
|
||||
export function getScaleDimensionFromData(
|
||||
data: PanelData | undefined,
|
||||
cfg: ScaleDimensionConfig
|
||||
|
|
|
@ -2,9 +2,9 @@ import { css } from '@emotion/css';
|
|||
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { DirectionDimensionConfig, DirectionDimensionMode, ConnectionDirection } from '@grafana/schema';
|
||||
import { useStyles2 } from '@grafana/ui';
|
||||
import { config } from 'app/core/config';
|
||||
import { ConnectionDirection } from 'app/features/canvas/element';
|
||||
import { Scene } from 'app/features/canvas/runtime/scene';
|
||||
|
||||
import { ConnectionCoordinates } from '../../panelcfg.gen';
|
||||
|
@ -47,7 +47,10 @@ export const ConnectionSVG = ({
|
|||
const EDITOR_HEAD_ID = useMemo(() => `editorHead-${headId}`, [headId]);
|
||||
const defaultArrowColor = config.theme2.colors.text.primary;
|
||||
const defaultArrowSize = 2;
|
||||
const defaultArrowDirection = ConnectionDirection.Forward;
|
||||
const defaultArrowDirection: DirectionDimensionConfig = {
|
||||
mode: DirectionDimensionMode.Fixed,
|
||||
fixed: ConnectionDirection.Forward,
|
||||
};
|
||||
const maximumVertices = 10;
|
||||
|
||||
const [selectedConnection, setSelectedConnection] = useState<ConnectionState | undefined>(undefined);
|
||||
|
@ -162,7 +165,12 @@ export const ConnectionSVG = ({
|
|||
const yDist = yEnd - yStart;
|
||||
|
||||
const { strokeColor, strokeWidth, strokeRadius, arrowDirection, lineStyle, shouldAnimate } =
|
||||
getConnectionStyles(info, scene, defaultArrowSize, defaultArrowDirection);
|
||||
getConnectionStyles(
|
||||
info,
|
||||
scene,
|
||||
defaultArrowSize,
|
||||
defaultArrowDirection.fixed ?? ConnectionDirection.Forward
|
||||
);
|
||||
|
||||
const isSelected = selectedConnection === v && scene.panel.context.instanceState.selectedConnection;
|
||||
|
||||
|
|
|
@ -2,9 +2,9 @@ import { css } from '@emotion/css';
|
|||
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { DirectionDimensionConfig, DirectionDimensionMode, ConnectionDirection } from '@grafana/schema';
|
||||
import { useStyles2 } from '@grafana/ui';
|
||||
import { config } from 'app/core/config';
|
||||
import { ConnectionDirection } from 'app/features/canvas/element';
|
||||
import { Scene } from 'app/features/canvas/runtime/scene';
|
||||
|
||||
import { ConnectionCoordinates } from '../../panelcfg.gen';
|
||||
|
@ -38,7 +38,10 @@ export const ConnectionSVG = ({ setLineRef, setVertexPathRef, setVertexRef, setC
|
|||
const EDITOR_HEAD_ID = useMemo(() => `editorHead-${headId}`, [headId]);
|
||||
const defaultArrowColor = config.theme2.colors.text.primary;
|
||||
const defaultArrowSize = 2;
|
||||
const defaultArrowDirection = ConnectionDirection.Forward;
|
||||
const defaultArrowDirection: DirectionDimensionConfig = {
|
||||
mode: DirectionDimensionMode.Fixed,
|
||||
fixed: ConnectionDirection.Forward,
|
||||
};
|
||||
const maximumVertices = 10;
|
||||
|
||||
const [selectedConnection, setSelectedConnection] = useState<ConnectionState | undefined>(undefined);
|
||||
|
@ -152,7 +155,12 @@ export const ConnectionSVG = ({ setLineRef, setVertexPathRef, setVertexRef, setC
|
|||
const yDist = yEnd - yStart;
|
||||
|
||||
const { strokeColor, strokeWidth, strokeRadius, arrowDirection, lineStyle, shouldAnimate } =
|
||||
getConnectionStyles(info, scene, defaultArrowSize, defaultArrowDirection);
|
||||
getConnectionStyles(
|
||||
info,
|
||||
scene,
|
||||
defaultArrowSize,
|
||||
defaultArrowDirection.fixed ?? ConnectionDirection.Forward
|
||||
);
|
||||
|
||||
const isSelected = selectedConnection === v && scene.panel.context.instanceState.selectedConnection;
|
||||
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import { FieldType } from '@grafana/data';
|
||||
import { PanelOptionsSupplier } from '@grafana/data/internal';
|
||||
import { t } from '@grafana/i18n';
|
||||
import { ConnectionDirection } from 'app/features/canvas/element';
|
||||
import { ConnectionDirection, DirectionDimensionMode } from '@grafana/schema';
|
||||
import { SVGElements } from 'app/features/canvas/runtime/element';
|
||||
import { BackgroundSizeEditor } from 'app/features/dimensions/editors/BackgroundSizeEditor';
|
||||
import { ColorDimensionEditor } from 'app/features/dimensions/editors/ColorDimensionEditor';
|
||||
import { DirectionDimensionEditor } from 'app/features/dimensions/editors/DirectionDimensionEditor';
|
||||
import { ResourceDimensionEditor } from 'app/features/dimensions/editors/ResourceDimensionEditor';
|
||||
import { ScaleDimensionEditor } from 'app/features/dimensions/editors/ScaleDimensionEditor';
|
||||
|
||||
|
@ -181,20 +182,18 @@ export const optionBuilder: OptionSuppliers = {
|
|||
},
|
||||
|
||||
addDirection: (builder, context) => {
|
||||
const category = [t('canvas.category-arrow-direction', 'Arrow Direction')];
|
||||
builder.addRadio({
|
||||
const category = [t('canvas.category-arrow-direction', 'Direction')];
|
||||
builder.addCustomEditor({
|
||||
category,
|
||||
id: 'direction',
|
||||
path: 'direction',
|
||||
name: t('canvas.label-direction', 'Direction'),
|
||||
settings: {
|
||||
options: [
|
||||
{ value: undefined, label: t('canvas.direction-options.label-forward', 'Forward') },
|
||||
{ value: ConnectionDirection.Reverse, label: t('canvas.direction-options.label-reverse', 'Reverse') },
|
||||
{ value: ConnectionDirection.Both, label: t('canvas.direction-options.label-both', 'Both') },
|
||||
{ value: ConnectionDirection.None, label: t('canvas.direction-options.label-none', 'None') },
|
||||
],
|
||||
editor: DirectionDimensionEditor,
|
||||
settings: {},
|
||||
defaultValue: {
|
||||
mode: DirectionDimensionMode.Fixed,
|
||||
fixed: ConnectionDirection.Forward,
|
||||
},
|
||||
defaultValue: ConnectionDirection.Forward,
|
||||
});
|
||||
},
|
||||
|
||||
|
|
|
@ -42,4 +42,57 @@ describe('Canvas migration', () => {
|
|||
expect(panel.options.root.elements[0].links[0].oneClick).toBe(true);
|
||||
expect(panel.options.root.elements[0].actions[0].fetch.url).toBe('http://test.com');
|
||||
});
|
||||
|
||||
it('should migrate connection direction from string to object format', () => {
|
||||
const panel = {
|
||||
type: 'canvas',
|
||||
options: {
|
||||
root: {
|
||||
elements: [
|
||||
{
|
||||
name: 'Element 1',
|
||||
type: 'rectangle',
|
||||
connections: [
|
||||
{
|
||||
direction: 'forward',
|
||||
target: 'element2',
|
||||
},
|
||||
{
|
||||
direction: 'reverse',
|
||||
target: 'element3',
|
||||
},
|
||||
{
|
||||
direction: 'both',
|
||||
target: 'element4',
|
||||
},
|
||||
{
|
||||
target: 'element5',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
pluginVersion: '12.1',
|
||||
} as unknown as PanelModel;
|
||||
|
||||
panel.options = canvasMigrationHandler(panel);
|
||||
|
||||
const connectionsElement1 = panel.options.root.elements[0].connections;
|
||||
|
||||
expect(connectionsElement1[0].direction).toEqual({
|
||||
mode: 'fixed',
|
||||
fixed: 'forward',
|
||||
});
|
||||
|
||||
expect(connectionsElement1[1].direction).toEqual({
|
||||
mode: 'fixed',
|
||||
fixed: 'reverse',
|
||||
});
|
||||
|
||||
expect(connectionsElement1[2].direction).toEqual({
|
||||
mode: 'fixed',
|
||||
fixed: 'both',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -76,5 +76,28 @@ export const canvasMigrationHandler = (panel: PanelModel): Partial<Options> => {
|
|||
}
|
||||
}
|
||||
|
||||
// migrate connection direction
|
||||
if (parseFloat(pluginVersion) <= 12.2) {
|
||||
const root = panel.options?.root;
|
||||
if (root?.elements) {
|
||||
for (const element of root.elements) {
|
||||
for (const connection of element.connections || []) {
|
||||
if (connection.direction && typeof connection.direction === 'string') {
|
||||
// convert old direction to new format
|
||||
connection.direction = {
|
||||
mode: 'fixed',
|
||||
fixed: connection.direction,
|
||||
};
|
||||
} else if (!connection.direction) {
|
||||
connection.direction = {
|
||||
mode: 'fixed',
|
||||
fixed: 'forward',
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return panel.options;
|
||||
};
|
||||
|
|
|
@ -97,7 +97,10 @@ export const plugin = new PanelPlugin<Options>(CanvasPanel)
|
|||
},
|
||||
},
|
||||
})
|
||||
.setMigrationHandler(canvasMigrationHandler)
|
||||
.setMigrationHandler(canvasMigrationHandler, (panel) => {
|
||||
const pluginVersion = panel?.pluginVersion ?? '';
|
||||
return parseFloat(pluginVersion) <= 12.2;
|
||||
})
|
||||
.setPanelOptions((builder, context) => {
|
||||
const state: InstanceState = context.instanceState;
|
||||
|
||||
|
|
|
@ -73,6 +73,7 @@ composableKinds: PanelCfg: {
|
|||
path: ConnectionPath
|
||||
color?: ui.ColorDimensionConfig
|
||||
size?: ui.ScaleDimensionConfig
|
||||
direction?: ui.DirectionDimensionConfig
|
||||
vertices?: [...ConnectionCoordinates]
|
||||
sourceOriginal?: ConnectionCoordinates
|
||||
targetOriginal?: ConnectionCoordinates
|
||||
|
|
|
@ -78,6 +78,7 @@ export enum ConnectionPath {
|
|||
|
||||
export interface CanvasConnection {
|
||||
color?: ui.ColorDimensionConfig;
|
||||
direction?: ui.DirectionDimensionConfig;
|
||||
path: ConnectionPath;
|
||||
size?: ui.ScaleDimensionConfig;
|
||||
source: ConnectionCoordinates;
|
||||
|
|
|
@ -1,14 +1,10 @@
|
|||
import { isNumber, isString } from 'lodash';
|
||||
|
||||
import { DataFrame, Field, AppEvents, getFieldDisplayName, PluginState, SelectableValue } from '@grafana/data';
|
||||
import { ConnectionDirection } from '@grafana/schema';
|
||||
import appEvents from 'app/core/app_events';
|
||||
import { hasAlphaPanels, config } from 'app/core/config';
|
||||
import {
|
||||
CanvasConnection,
|
||||
CanvasElementItem,
|
||||
CanvasElementOptions,
|
||||
ConnectionDirection,
|
||||
} from 'app/features/canvas/element';
|
||||
import { CanvasConnection, CanvasElementItem, CanvasElementOptions } from 'app/features/canvas/element';
|
||||
import { notFoundItem } from 'app/features/canvas/elements/notFound';
|
||||
import { advancedElementItems, canvasElementRegistry, defaultElementItems } from 'app/features/canvas/registry';
|
||||
import { ElementState } from 'app/features/canvas/runtime/element';
|
||||
|
@ -107,6 +103,7 @@ export function onAddItem(sel: SelectableValue<string>, rootLayer: FrameState |
|
|||
export function isConnectionSource(element: ElementState) {
|
||||
return element.options.connections && element.options.connections.length > 0;
|
||||
}
|
||||
|
||||
export function isConnectionTarget(element: ElementState, sceneByName: Map<string, ElementState>) {
|
||||
const connections = getConnections(sceneByName);
|
||||
return connections.some((connection) => connection.target === element);
|
||||
|
@ -347,7 +344,9 @@ export const getConnectionStyles = (
|
|||
const strokeColor = info.color ? scene.context.getColor(info.color).value() : defaultArrowColor;
|
||||
const strokeWidth = info.size ? scene.context.getScale(info.size).get(lastRowIndex) : defaultArrowSize;
|
||||
const strokeRadius = info.radius ? scene.context.getScale(info.radius).get(lastRowIndex) : 0;
|
||||
const arrowDirection = info.direction ? info.direction : defaultArrowDirection;
|
||||
const arrowDirection = info.direction
|
||||
? scene.context.getDirection(info.direction).get(lastRowIndex)
|
||||
: defaultArrowDirection;
|
||||
const lineStyle = getLineStyle(info.lineStyle?.style);
|
||||
const shouldAnimate = info.lineStyle?.animate;
|
||||
|
||||
|
|
|
@ -3755,7 +3755,7 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"category-arrow-direction": "Arrow Direction",
|
||||
"category-arrow-direction": "Direction",
|
||||
"category-background": "Background",
|
||||
"category-border": "Border",
|
||||
"category-canvas": "Canvas",
|
||||
|
@ -3787,15 +3787,17 @@
|
|||
"auto": "Auto"
|
||||
}
|
||||
},
|
||||
"connection": {
|
||||
"direction-options": {
|
||||
"label-both": "Both",
|
||||
"label-forward": "Forward",
|
||||
"label-none": "None",
|
||||
"label-reverse": "Reverse"
|
||||
}
|
||||
},
|
||||
"description-experimental-types": "Enable selection of experimental element types",
|
||||
"description-inline-editing": "Enable editing the panel directly",
|
||||
"description-pan-zoom": "Enable pan and zoom",
|
||||
"direction-options": {
|
||||
"label-both": "Both",
|
||||
"label-forward": "Forward",
|
||||
"label-none": "None",
|
||||
"label-reverse": "Reverse"
|
||||
},
|
||||
"drone-front-item": {
|
||||
"category-drone-front": "Drone Front",
|
||||
"name-roll-angle": "Roll Angle"
|
||||
|
@ -6671,6 +6673,14 @@
|
|||
"label-fixed-color": "Fixed color",
|
||||
"noOptionsMessage-no-fields-found": "No fields found"
|
||||
},
|
||||
"direction-dimension-editor": {
|
||||
"description-field": "Direction based on field value",
|
||||
"description-fixed": "Fixed direction value",
|
||||
"label-direction": "Direction",
|
||||
"label-field": "Field",
|
||||
"label-fixed": "Fixed",
|
||||
"label-source": "Source"
|
||||
},
|
||||
"file-dropzone-custom-children": {
|
||||
"upload": "Upload"
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue