浏览代码

Annotations: Annotation list style improvements (#16541)

moved page-action-bar to top and put header inside it, removed </input> to be able to run prettier
Patrick O'Carroll 6 年之前
父节点
当前提交
23535c2bb2

+ 143 - 104
public/app/features/annotations/partials/editor.html

@@ -1,113 +1,152 @@
-
 <div ng-controller="AnnotationsEditorCtrl">
-	<h3 class="dashboard-settings__header">
-		<a ng-click="ctrl.backToList()">Annotations</a>
-		<span ng-show="ctrl.mode === 'new'">&gt; New</span>
-		<span ng-show="ctrl.mode === 'edit'">&gt; Edit</span>
-	</h3>
+  <div class="page-action-bar">
+    <h3 class="dashboard-settings__header">
+      <a ng-click="ctrl.backToList()">Annotations</a>
+      <span ng-show="ctrl.mode === 'new'">&gt; New</span>
+      <span ng-show="ctrl.mode === 'edit'">&gt; Edit</span>
+    </h3>
+
+    <div class="page-action-bar__spacer"></div>
 
-	<div ng-if="ctrl.mode === 'list'">
-		<div class="page-action-bar" ng-if="ctrl.annotations.length > 1">
-			<div class="page-action-bar__spacer"></div>
-			<a type="button" class="btn btn-primary" ng-click="ctrl.setupNew();"><i class="fa fa-plus" ></i> New</a>
-		</div>
+    <a
+      type="button"
+      class="btn btn-primary"
+      ng-click="ctrl.setupNew();"
+      ng-if="ctrl.annotations.length > 1"
+      ng-hide="ctrl.mode === 'edit' || ctrl.mode === 'new'"
+      ><i class="fa fa-plus"></i> New</a
+    >
+  </div>
 
-		<table class="filter-table filter-table--hover">
-			<thead>
-				<tr>
-					<th>Query name</th>
-					<th>Data source</th>
-					<th colspan="3"></th>
-				</tr>
-			</thead>
-			<tbody>
-				<tr ng-repeat="annotation in ctrl.annotations track by annotation.name">
-					<td style="width:90%" ng-hide="annotation.builtIn" class="pointer" ng-click="ctrl.edit(annotation)">
-						<i class="fa fa-comment" style="color:{{annotation.iconColor}}"></i> &nbsp;
-						{{annotation.name}}
-					</td>
-					<td style="width:90%" ng-show="annotation.builtIn" class="pointer" ng-click="ctrl.edit(annotation)">
-						<i class="gicon gicon-annotation"></i> &nbsp;
-						<em class="muted">{{annotation.name}} (Built-in)</em>
-					</td>
-					<td class="pointer" ng-click="ctrl.edit(annotation)">
-						{{annotation.datasource || 'Default'}}
-					</td>
-					<td style="width: 1%"><i ng-click="ctrl.move($index,-1)" ng-hide="$first" class="pointer fa fa-arrow-up"></i></td>
-					<td style="width: 1%"><i ng-click="ctrl.move($index,1)" ng-hide="$last" class="pointer fa fa-arrow-down"></i></td>
-					<td style="width: 1%">
-						<a ng-click="ctrl.removeAnnotation(annotation)" class="btn btn-danger btn-small" ng-hide="annotation.builtIn">
-							<i class="fa fa-remove"></i>
-						</a>
-					</td>
-				</tr>
-			</tbody>
-		</table>
+  <div ng-if="ctrl.mode === 'list'">
+    <table class="filter-table filter-table--hover">
+      <thead>
+        <tr>
+          <th>Query name</th>
+          <th>Data source</th>
+          <th colspan="3"></th>
+        </tr>
+      </thead>
+      <tbody>
+        <tr ng-repeat="annotation in ctrl.annotations track by annotation.name">
+          <td style="width:90%" ng-hide="annotation.builtIn" class="pointer" ng-click="ctrl.edit(annotation)">
+            <i class="fa fa-comment" style="color:{{ annotation.iconColor }}"></i> &nbsp;
+            {{ annotation.name }}
+          </td>
+          <td style="width:90%" ng-show="annotation.builtIn" class="pointer" ng-click="ctrl.edit(annotation)">
+            <i class="gicon gicon-annotation"></i> &nbsp;
+            <em class="muted">{{ annotation.name }} (Built-in)</em>
+          </td>
+          <td class="pointer" ng-click="ctrl.edit(annotation)">
+            {{ annotation.datasource || 'Default' }}
+          </td>
+          <td style="width: 1%">
+            <i ng-click="ctrl.move($index,-1)" ng-hide="$first" class="pointer fa fa-arrow-up"></i>
+          </td>
+          <td style="width: 1%">
+            <i ng-click="ctrl.move($index,1)" ng-hide="$last" class="pointer fa fa-arrow-down"></i>
+          </td>
+          <td style="width: 1%">
+            <a
+              ng-click="ctrl.removeAnnotation(annotation)"
+              class="btn btn-danger btn-small"
+              ng-hide="annotation.builtIn"
+            >
+              <i class="fa fa-remove"></i>
+            </a>
+          </td>
+        </tr>
+      </tbody>
+    </table>
 
-		<!-- empty list cta, there is always one built in query -->
-		<div ng-if="ctrl.annotations.length === 1" class="p-t-2">
-			<div class="empty-list-cta">
-				<div class="empty-list-cta__title">There are no custom annotation queries added yet</div>
-				<a ng-click="ctrl.setupNew()" class="empty-list-cta__button btn btn-large btn-primary">
-					<i class="gicon gicon-annotation"></i>
-					Add Annotation Query
-				</a>
-				<div class="grafana-info-box">
-					<h5>What are Annotations?</h5>
-					<p>
-					Annotations provide a way to integrate event data into your graphs. They are visualized as vertical lines and icons
-					on all graph panels. When you hover over an annotation icon you can get event text &amp; tags for the event. You can add annotation events
-					directly from grafana by holding CTRL or CMD + click on graph (or drag region). These will be stored in Grafana's annotation database.
-					</p>
-					Checkout the <a class="external-link" target="_blank" href="http://docs.grafana.org/reference/annotations/">Annotations documentation</a> for more information.
-				</div>
-			</div>
-		</div>
-	</div>
+    <!-- empty list cta, there is always one built in query -->
+    <div ng-if="ctrl.annotations.length === 1" class="p-t-2">
+      <div class="empty-list-cta">
+        <div class="empty-list-cta__title">There are no custom annotation queries added yet</div>
+        <a ng-click="ctrl.setupNew()" class="empty-list-cta__button btn btn-large btn-primary">
+          <i class="gicon gicon-annotation"></i>
+          Add Annotation Query
+        </a>
+        <div class="grafana-info-box">
+          <h5>What are Annotations?</h5>
+          <p>
+            Annotations provide a way to integrate event data into your graphs. They are visualized as vertical lines
+            and icons on all graph panels. When you hover over an annotation icon you can get event text &amp; tags for
+            the event. You can add annotation events directly from grafana by holding CTRL or CMD + click on graph (or
+            drag region). These will be stored in Grafana's annotation database.
+          </p>
+          Checkout the
+          <a class="external-link" target="_blank" href="http://docs.grafana.org/reference/annotations/"
+            >Annotations documentation</a
+          >
+          for more information.
+        </div>
+      </div>
+    </div>
+  </div>
 
-	<div class="annotations-basic-settings" ng-if="ctrl.mode === 'edit' || ctrl.mode === 'new'">
-		<div class="gf-form-group">
-			<h5 class="section-heading">General</h5>
-			<div class="gf-form-inline">
-				<div class="gf-form">
-					<span class="gf-form-label width-7">Name</span>
-					<input type="text" class="gf-form-input width-20" ng-model='ctrl.currentAnnotation.name' placeholder="name"></input>
-				</div>
-				<div class="gf-form">
-					<span class="gf-form-label width-7">Data source</span>
-					<div class="gf-form-select-wrapper">
-						<select class="gf-form-input" ng-model="ctrl.currentAnnotation.datasource" ng-options="f.name as f.name for f in ctrl.datasources" ng-change="ctrl.datasourceChanged()"></select>
-					</div>
-				</div>
-			</div>
-		</div>
+  <div class="annotations-basic-settings" ng-if="ctrl.mode === 'edit' || ctrl.mode === 'new'">
+    <div class="gf-form-group">
+      <h5 class="section-heading">General</h5>
+      <div class="gf-form-inline">
+        <div class="gf-form">
+          <span class="gf-form-label width-7">Name</span>
+          <input type="text" class="gf-form-input width-20" ng-model="ctrl.currentAnnotation.name" placeholder="name" />
+        </div>
+        <div class="gf-form">
+          <span class="gf-form-label width-7">Data source</span>
+          <div class="gf-form-select-wrapper">
+            <select
+              class="gf-form-input"
+              ng-model="ctrl.currentAnnotation.datasource"
+              ng-options="f.name as f.name for f in ctrl.datasources"
+              ng-change="ctrl.datasourceChanged()"
+            ></select>
+          </div>
+        </div>
+      </div>
+    </div>
 
-		<div class="gf-form-group">
-			<div class="gf-form-inline">
-				<gf-form-switch class="gf-form" label="Enabled" checked="ctrl.currentAnnotation.enable" label-class="width-7">
-				</gf-form-switch>
-				<gf-form-switch class="gf-form" label="Hidden" tooltip="Hides the annotation query toggle from showing at the top of the dashboard" checked="ctrl.currentAnnotation.hide" label-class="width-7">
-				</gf-form-switch>
-				<div class="gf-form">
-					<label class="gf-form-label width-9">Color</label>
-					<span class="gf-form-label">
-						<color-picker color="ctrl.currentAnnotation.iconColor" onChange="ctrl.onColorChange"></color-picker>
-					</span>
-				</div>
-			</div>
-		</div>
+    <div class="gf-form-group">
+      <div class="gf-form-inline">
+        <gf-form-switch class="gf-form" label="Enabled" checked="ctrl.currentAnnotation.enable" label-class="width-7">
+        </gf-form-switch>
+        <gf-form-switch
+          class="gf-form"
+          label="Hidden"
+          tooltip="Hides the annotation query toggle from showing at the top of the dashboard"
+          checked="ctrl.currentAnnotation.hide"
+          label-class="width-7"
+        >
+        </gf-form-switch>
+        <div class="gf-form">
+          <label class="gf-form-label width-9">Color</label>
+          <span class="gf-form-label">
+            <color-picker color="ctrl.currentAnnotation.iconColor" onChange="ctrl.onColorChange"></color-picker>
+          </span>
+        </div>
+      </div>
+    </div>
 
-		<h5 class="section-heading">Query</h5>
-		<rebuild-on-change property="ctrl.currentDatasource">
-			<plugin-component type="annotations-query-ctrl">
-			</plugin-component>
-		</rebuild-on-change>
+    <h5 class="section-heading">Query</h5>
+    <rebuild-on-change property="ctrl.currentDatasource">
+      <plugin-component type="annotations-query-ctrl"> </plugin-component>
+    </rebuild-on-change>
 
-		<div class="gf-form">
-			<div class="gf-form-button-row p-y-0">
-				<button ng-show="ctrl.mode === 'new'" type="button" class="btn gf-form-button btn-primary" ng-click="ctrl.add()">Add</button>
-				<button ng-show="ctrl.mode === 'edit'" type="button" class="btn btn-primary pull-left" ng-click="ctrl.update()">Update</button>
-			</div>
-		</div>
-	</div>
+    <div class="gf-form">
+      <div class="gf-form-button-row p-y-0">
+        <button
+          ng-show="ctrl.mode === 'new'"
+          type="button"
+          class="btn gf-form-button btn-primary"
+          ng-click="ctrl.add()"
+        >
+          Add
+        </button>
+        <button ng-show="ctrl.mode === 'edit'" type="button" class="btn btn-primary pull-left" ng-click="ctrl.update()">
+          Update
+        </button>
+      </div>
+    </div>
+  </div>
 </div>

+ 86 - 28
public/app/features/dashboard/components/DashLinks/editor.html

@@ -1,8 +1,21 @@
-<h3 class="dashboard-settings__header">
-  <a ng-click="ctrl.backToList()">Dashboard Links</a>
-  <span ng-show="ctrl.mode === 'new'">&gt; New</span>
-  <span ng-show="ctrl.mode === 'edit'">&gt; Edit</span>
-</h3>
+<div class="page-action-bar">
+  <h3 class="dashboard-settings__header">
+    <a ng-click="ctrl.backToList()">Dashboard Links</a>
+    <span ng-show="ctrl.mode === 'new'">&gt; New</span>
+    <span ng-show="ctrl.mode === 'edit'">&gt; Edit</span>
+  </h3>
+
+  <div class="page-action-bar__spacer"></div>
+  <a
+    type="button"
+    class="btn btn-primary"
+    ng-click="ctrl.setupNew()"
+    ng-if="ctrl.dashboard.links.length > 0"
+    ng-hide="ctrl.mode === 'edit' || ctrl.mode === 'new'"
+  >
+    <i class="fa fa-plus"></i> New</a
+  >
+</div>
 
 <div ng-if="ctrl.mode == 'list'">
   <div ng-if="ctrl.dashboard.links.length === 0">
@@ -17,18 +30,14 @@
       <div class="grafana-info-box">
         <h5>What are Dashboard Links?</h5>
         <p>
-					Dashboard Links allow you to place links to other dashboards and web sites directly in below the dashboard header.
+          Dashboard Links allow you to place links to other dashboards and web sites directly in below the dashboard
+          header.
         </p>
       </div>
     </div>
   </div>
 
   <div ng-if="ctrl.dashboard.links.length > 0">
-    <div class="page-action-bar">
-      <div class="page-action-bar__spacer"></div>
-      <a type="button" class="btn btn-primary" ng-click="ctrl.setupNew()">
-        <i class="fa fa-plus"></i> New</a>
-    </div>
     <table class="filter-table filter-table--hover">
       <thead>
         <tr>
@@ -41,17 +50,23 @@
         <tr ng-repeat="link in ctrl.dashboard.links">
           <td class="pointer" ng-click="ctrl.editLink(link)">
             <i class="fa fa-fw fa-external-link"></i>
-            {{link.type}}
+            {{ link.type }}
           </td>
           <td>
             <div ng-if="link.title">
-              {{link.title}}
+              {{ link.title }}
             </div>
             <div ng-if="!link.title && link.url">
-              {{link.url}}
+              {{ link.url }}
             </div>
-            <span ng-if="!link.title && link.tags" ng-repeat="tag in link.tags" tag-color-from-name="tag" class="label label-tag" style="margin-right: 6px">
-              {{tag}}
+            <span
+              ng-if="!link.title && link.tags"
+              ng-repeat="tag in link.tags"
+              tag-color-from-name="tag"
+              class="label label-tag"
+              style="margin-right: 6px"
+            >
+              {{ tag }}
             </span>
           </td>
           <td style="width: 1%">
@@ -77,41 +92,66 @@
       <div class="gf-form">
         <span class="gf-form-label width-8">Type</span>
         <div class="gf-form-select-wrapper width-10">
-          <select class="gf-form-input" ng-model="ctrl.link.type" ng-options="f for f in ['dashboards','link']"></select>
+          <select
+            class="gf-form-input"
+            ng-model="ctrl.link.type"
+            ng-options="f for f in ['dashboards','link']"
+          ></select>
         </div>
       </div>
 
       <div class="gf-form" ng-show="ctrl.link.type === 'dashboards'">
         <span class="gf-form-label width-8">With tags</span>
-        <bootstrap-tagsinput ng-model="ctrl.link.tags" tagclass="label label-tag" placeholder="add tags" style="margin-right: .25rem"></bootstrap-tagsinput>
+        <bootstrap-tagsinput
+          ng-model="ctrl.link.tags"
+          tagclass="label label-tag"
+          placeholder="add tags"
+          style="margin-right: .25rem"
+        ></bootstrap-tagsinput>
       </div>
 
-      <gf-form-switch ng-show="ctrl.link.type === 'dashboards'" class="gf-form" label="As dropdown" checked="ctrl.link.asDropdown"
-        switch-class="max-width-4" label-class="width-8"></gf-form-switch>
+      <gf-form-switch
+        ng-show="ctrl.link.type === 'dashboards'"
+        class="gf-form"
+        label="As dropdown"
+        checked="ctrl.link.asDropdown"
+        switch-class="max-width-4"
+        label-class="width-8"
+      ></gf-form-switch>
       <div class="gf-form" ng-show="ctrl.link.type === 'dashboards' && ctrl.link.asDropdown">
         <span class="gf-form-label width-8">Title</span>
-        <input type="text" ng-model="ctrl.link.title" class="gf-form-input max-width-10" ng-model-onblur>
+        <input type="text" ng-model="ctrl.link.title" class="gf-form-input max-width-10" ng-model-onblur />
       </div>
       <div ng-show="ctrl.link.type === 'link'">
         <div class="gf-form">
           <li class="gf-form-label width-8">Url</li>
-          <input type="text" ng-model="ctrl.link.url" class="gf-form-input width-20" ng-model-onblur>
+          <input type="text" ng-model="ctrl.link.url" class="gf-form-input width-20" ng-model-onblur />
         </div>
 
         <div class="gf-form">
           <span class="gf-form-label width-8">Title</span>
-          <input type="text" ng-model="ctrl.link.title" class="gf-form-input width-20" ng-model-onblur>
+          <input type="text" ng-model="ctrl.link.title" class="gf-form-input width-20" ng-model-onblur />
         </div>
 
         <div class="gf-form">
           <span class="gf-form-label width-8">Tooltip</span>
-          <input type="text" ng-model="ctrl.link.tooltip" class="gf-form-input width-20" placeholder="Open dashboard" ng-model-onblur>
+          <input
+            type="text"
+            ng-model="ctrl.link.tooltip"
+            class="gf-form-input width-20"
+            placeholder="Open dashboard"
+            ng-model-onblur
+          />
         </div>
 
         <div class="gf-form">
           <span class="gf-form-label width-8">Icon</span>
           <div class="gf-form-select-wrapper width-20">
-            <select class="gf-form-input" ng-model="ctrl.link.icon" ng-options="k as k for (k, v) in ctrl.iconMap"></select>
+            <select
+              class="gf-form-input"
+              ng-model="ctrl.link.icon"
+              ng-options="k as k for (k, v) in ctrl.iconMap"
+            ></select>
           </div>
         </div>
       </div>
@@ -120,9 +160,27 @@
     <div class="gf-form-group">
       <h5 class="section-heading">Include</h5>
       <div>
-        <gf-form-switch class="gf-form" label="Time range" checked="ctrl.link.keepTime" switch-class="max-width-6" label-class="width-9"></gf-form-switch>
-        <gf-form-switch class="gf-form" label="Variable values" checked="ctrl.link.includeVars" switch-class="max-width-6" label-class="width-9"></gf-form-switch>
-        <gf-form-switch class="gf-form" label="Open in new tab" checked="ctrl.link.targetBlank" switch-class="max-width-6" label-class="width-9"></gf-form-switch>
+        <gf-form-switch
+          class="gf-form"
+          label="Time range"
+          checked="ctrl.link.keepTime"
+          switch-class="max-width-6"
+          label-class="width-9"
+        ></gf-form-switch>
+        <gf-form-switch
+          class="gf-form"
+          label="Variable values"
+          checked="ctrl.link.includeVars"
+          switch-class="max-width-6"
+          label-class="width-9"
+        ></gf-form-switch>
+        <gf-form-switch
+          class="gf-form"
+          label="Open in new tab"
+          checked="ctrl.link.targetBlank"
+          switch-class="max-width-6"
+          label-class="width-9"
+        ></gf-form-switch>
       </div>
     </div>
   </div>

+ 446 - 324
public/app/features/templating/partials/editor.html

@@ -1,325 +1,447 @@
 <div ng-controller="VariableEditorCtrl" ng-init="init()">
-
-	<h3 class="dashboard-settings__header">
-		<a ng-click="setMode('list')">Variables</a>
-		<span ng-show="mode === 'new'">&gt; New</span>
-		<span ng-show="mode === 'edit'">&gt; Edit</span>
-	</h3>
-
-	<div ng-if="mode === 'list'">
-
-		<div ng-if="variables.length === 0">
-			<div class="empty-list-cta">
-				<div class="empty-list-cta__title">There are no variables added yet</div>
-				<a ng-click="setMode('new')" class="empty-list-cta__button btn btn-large btn-primary">
-					<i class="gicon gicon-variable"></i>
-					Add variable
-				</a>
-				<div class="grafana-info-box">
-					<h5>What do variables do?</h5>
-					<p>Variables enable more interactive and dynamic dashboards. Instead of hard-coding things like server or sensor
-						names
-						in your metric queries you can use variables in their place. Variables are shown as dropdown select boxes at the
-						top of
-						the dashboard. These dropdowns make it easy to change the data being displayed in your dashboard.
-
-						Check out the
-						<a class="external-link" href="http://docs.grafana.org/reference/templating/" target="_blank">
-							Templating documentation
-						</a> for more information.
-				</div>
-			</div>
-		</div>
-
-		<div ng-if="variables.length">
-			<div class="page-action-bar">
-				<div class="page-action-bar__spacer"></div>
-				<a type="button" class="btn btn-primary" ng-click="setMode('new');"><i class="fa fa-plus"></i> New</a>
-			</div>
-
-			<table class="filter-table filter-table--hover">
-				<thead>
-					<tr>
-						<th>Variable</th>
-						<th>Definition</th>
-						<th colspan="5"></th>
-					</tr>
-				</thead>
-				<tbody>
-					<tr ng-repeat="variable in variables">
-						<td style="width: 1%">
-							<span ng-click="edit(variable)" class="pointer template-variable">
-								${{variable.name}}
-							</span>
-						</td>
-						<td style="max-width: 200px;" ng-click="edit(variable)" class="pointer max-width">
-							{{variable.definition ? variable.definition : variable.query}}
-						</td>
-						<td style="width: 1%"><i ng-click="_.move(variables,$index,$index-1)" ng-hide="$first" class="pointer fa fa-arrow-up"></i></td>
-						<td style="width: 1%"><i ng-click="_.move(variables,$index,$index+1)" ng-hide="$last" class="pointer fa fa-arrow-down"></i></td>
-						<td style="width: 1%">
-							<a ng-click="duplicate(variable)" class="btn btn-inverse btn-small">
-								Duplicate
-							</a>
-						</td>
-						<td style="width: 1%">
-							<a ng-click="removeVariable(variable)" class="btn btn-danger btn-small">
-								<i class="fa fa-remove"></i>
-							</a>
-						</td>
-					</tr>
-				</tbody>
-			</table>
-		</div>
-	</div>
-
-	<form ng-if="mode === 'edit' || mode === 'new'" name="ctrl.form">
-		<h5 class="section-heading">General</h5>
-		<div class="gf-form-group">
-			<div class="gf-form-inline">
-				<div class="gf-form max-width-19">
-					<span class="gf-form-label width-6">Name</span>
-					<input type="text" class="gf-form-input" name="name" placeholder="name" ng-model='current.name' required
-					 ng-pattern="namePattern"></input>
-				</div>
-				<div class="gf-form max-width-19">
-					<span class="gf-form-label width-6">
-						Type
-						<info-popover mode="right-normal">
-							{{variableTypes[current.type].description}}
-						</info-popover>
-					</span>
-					<div class="gf-form-select-wrapper max-width-17">
-						<select class="gf-form-input" ng-model="current.type" ng-options="k as v.name for (k, v) in variableTypes"
-						 ng-change="typeChanged()"></select>
-					</div>
-				</div>
-			</div>
-
-			<div class="gf-form" ng-show="ctrl.form.name.$error.pattern">
-				<span class="gf-form-label gf-form-label--error">Template names cannot begin with '__', that's reserved for
-					Grafana's global variables</span>
-			</div>
-
-			<div class="gf-form-inline">
-				<div class="gf-form max-width-19">
-					<span class="gf-form-label width-6">Label</span>
-					<input type="text" class="gf-form-input" ng-model='current.label' placeholder="optional display name"></input>
-				</div>
-				<div class="gf-form max-width-19">
-					<span class="gf-form-label width-6">Hide</span>
-					<div class="gf-form-select-wrapper max-width-15">
-						<select class="gf-form-input" ng-model="current.hide" ng-options="f.value as f.text for f in hideOptions"></select>
-					</div>
-				</div>
-			</div>
-		</div>
-
-		<div ng-if="current.type === 'interval'" class="gf-form-group">
-			<h5 class="section-heading">Interval Options</h5>
-
-			<div class="gf-form">
-				<span class="gf-form-label width-9">Values</span>
-				<input type="text" class="gf-form-input" ng-model='current.query' placeholder="1m,10m,1h,6h,1d,7d" ng-model-onblur
-				 ng-change="runQuery()" required></input>
-			</div>
-
-			<div class="gf-form-inline">
-				<gf-form-switch class="gf-form" label="Auto Option" label-class="width-9" checked="current.auto" on-change="runQuery()">
-				</gf-form-switch>
-
-				<div class="gf-form">
-					<span class="gf-form-label width-9" ng-show="current.auto">
-						Step count <tip>How many times should the current time range be divided to calculate the value</tip>
-					</span>
-					<div class="gf-form-select-wrapper max-width-10" ng-show="current.auto">
-						<select class="gf-form-input" ng-model="current.auto_count" ng-options="f for f in [1,2,3,4,5,10,20,30,40,50,100,200,300,400,500]"
-						 ng-change="runQuery()"></select>
-					</div>
-				</div>
-				<div class="gf-form">
-					<span class="gf-form-label" ng-show="current.auto">
-						Min interval <tip>The calculated value will not go below this threshold</tip>
-					</span>
-					<input type="text" class="gf-form-input max-width-10" ng-show="current.auto" ng-model="current.auto_min" ng-change="runQuery()"
-					 placeholder="10s"></input>
-				</div>
-			</div>
-		</div>
-
-		<div ng-if="current.type === 'custom'" class="gf-form-group">
-			<h5 class="section-heading">Custom Options</h5>
-			<div class="gf-form">
-				<span class="gf-form-label width-14">Values separated by comma</span>
-				<input type="text" class="gf-form-input" ng-model='current.query' ng-blur="runQuery()" placeholder="1, 10, 20, myvalue, escaped\,value"
-				 required></input>
-			</div>
-		</div>
-
-		<div ng-if="current.type === 'constant'" class="gf-form-group">
-			<h5 class="section-heading">Constant options</h5>
-			<div class="gf-form">
-				<span class="gf-form-label">Value</span>
-				<input type="text" class="gf-form-input" ng-model='current.query' ng-blur="runQuery()" placeholder="your metric prefix"></input>
-			</div>
-		</div>
-
-		<div ng-if="current.type === 'textbox'" class="gf-form-group">
-			<h5 class="section-heading">Text options</h5>
-			<div class="gf-form">
-				<span class="gf-form-label">Default value</span>
-				<input type="text" class="gf-form-input" ng-model='current.query' ng-blur="runQuery()" placeholder="default value, if any"></input>
-			</div>
-		</div>
-
-		<div ng-if="current.type === 'query'" class="gf-form-group">
-			<h5 class="section-heading">Query Options</h5>
-
-			<div class="gf-form-inline">
-				<div class="gf-form max-width-21">
-					<span class="gf-form-label width-10">Data source</span>
-					<div class="gf-form-select-wrapper max-width-14">
-						<select class="gf-form-input" ng-model="current.datasource" ng-options="f.value as f.name for f in datasources"
-						 ng-change="datasourceChanged()" required>
-							<option value="" ng-if="false"></option>
-						</select>
-					</div>
-				</div>
-
-				<div class="gf-form max-width-22">
-					<span class="gf-form-label width-10">
-						Refresh
-						<info-popover mode="right-normal">
-							When to update the values of this variable.
-						</info-popover>
-					</span>
-					<div class="gf-form-select-wrapper width-15">
-						<select class="gf-form-input" ng-model="current.refresh" ng-options="f.value as f.text for f in refreshOptions"></select>
-					</div>
-				</div>
-			</div>
-
-			<rebuild-on-change property="currentDatasource">
-				<variable-query-editor-loader>
-				</variable-query-editor-loader>
-			</rebuild-on-change>
-
-			<div class="gf-form">
-				<span class="gf-form-label width-10">
-					Regex
-					<info-popover mode="right-normal">
-						Optional, if you want to extract part of a series name or metric node segment.
-					</info-popover>
-				</span>
-				<input type="text" class="gf-form-input" ng-model='current.regex' placeholder="/.*-(.*)-.*/" ng-model-onblur
-				 ng-change="runQuery()"></input>
-			</div>
-			<div class="gf-form max-width-21">
-				<span class="gf-form-label width-10">
-					Sort
-					<info-popover mode="right-normal">
-						How to sort the values of this variable.
-					</info-popover>
-				</span>
-				<div class="gf-form-select-wrapper max-width-14">
-					<select class="gf-form-input" ng-model="current.sort" ng-options="f.value as f.text for f in sortOptions"
-					 ng-change="runQuery()"></select>
-				</div>
-			</div>
-		</div>
-
-		<div ng-show="current.type === 'datasource'" class="gf-form-group">
-			<h5 class="section-heading">Data source options</h5>
-
-			<div class="gf-form">
-				<label class="gf-form-label width-12">Type</label>
-				<div class="gf-form-select-wrapper max-width-18">
-					<select class="gf-form-input" ng-model="current.query" ng-options="f.value as f.text for f in datasourceTypes"
-					 ng-change="runQuery()"></select>
-				</div>
-			</div>
-
-			<div class="gf-form">
-				<label class="gf-form-label width-12">
-					Instance name filter
-					<info-popover mode="right-normal">
-						Regex filter for which data source instances to choose from in
-						the variable value dropdown. Leave empty for all.
-						<br><br>
-						Example: <code>/^prod/</code>
-
-					</info-popover>
-				</label>
-				<input type="text" class="gf-form-input max-width-18" ng-model='current.regex' placeholder="/.*-(.*)-.*/"
-				 ng-model-onblur ng-change="runQuery()"></input>
-			</div>
-		</div>
-
-		<div ng-if="current.type === 'adhoc'" class="gf-form-group">
-			<h5 class="section-heading">Options</h5>
-			<div class="gf-form max-width-21">
-				<span class="gf-form-label width-8">Data source</span>
-				<div class="gf-form-select-wrapper max-width-14">
-					<select class="gf-form-input" ng-model="current.datasource" ng-options="f.value as f.name for f in datasources"
-					 required ng-change="validate()">
-						<option value="" ng-if="false"></option>
-					</select>
-				</div>
-			</div>
-		</div>
-
-		<div class="section gf-form-group" ng-show="variableTypes[current.type].supportsMulti">
-			<h5 class="section-heading">Selection Options</h5>
-			<div class="section">
-				<gf-form-switch class="gf-form" label="Multi-value" label-class="width-10" tooltip="Enables multiple values to be selected at the same time"
-				 checked="current.multi" on-change="runQuery()">
-				</gf-form-switch>
-				<gf-form-switch class="gf-form" label="Include All option" label-class="width-10" checked="current.includeAll"
-				 on-change="runQuery()">
-				</gf-form-switch>
-			</div>
-			<div class="gf-form" ng-if="current.includeAll">
-				<span class="gf-form-label width-10">Custom all value</span>
-				<input type="text" class="gf-form-input max-width-15" ng-model='current.allValue' placeholder="blank = auto"></input>
-			</div>
-		</div>
-
-		<div class="gf-form-group" ng-if="current.type === 'query'">
-			<h5>Value groups/tags (Experimental feature)</h5>
-			<gf-form-switch class="gf-form" label="Enabled" label-class="width-10" checked="current.useTags" on-change="runQuery()">
-			</gf-form-switch>
-			<div class="gf-form last" ng-if="current.useTags">
-				<span class="gf-form-label width-10">Tags query</span>
-				<input type="text" class="gf-form-input" ng-model='current.tagsQuery' placeholder="metric name or tags query"
-				 ng-model-onblur></input>
-			</div>
-			<div class="gf-form" ng-if="current.useTags">
-				<li class="gf-form-label width-10">Tag values query</li>
-				<input type="text" class="gf-form-input" ng-model='current.tagValuesQuery' placeholder="apps.$tag.*"
-				 ng-model-onblur></input>
-			</div>
-		</div>
-
-		<div class="gf-form-group" ng-show="current.options.length">
-			<h5>Preview of values</h5>
-			<div class="gf-form-inline">
-				<div class="gf-form" ng-repeat="option in current.options | limitTo: optionsLimit">
-					<span class="gf-form-label">{{option.text}}</span>
-				</div>
-				<div class="gf-form" ng-if="current.options.length > optionsLimit">
-					<a class="gf-form-label btn-secondary" ng-click="showMoreOptions()">Show more</a>
-				</div>
-			</div>
-		</div>
-
-		<div class="alert alert-info gf-form-group" ng-if="infoText">
-			{{infoText}}
-		</div>
-
-		<div class="gf-form-button-row p-y-0">
-			<button type="submit" class="btn btn-primary" ng-show="mode === 'edit'" ng-click="update();">Update</button>
-			<button type="submit" class="btn btn-primary" ng-show="mode === 'new'" ng-click="add();">Add</button>
-		</div>
-
-	</form>
-</div>
+  <div class="page-action-bar">
+    <h3 class="dashboard-settings__header">
+      <a ng-click="setMode('list')">Variables</a>
+      <span ng-show="mode === 'new'">&gt; New</span>
+      <span ng-show="mode === 'edit'">&gt; Edit</span>
+    </h3>
+
+    <div class="page-action-bar__spacer"></div>
+    <a
+      type="button"
+      class="btn btn-primary"
+      ng-click="setMode('new');"
+      ng-if="variables.length > 0"
+      ng-hide="mode === 'edit' || mode === 'new'"
+      ><i class="fa fa-plus"></i> New</a
+    >
+  </div>
+
+  <div ng-if="mode === 'list'">
+    <div ng-if="variables.length === 0">
+      <div class="empty-list-cta">
+        <div class="empty-list-cta__title">There are no variables added yet</div>
+        <a ng-click="setMode('new')" class="empty-list-cta__button btn btn-large btn-primary">
+          <i class="gicon gicon-variable"></i>
+          Add variable
+        </a>
+        <div class="grafana-info-box">
+          <h5>What do variables do?</h5>
+          <p>
+            Variables enable more interactive and dynamic dashboards. Instead of hard-coding things like server or
+            sensor names in your metric queries you can use variables in their place. Variables are shown as dropdown
+            select boxes at the top of the dashboard. These dropdowns make it easy to change the data being displayed in
+            your dashboard. Check out the
+            <a class="external-link" href="http://docs.grafana.org/reference/templating/" target="_blank">
+              Templating documentation
+            </a>
+            for more information.
+          </p>
+        </div>
+      </div>
+    </div>
+
+    <div ng-if="variables.length">
+      <table class="filter-table filter-table--hover">
+        <thead>
+          <tr>
+            <th>Variable</th>
+            <th>Definition</th>
+            <th colspan="5"></th>
+          </tr>
+        </thead>
+        <tbody>
+          <tr ng-repeat="variable in variables">
+            <td style="width: 1%">
+              <span ng-click="edit(variable)" class="pointer template-variable"> ${{ variable.name }} </span>
+            </td>
+            <td style="max-width: 200px;" ng-click="edit(variable)" class="pointer max-width">
+              {{ variable.definition ? variable.definition : variable.query }}
+            </td>
+            <td style="width: 1%">
+              <i ng-click="_.move(variables,$index,$index-1)" ng-hide="$first" class="pointer fa fa-arrow-up"></i>
+            </td>
+            <td style="width: 1%">
+              <i ng-click="_.move(variables,$index,$index+1)" ng-hide="$last" class="pointer fa fa-arrow-down"></i>
+            </td>
+            <td style="width: 1%">
+              <a ng-click="duplicate(variable)" class="btn btn-inverse btn-small">
+                Duplicate
+              </a>
+            </td>
+            <td style="width: 1%">
+              <a ng-click="removeVariable(variable)" class="btn btn-danger btn-small">
+                <i class="fa fa-remove"></i>
+              </a>
+            </td>
+          </tr>
+        </tbody>
+      </table>
+    </div>
+  </div>
+
+  <form ng-if="mode === 'edit' || mode === 'new'" name="ctrl.form">
+    <h5 class="section-heading">General</h5>
+    <div class="gf-form-group">
+      <div class="gf-form-inline">
+        <div class="gf-form max-width-19">
+          <span class="gf-form-label width-6">Name</span>
+          <input
+            type="text"
+            class="gf-form-input"
+            name="name"
+            placeholder="name"
+            ng-model="current.name"
+            required
+            ng-pattern="namePattern"
+          />
+        </div>
+        <div class="gf-form max-width-19">
+          <span class="gf-form-label width-6">
+            Type
+            <info-popover mode="right-normal">
+              {{ variableTypes[current.type].description }}
+            </info-popover>
+          </span>
+          <div class="gf-form-select-wrapper max-width-17">
+            <select
+              class="gf-form-input"
+              ng-model="current.type"
+              ng-options="k as v.name for (k, v) in variableTypes"
+              ng-change="typeChanged()"
+            ></select>
+          </div>
+        </div>
+      </div>
+
+      <div class="gf-form" ng-show="ctrl.form.name.$error.pattern">
+        <span class="gf-form-label gf-form-label--error"
+          >Template names cannot begin with '__', that's reserved for Grafana's global variables</span
+        >
+      </div>
+
+      <div class="gf-form-inline">
+        <div class="gf-form max-width-19">
+          <span class="gf-form-label width-6">Label</span>
+          <input type="text" class="gf-form-input" ng-model="current.label" placeholder="optional display name" />
+        </div>
+        <div class="gf-form max-width-19">
+          <span class="gf-form-label width-6">Hide</span>
+          <div class="gf-form-select-wrapper max-width-15">
+            <select
+              class="gf-form-input"
+              ng-model="current.hide"
+              ng-options="f.value as f.text for f in hideOptions"
+            ></select>
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <div ng-if="current.type === 'interval'" class="gf-form-group">
+      <h5 class="section-heading">Interval Options</h5>
+
+      <div class="gf-form">
+        <span class="gf-form-label width-9">Values</span>
+        <input
+          type="text"
+          class="gf-form-input"
+          ng-model="current.query"
+          placeholder="1m,10m,1h,6h,1d,7d"
+          ng-model-onblur
+          ng-change="runQuery()"
+          required
+        />
+      </div>
+
+      <div class="gf-form-inline">
+        <gf-form-switch
+          class="gf-form"
+          label="Auto Option"
+          label-class="width-9"
+          checked="current.auto"
+          on-change="runQuery()"
+        >
+        </gf-form-switch>
+
+        <div class="gf-form">
+          <span class="gf-form-label width-9" ng-show="current.auto">
+            Step count <tip>How many times should the current time range be divided to calculate the value</tip>
+          </span>
+          <div class="gf-form-select-wrapper max-width-10" ng-show="current.auto">
+            <select
+              class="gf-form-input"
+              ng-model="current.auto_count"
+              ng-options="f for f in [1,2,3,4,5,10,20,30,40,50,100,200,300,400,500]"
+              ng-change="runQuery()"
+            ></select>
+          </div>
+        </div>
+        <div class="gf-form">
+          <span class="gf-form-label" ng-show="current.auto">
+            Min interval <tip>The calculated value will not go below this threshold</tip>
+          </span>
+          <input
+            type="text"
+            class="gf-form-input max-width-10"
+            ng-show="current.auto"
+            ng-model="current.auto_min"
+            ng-change="runQuery()"
+            placeholder="10s"
+          />
+        </div>
+      </div>
+    </div>
+
+    <div ng-if="current.type === 'custom'" class="gf-form-group">
+      <h5 class="section-heading">Custom Options</h5>
+      <div class="gf-form">
+        <span class="gf-form-label width-14">Values separated by comma</span>
+        <input
+          type="text"
+          class="gf-form-input"
+          ng-model="current.query"
+          ng-blur="runQuery()"
+          placeholder="1, 10, 20, myvalue, escaped\,value"
+          required
+        />
+      </div>
+    </div>
+
+    <div ng-if="current.type === 'constant'" class="gf-form-group">
+      <h5 class="section-heading">Constant options</h5>
+      <div class="gf-form">
+        <span class="gf-form-label">Value</span>
+        <input
+          type="text"
+          class="gf-form-input"
+          ng-model="current.query"
+          ng-blur="runQuery()"
+          placeholder="your metric prefix"
+        />
+      </div>
+    </div>
+
+    <div ng-if="current.type === 'textbox'" class="gf-form-group">
+      <h5 class="section-heading">Text options</h5>
+      <div class="gf-form">
+        <span class="gf-form-label">Default value</span>
+        <input
+          type="text"
+          class="gf-form-input"
+          ng-model="current.query"
+          ng-blur="runQuery()"
+          placeholder="default value, if any"
+        />
+      </div>
+    </div>
+
+    <div ng-if="current.type === 'query'" class="gf-form-group">
+      <h5 class="section-heading">Query Options</h5>
+
+      <div class="gf-form-inline">
+        <div class="gf-form max-width-21">
+          <span class="gf-form-label width-10">Data source</span>
+          <div class="gf-form-select-wrapper max-width-14">
+            <select
+              class="gf-form-input"
+              ng-model="current.datasource"
+              ng-options="f.value as f.name for f in datasources"
+              ng-change="datasourceChanged()"
+              required
+            >
+              <option value="" ng-if="false"></option>
+            </select>
+          </div>
+        </div>
+
+        <div class="gf-form max-width-22">
+          <span class="gf-form-label width-10">
+            Refresh
+            <info-popover mode="right-normal">
+              When to update the values of this variable.
+            </info-popover>
+          </span>
+          <div class="gf-form-select-wrapper width-15">
+            <select
+              class="gf-form-input"
+              ng-model="current.refresh"
+              ng-options="f.value as f.text for f in refreshOptions"
+            ></select>
+          </div>
+        </div>
+      </div>
+
+      <rebuild-on-change property="currentDatasource">
+        <variable-query-editor-loader> </variable-query-editor-loader>
+      </rebuild-on-change>
+
+      <div class="gf-form">
+        <span class="gf-form-label width-10">
+          Regex
+          <info-popover mode="right-normal">
+            Optional, if you want to extract part of a series name or metric node segment.
+          </info-popover>
+        </span>
+        <input
+          type="text"
+          class="gf-form-input"
+          ng-model="current.regex"
+          placeholder="/.*-(.*)-.*/"
+          ng-model-onblur
+          ng-change="runQuery()"
+        />
+      </div>
+      <div class="gf-form max-width-21">
+        <span class="gf-form-label width-10">
+          Sort
+          <info-popover mode="right-normal">
+            How to sort the values of this variable.
+          </info-popover>
+        </span>
+        <div class="gf-form-select-wrapper max-width-14">
+          <select
+            class="gf-form-input"
+            ng-model="current.sort"
+            ng-options="f.value as f.text for f in sortOptions"
+            ng-change="runQuery()"
+          ></select>
+        </div>
+      </div>
+    </div>
+
+    <div ng-show="current.type === 'datasource'" class="gf-form-group">
+      <h5 class="section-heading">Data source options</h5>
+
+      <div class="gf-form">
+        <label class="gf-form-label width-12">Type</label>
+        <div class="gf-form-select-wrapper max-width-18">
+          <select
+            class="gf-form-input"
+            ng-model="current.query"
+            ng-options="f.value as f.text for f in datasourceTypes"
+            ng-change="runQuery()"
+          ></select>
+        </div>
+      </div>
+
+      <div class="gf-form">
+        <label class="gf-form-label width-12">
+          Instance name filter
+          <info-popover mode="right-normal">
+            Regex filter for which data source instances to choose from in the variable value dropdown. Leave empty for
+            all.
+            <br /><br />
+            Example: <code>/^prod/</code>
+          </info-popover>
+        </label>
+        <input
+          type="text"
+          class="gf-form-input max-width-18"
+          ng-model="current.regex"
+          placeholder="/.*-(.*)-.*/"
+          ng-model-onblur
+          ng-change="runQuery()"
+        />
+      </div>
+    </div>
+
+    <div ng-if="current.type === 'adhoc'" class="gf-form-group">
+      <h5 class="section-heading">Options</h5>
+      <div class="gf-form max-width-21">
+        <span class="gf-form-label width-8">Data source</span>
+        <div class="gf-form-select-wrapper max-width-14">
+          <select
+            class="gf-form-input"
+            ng-model="current.datasource"
+            ng-options="f.value as f.name for f in datasources"
+            required
+            ng-change="validate()"
+          >
+            <option value="" ng-if="false"></option>
+          </select>
+        </div>
+      </div>
+    </div>
+
+    <div class="section gf-form-group" ng-show="variableTypes[current.type].supportsMulti">
+      <h5 class="section-heading">Selection Options</h5>
+      <div class="section">
+        <gf-form-switch
+          class="gf-form"
+          label="Multi-value"
+          label-class="width-10"
+          tooltip="Enables multiple values to be selected at the same time"
+          checked="current.multi"
+          on-change="runQuery()"
+        >
+        </gf-form-switch>
+        <gf-form-switch
+          class="gf-form"
+          label="Include All option"
+          label-class="width-10"
+          checked="current.includeAll"
+          on-change="runQuery()"
+        >
+        </gf-form-switch>
+      </div>
+      <div class="gf-form" ng-if="current.includeAll">
+        <span class="gf-form-label width-10">Custom all value</span>
+        <input type="text" class="gf-form-input max-width-15" ng-model="current.allValue" placeholder="blank = auto" />
+      </div>
+    </div>
+
+    <div class="gf-form-group" ng-if="current.type === 'query'">
+      <h5>Value groups/tags (Experimental feature)</h5>
+      <gf-form-switch
+        class="gf-form"
+        label="Enabled"
+        label-class="width-10"
+        checked="current.useTags"
+        on-change="runQuery()"
+      >
+      </gf-form-switch>
+      <div class="gf-form last" ng-if="current.useTags">
+        <span class="gf-form-label width-10">Tags query</span>
+        <input
+          type="text"
+          class="gf-form-input"
+          ng-model="current.tagsQuery"
+          placeholder="metric name or tags query"
+          ng-model-onblur
+        />
+      </div>
+      <div class="gf-form" ng-if="current.useTags">
+        <li class="gf-form-label width-10">Tag values query</li>
+        <input
+          type="text"
+          class="gf-form-input"
+          ng-model="current.tagValuesQuery"
+          placeholder="apps.$tag.*"
+          ng-model-onblur
+        />
+      </div>
+    </div>
+
+    <div class="gf-form-group" ng-show="current.options.length">
+      <h5>Preview of values</h5>
+      <div class="gf-form-inline">
+        <div class="gf-form" ng-repeat="option in current.options | limitTo: optionsLimit">
+          <span class="gf-form-label">{{ option.text }}</span>
+        </div>
+        <div class="gf-form" ng-if="current.options.length > optionsLimit">
+          <a class="gf-form-label btn-secondary" ng-click="showMoreOptions()">Show more</a>
+        </div>
+      </div>
+    </div>
+
+    <div class="alert alert-info gf-form-group" ng-if="infoText">
+      {{ infoText }}
+    </div>
+
+    <div class="gf-form-button-row p-y-0">
+      <button type="submit" class="btn btn-primary" ng-show="mode === 'edit'" ng-click="update();">Update</button>
+      <button type="submit" class="btn btn-primary" ng-show="mode === 'new'" ng-click="add();">Add</button>
+    </div>
+  </form>
+</div>