Browse Source

feat(table): added sanitize html option to column styles for table panel, fixes #4596

Torkel Ödegaard 9 years ago
parent
commit
65683ab241

+ 1 - 1
pkg/plugins/dashboards_updater.go

@@ -12,7 +12,7 @@ func init() {
 }
 }
 
 
 func updateAppDashboards() {
 func updateAppDashboards() {
-	time.Sleep(time.Second * 1)
+	time.Sleep(time.Second * 5)
 
 
 	plog.Debug("Looking for App Dashboard Updates")
 	plog.Debug("Looking for App Dashboard Updates")
 
 

+ 4 - 0
public/app/core/components/search/search.html

@@ -72,6 +72,10 @@
 			Import
 			Import
 		</a>
 		</a>
 
 
+		<a class="pull-right small muted" target="_blank" href="https://grafana.net/dashboards?utm_source=grafana_search">
+			Explore ready made dashboards on Grafana.net
+		</a>
+
  		<div class="clearfix"></div>
  		<div class="clearfix"></div>
 	</div>
 	</div>
 </div>
 </div>

+ 4 - 0
public/app/features/plugins/partials/plugin_list.html

@@ -5,6 +5,10 @@
   <div class="page-header">
   <div class="page-header">
     <h1>Plugins</h1>
     <h1>Plugins</h1>
 
 
+		<a class="btn btn-inverse" href="https://grafana.net/plugins?utm_source=grafana_plugin_list" target="_blank">
+			Explore plugins on Grafana.net
+		</a>
+
 		<div class="page-header-tabs">
 		<div class="page-header-tabs">
 			<ul class="gf-tabs">
 			<ul class="gf-tabs">
 				<li class="gf-tabs-item">
 				<li class="gf-tabs-item">

+ 6 - 1
public/app/plugins/panel/table/editor.html

@@ -103,6 +103,11 @@
 						<metric-segment-model property="style.dateFormat" options="editor.dateFormats" on-change="editor.render()" custom="true"></metric-segment-model>
 						<metric-segment-model property="style.dateFormat" options="editor.dateFormats" on-change="editor.render()" custom="true"></metric-segment-model>
 					</li>
 					</li>
 				</ul>
 				</ul>
+				<ul class="tight-form-list" ng-if="style.type === 'string'">
+					<li class="tight-form-item">
+						<editor-checkbox text="Sanitize HTML" model="style.sanitize" change="editor.render()"></editor-checkbox>
+					</li>
+				</ul>
 				<div class="clearfix"></div>
 				<div class="clearfix"></div>
 			</div>
 			</div>
 			<div class="tight-form" ng-if="style.type === 'number'">
 			<div class="tight-form" ng-if="style.type === 'number'">
@@ -152,7 +157,7 @@
 						Decimals
 						Decimals
 					</li>
 					</li>
 					<li style="width: 105px">
 					<li style="width: 105px">
-						<input type="number" class="input-mini tight-form-input" ng-model="style.decimals" ng-change="render()" ng-model-onblur>
+						<input type="number" class="input-mini tight-form-input" ng-model="style.decimals" ng-change="editor.render()" ng-model-onblur>
 					</li>
 					</li>
 				</ul>
 				</ul>
 				<div class="clearfix"></div>
 				<div class="clearfix"></div>

+ 2 - 2
public/app/plugins/panel/table/module.ts

@@ -45,7 +45,7 @@ class TablePanelCtrl extends MetricsPanelCtrl {
   };
   };
 
 
   /** @ngInject */
   /** @ngInject */
-  constructor($scope, $injector, private annotationsSrv) {
+  constructor($scope, $injector, private annotationsSrv, private $sanitize) {
     super($scope, $injector);
     super($scope, $injector);
     this.pageIndex = 0;
     this.pageIndex = 0;
 
 
@@ -159,7 +159,7 @@ class TablePanelCtrl extends MetricsPanelCtrl {
     }
     }
 
 
     function appendTableRows(tbodyElem) {
     function appendTableRows(tbodyElem) {
-      var renderer = new TableRenderer(panel, data, ctrl.dashboard.isTimezoneUtc());
+      var renderer = new TableRenderer(panel, data, ctrl.dashboard.isTimezoneUtc(), ctrl.$sanitize);
       tbodyElem.empty();
       tbodyElem.empty();
       tbodyElem.html(renderer.render(ctrl.pageIndex));
       tbodyElem.html(renderer.render(ctrl.pageIndex));
     }
     }

+ 11 - 6
public/app/plugins/panel/table/renderer.ts

@@ -8,7 +8,7 @@ export class TableRenderer {
   formaters: any[];
   formaters: any[];
   colorState: any;
   colorState: any;
 
 
-  constructor(private panel, private table, private isUtc) {
+  constructor(private panel, private table, private isUtc, private sanitize) {
     this.formaters = [];
     this.formaters = [];
     this.colorState = {};
     this.colorState = {};
   }
   }
@@ -24,7 +24,7 @@ export class TableRenderer {
     return _.first(style.colors);
     return _.first(style.colors);
   }
   }
 
 
-  defaultCellFormater(v) {
+  defaultCellFormater(v, style) {
     if (v === null || v === void 0 || v === undefined) {
     if (v === null || v === void 0 || v === undefined) {
       return '';
       return '';
     }
     }
@@ -33,7 +33,11 @@ export class TableRenderer {
       v = v.join(', ');
       v = v.join(', ');
     }
     }
 
 
-    return v;
+    if (style && style.sanitize) {
+      return this.sanitize(v);
+    } else {
+      return _.escape(v);
+    }
   }
   }
 
 
   createColumnFormater(style, column) {
   createColumnFormater(style, column) {
@@ -61,7 +65,7 @@ export class TableRenderer {
         }
         }
 
 
         if (_.isString(v)) {
         if (_.isString(v)) {
-          return v;
+          return this.defaultCellFormater(v, style);
         }
         }
 
 
         if (style.colorMode) {
         if (style.colorMode) {
@@ -72,7 +76,9 @@ export class TableRenderer {
       };
       };
     }
     }
 
 
-    return this.defaultCellFormater;
+    return (value) => {
+      return this.defaultCellFormater(value, style);
+    };
   }
   }
 
 
   formatColumnValue(colIndex, value) {
   formatColumnValue(colIndex, value) {
@@ -96,7 +102,6 @@ export class TableRenderer {
 
 
   renderCell(columnIndex, value, addWidthHack = false) {
   renderCell(columnIndex, value, addWidthHack = false) {
     value = this.formatColumnValue(columnIndex, value);
     value = this.formatColumnValue(columnIndex, value);
-    value = _.escape(value);
     var style = '';
     var style = '';
     if (this.colorState.cell) {
     if (this.colorState.cell) {
       style = ' style="background-color:' + this.colorState.cell + ';color: white"';
       style = ' style="background-color:' + this.colorState.cell + ';color: white"';

+ 16 - 1
public/app/plugins/panel/table/specs/renderer_specs.ts

@@ -13,6 +13,7 @@ describe('when rendering table', () => {
       {text: 'Undefined'},
       {text: 'Undefined'},
       {text: 'String'},
       {text: 'String'},
       {text: 'United', unit: 'bps'},
       {text: 'United', unit: 'bps'},
+      {text: 'Sanitized'},
     ];
     ];
 
 
     var panel = {
     var panel = {
@@ -47,11 +48,20 @@ describe('when rendering table', () => {
           type: 'number',
           type: 'number',
           unit: 'ms',
           unit: 'ms',
           decimals: 2,
           decimals: 2,
+        },
+        {
+          pattern: 'Sanitized',
+          type: 'string',
+          sanitize: true,
         }
         }
       ]
       ]
     };
     };
 
 
-    var renderer = new TableRenderer(panel, table, 'utc');
+    var sanitize = function(value) {
+      return 'sanitized';
+    };
+
+    var renderer = new TableRenderer(panel, table, 'utc', sanitize);
 
 
     it('time column should be formated', () => {
     it('time column should be formated', () => {
       var html = renderer.renderCell(0, 1388556366666);
       var html = renderer.renderCell(0, 1388556366666);
@@ -107,6 +117,11 @@ describe('when rendering table', () => {
       var html = renderer.renderCell(3, undefined);
       var html = renderer.renderCell(3, undefined);
       expect(html).to.be('<td></td>');
       expect(html).to.be('<td></td>');
     });
     });
+
+    it('sanitized value should render as', () => {
+      var html = renderer.renderCell(6, 'text <a href="http://google.com">link</a>');
+      expect(html).to.be('<td>sanitized</td>');
+    });
   });
   });
 });
 });
 
 

+ 1 - 0
public/sass/components/_search.scss

@@ -101,6 +101,7 @@
 
 
 .search-button-row {
 .search-button-row {
   padding-top: 20px;
   padding-top: 20px;
+  line-height: 2.5rem;
   button, a {
   button, a {
     margin-right: 10px;
     margin-right: 10px;
   }
   }