Commit fc50d995 authored by Savorboard's avatar Savorboard

add dashbaord

parent 5c6dc66c
using Microsoft.EntityFrameworkCore;
using Sample.RabbitMQ.SqlServer.Controllers;
namespace Sample.RabbitMQ.SqlServer
{
public class AppDbContext : DbContext
{
public DbSet<Person> Persons { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Server=192.168.2.206;Initial Catalog=TestCap;User Id=cmswuliu;Password=h7xY81agBn*Veiu3;MultipleActiveResultSets=True");
//optionsBuilder.UseSqlServer("Server=DESKTOP-M9R8T31;Initial Catalog=Sample.Kafka.SqlServer;User Id=sa;Password=P@ssw0rd;MultipleActiveResultSets=True");
//optionsBuilder.UseSqlServer("Server=192.168.2.206;Initial Catalog=TestCap;User Id=cmswuliu;Password=h7xY81agBn*Veiu3;MultipleActiveResultSets=True");
optionsBuilder.UseSqlServer("Server=DESKTOP-M9R8T31;Initial Catalog=Sample.Kafka.SqlServer;User Id=sa;Password=P@ssw0rd;MultipleActiveResultSets=True");
}
}
}
......@@ -2,12 +2,14 @@
using System.Diagnostics;
using System.Threading.Tasks;
using DotNetCore.CAP;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace Sample.RabbitMQ.SqlServer.Controllers
{
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
......@@ -33,12 +35,14 @@ namespace Sample.RabbitMQ.SqlServer.Controllers
[Route("~/publish")]
public IActionResult PublishMessage()
{
using(var trans = _dbContext.Database.BeginTransaction())
{
//_capBus.Publish("sample.rabbitmq.mysql22222", DateTime.Now);
_capBus.Publish("sample.rabbitmq.mysql33333", new Person { Name = "宜兴", Age = 11 });
trans.Commit();
}
var person = new Person { Name = "宜兴", Age = 11 };
_dbContext.Persons.Add(person);
_dbContext.SaveChanges();
throw new Exception();
//_capBus.Publish("sample.rabbitmq.mysql22222", DateTime.Now);
_capBus.Publish("sample.rabbitmq.mysql33333", person);
return Ok();
}
......@@ -48,7 +52,7 @@ namespace Sample.RabbitMQ.SqlServer.Controllers
using (var trans = await _dbContext.Database.BeginTransactionAsync())
{
await _capBus.PublishAsync("sample.rabbitmq.mysql", "");
trans.Commit();
}
return Ok();
......
// <auto-generated />
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.EntityFrameworkCore.Storage.Internal;
using Sample.RabbitMQ.SqlServer;
using System;
namespace Sample.RabbitMQ.SqlServer.Migrations
{
[DbContext(typeof(AppDbContext))]
[Migration("20170824130007_AddPersons")]
partial class AddPersons
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "2.0.0-rtm-26452")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
modelBuilder.Entity("Sample.RabbitMQ.SqlServer.Controllers.Person", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("Age");
b.Property<string>("Name");
b.HasKey("Id");
b.ToTable("Persons");
});
#pragma warning restore 612, 618
}
}
}
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using System;
using System.Collections.Generic;
namespace Sample.RabbitMQ.SqlServer.Migrations
{
public partial class AddPersons : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Persons",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
Age = table.Column<int>(type: "int", nullable: false),
Name = table.Column<string>(type: "nvarchar(max)", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Persons", x => x.Id);
});
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Persons");
}
}
}
// <auto-generated />
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.EntityFrameworkCore.Storage.Internal;
using Sample.RabbitMQ.SqlServer;
using System;
namespace Sample.RabbitMQ.SqlServer.Migrations
{
[DbContext(typeof(AppDbContext))]
partial class AppDbContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "2.0.0-rtm-26452")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
modelBuilder.Entity("Sample.RabbitMQ.SqlServer.Controllers.Person", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("Age");
b.Property<string>("Name");
b.HasKey("Id");
b.ToTable("Persons");
});
#pragma warning restore 612, 618
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using DotNetCore.CAP;
namespace Sample.RabbitMQ.SqlServer.Services
{
public interface ICmsService
{
void Add();
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Sample.RabbitMQ.SqlServer.Services
{
public interface IOrderService
{
void Check();
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using DotNetCore.CAP;
namespace Sample.RabbitMQ.SqlServer.Services.Impl
{
public class CmsService : ICmsService, ICapSubscribe
{
public void Add()
{
throw new NotImplementedException();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using DotNetCore.CAP;
namespace Sample.RabbitMQ.SqlServer.Services.Impl
{
public class OrderService : IOrderService, ICapSubscribe
{
public void Check()
{
throw new NotImplementedException();
}
}
}
......@@ -2,6 +2,8 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Sample.RabbitMQ.SqlServer.Services;
using Sample.RabbitMQ.SqlServer.Services.Impl;
namespace Sample.RabbitMQ.SqlServer
{
......@@ -11,14 +13,13 @@ namespace Sample.RabbitMQ.SqlServer
{
services.AddDbContext<AppDbContext>();
services.AddTransient<IOrderService, OrderService>();
services.AddTransient<ICmsService, CmsService>();
services.AddCap(x =>
{
x.UseEntityFramework<AppDbContext>();
x.UseRabbitMQ(y=> {
y.HostName = "192.168.2.206";
y.UserName = "admin";
y.Password = "123123";
});
x.UseRabbitMQ("localhost");
});
services.AddMvc();
......
This source diff could not be displayed because it is too large. You can view the blob instead.
/* Sticky footer styles
-------------------------------------------------- */
html, body {
height: 100%;
/* The html and body elements cannot have any padding or margin. */
}
body {
/* 75px to make the container go all the way to the bottom of the topbar */
padding-top: 75px;
}
/* Wrapper for page content to push down footer */
#wrap {
min-height: 100%;
height: auto !important;
height: 100%;
/* Negative indent footer by its height */
margin: 0 auto -60px;
/* Pad bottom by footer height */
padding: 0 0 60px;
}
/* Set the fixed height of the footer here */
#footer {
background-color: #f5f5f5;
}
/* Custom page CSS
-------------------------------------------------- */
.container .credit {
margin: 20px 0;
}
.page-header {
margin-top: 0;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.btn-death {
background-color: #777;
border-color: #666;
color: #fff;
}
.btn-death:hover {
background-color: #666;
border-color: #555;
color: #fff;
}
.list-group .list-group-item .glyphicon {
margin-right: 3px;
}
.breadcrumb {
margin-bottom: 10px;
background-color: inherit;
padding: 0;
}
.btn-toolbar-label {
padding: 7px 0;
vertical-align: middle;
display: inline-block;
margin-left: 5px;
}
.btn-toolbar-label-sm {
padding: 5px 0;
}
.btn-toolbar-spacer {
width: 5px;
display: inline-block;
height: 1px;
}
a:hover .label-hover {
background-color: #2a6496!important;
color: #fff!important;
}
.expander {
cursor: pointer;
}
.expandable {
display: none;
}
.table-inner {
margin-bottom: 7px;
font-size: 90%;
}
.min-width {
width: 1%;
white-space: nowrap;
}
.align-right {
text-align: right;
}
.table>tbody>tr.hover:hover>td, .table>tbody>tr.hover:hover>th {
background-color: #f9f9f9;
}
.table>tbody>tr.highlight>td, .table>tbody>tr.highlight>th {
background-color: #fcf8e3;
border-color: #fbeed5;
}
.table>tbody>tr.highlight:hover>td, .table>tbody>tr.highlight:hover>th {
background-color: #f6f2dd;
border-color: #f5e8ce;
}
.word-break {
word-break: break-all;
}
/* Statistics widget
-------------------------------------------------- */
#stats .list-group-item {
border-color: #e7e7e7;
background-color: #f8f8f8;
}
#stats a.list-group-item {
color: #777;
}
#stats a.list-group-item:hover,
#stats a.list-group-item:focus {
color: #333;
}
#stats .list-group-item.active,
#stats .list-group-item.active:hover,
#stats .list-group-item.active:focus {
color: #555;
background-color: #e7e7e7;
border-color: #e7e7e7;
}
.table td.failed-job-details {
padding-top: 0;
padding-bottom: 0;
border-top: none;
background-color: #f5f5f5;
}
.obsolete-data, .obsolete-data a, .obsolete-data pre, .obsolete-data .label {
color: #999;
}
.obsolete-data pre, .obsolete-data .label {
background-color: #f5f5f5;
}
.obsolete-data .glyphicon-question-sign {
font-size: 80%;
color: #999;
}
.stack-trace {
padding: 10px;
border: none;
}
.st-type {
font-weight: bold;
}
.st-param-name {
color: #666;
}
.st-file {
color: #999;
}
.st-method {
color: #00008B;
font-weight: bold;
}
.st-line {
color: #8B008B;
}
.width-200 {
width: 200px;
}
.btn-toolbar-top {
margin-bottom: 10px;
}
.paginator .btn {
color: #428bca;
}
.paginator .btn.active {
color: #333;
}
/* Job Snippet styles */
.job-snippet {
margin-bottom: 20px;
padding: 15px;
display: table;
width: 100%;
-ms-border-radius: 4px;
border-radius: 4px;
background-color: #f5f5f5;
}
.job-snippet > * {
display: table-cell;
vertical-align: top;
}
.job-snippet-code {
vertical-align: top;
}
.job-snippet-code pre {
border: none;
margin: 0;
background: inherit;
padding: 0;
-ms-border-radius: 0;
border-radius: 0;
font-size: 14px;
}
.job-snippet-code code {
display: block;
color: black;
}
.job-snippet-code pre .comment {
color: rgb(0, 128, 0);
}
.job-snippet-code pre .keyword {
color: rgb(0, 0, 255);
}
.job-snippet-code pre .string {
color: rgb(163, 21, 21);
}
.job-snippet-code pre .type {
color: rgb(43, 145, 175);
}
.job-snippet-code pre .xmldoc {
color: rgb(128, 128, 128);
}
.job-snippet-properties {
max-width: 200px;
padding-left: 5px;
}
.job-snippet-properties dl {
margin: 0;
}
.job-snippet-properties dl dt {
color: #999;
text-shadow: 0 1px white;
font-weight: normal;
}
.job-snippet-properties dl dd {
margin-left: 0;
margin-bottom: 5px;
}
.job-snippet-properties pre {
background-color: white;
-webkit-box-shadow: none;
-ms-box-shadow: none;
padding: 2px 4px;
border: none;
margin: 0;
}
.job-snippet-properties code {
color: black;
}
.state-card {
position: relative;
display: block;
margin-bottom: 7px;
padding: 12px;
background-color: #fff;
border: 1px solid #e5e5e5;
border-radius: 3px;
}
.state-card-title {
margin-bottom: 0;
}
.state-card-title .pull-right {
margin-top: 3px;
}
.state-card-text {
margin-top: 5px;
margin-bottom: 0;
}
.state-card h4 {
margin-top: 0;
}
.state-card-body {
padding: 10px;
margin: 10px -12px -12px -12px;
border-bottom-left-radius: 3px;
border-bottom-right-radius: 3px;
background-color: #f5f5f5;
}
.state-card-body dl {
margin-top: 5px;
margin-bottom: 0;
}
.state-card-body pre {
white-space: pre-wrap; /* CSS 3 */
word-wrap: break-word; /* Internet Explorer 5.5+ */
background: transparent;
padding: 0;
}
.state-card-body .stack-trace {
background-color: transparent;
padding: 0 20px;
margin-bottom: 0px;
}
.state-card-body .exception-type {
margin-top: 0;
}
/* Job History styles */
.job-history {
margin-bottom: 10px;
opacity: 0.8;
}
.job-history.job-history-current {
opacity: 1.0;
}
.job-history-heading {
padding: 5px 10px;
color: #666;
-ms-border-top-left-radius: 4px;
border-top-left-radius: 4px;
-ms-border-top-right-radius: 4px;
border-top-right-radius: 4px;
}
.job-history-body {
background-color: #f5f5f5;
padding: 10px;
}
.job-history-title {
margin-top: 0;
margin-bottom: 2px;
}
.job-history dl {
margin-top: 5px;
margin-bottom: 5px;
}
.job-history .stack-trace {
background-color: transparent;
padding: 0 20px;
margin-bottom: 5px;
}
.job-history .exception-type {
margin-top: 0;
}
.job-history-current .job-history-heading,
.job-history-current small {
color: white;
}
a.job-method {
color: inherit;
}
.list-group .glyphicon {
top: 2px;
}
span.metric {
display: inline-block;
min-width: 10px;
padding: 2px 6px;
font-size: 12px;
line-height: 1;
text-align: center;
white-space: nowrap;
vertical-align: baseline;
background-color: transparent;
border-radius: 10px;
border: solid 1px;
-webkit-transition: color .1s ease-out, background .1s ease-out, border .1s ease-out;
-moz-transition: color .1s ease-out, background .1s ease-out, border .1s ease-out;
-ms-transition: color .1s ease-out, background .1s ease-out, border .1s ease-out;
-o-transition: color .1s ease-out, background .1s ease-out, border .1s ease-out;
transition: color .1s ease-out, background .1s ease-out, border .1s ease-out;
}
span.metric.highlighted {
font-weight: bold;
color: #fff!important;
}
span.metric-default {
color: #777;
border-color: #777;
}
span.metric-default.highlighted {
background-color: #777;
}
div.metric {
border: solid 1px transparent;
border-radius: 4px;
-webkit-box-shadow: 0 1px 1px rgba(0,0,0,.05);
box-shadow: 0 1px 1px rgba(0,0,0,.05);
margin-bottom: 20px;
transition: color .1s ease-out, background .1s ease-out, border .1s ease-out;
}
div.metric .metric-body {
padding: 15px 15px 0;
font-size: 26px;
text-align: center;
}
div.metric .metric-description {
padding: 0 15px 15px;
text-align: center;
}
div.metric.metric-default {
border-color: #ddd;
}
div.metric-info,
span.metric-info {
color: #5bc0de;
border-color: #5bc0de;
}
span.metric-info.highlighted {
background-color: #5bc0de;
}
div.metric-warning,
span.metric-warning {
color: #f0ad4e;
border-color: #f0ad4e;
}
span.metric-warning.highlighted {
background-color: #f0ad4e;
}
div.metric-success,
span.metric-success {
color: #5cb85c;
border-color: #5cb85c;
}
span.metric-success.highlighted {
background-color: #5cb85c;
}
div.metric-danger,
span.metric-danger {
color: #d9534f;
border-color: #d9534f;
}
span.metric-danger.highlighted {
background-color: #d9534f;
}
span.metric-null,
div.metric-null {
display: none;
}
@media (min-width: 992px) {
#stats {
position: fixed;
width: 220px
}
}
@media (min-width: 1200px) {
#stats {
width: 262.5px;
}
}
.rickshaw_graph .detail{pointer-events:none;position:absolute;top:0;z-index:2;background:rgba(0,0,0,.1);bottom:0;width:1px;transition:opacity .25s linear;-moz-transition:opacity .25s linear;-o-transition:opacity .25s linear;-webkit-transition:opacity .25s linear}.rickshaw_graph .detail.inactive{opacity:0}.rickshaw_graph .detail .item.active{opacity:1}.rickshaw_graph .detail .x_label{font-family:Arial,sans-serif;border-radius:3px;padding:6px;opacity:.5;border:1px solid #e0e0e0;font-size:12px;position:absolute;background:#fff;white-space:nowrap}.rickshaw_graph .detail .item{position:absolute;z-index:2;border-radius:3px;padding:.25em;font-size:12px;font-family:Arial,sans-serif;opacity:0;background:rgba(0,0,0,.4);color:#fff;border:1px solid rgba(0,0,0,.4);margin-left:1em;margin-top:-1em;white-space:nowrap}.rickshaw_graph .detail .item.active{opacity:1;background:rgba(0,0,0,.8)}.rickshaw_graph .detail .item:before{content:"\25c2";position:absolute;left:-.5em;color:rgba(0,0,0,.7);width:0}.rickshaw_graph .detail .dot{width:4px;height:4px;margin-left:-4px;margin-top:-3px;border-radius:5px;position:absolute;box-shadow:0 0 2px rgba(0,0,0,.6);background:#fff;border-width:2px;border-style:solid;display:none;background-clip:padding-box}.rickshaw_graph .detail .dot.active{display:block}.rickshaw_graph{position:relative}.rickshaw_graph svg{display:block;overflow:hidden}.rickshaw_graph .x_tick{position:absolute;top:0;bottom:0;width:0;border-left:1px dotted rgba(0,0,0,.2);pointer-events:none}.rickshaw_graph .x_tick .title{position:absolute;font-size:12px;font-family:Arial,sans-serif;opacity:.5;white-space:nowrap;margin-left:3px;bottom:1px}.rickshaw_annotation_timeline{height:1px;border-top:1px solid #e0e0e0;margin-top:10px;position:relative}.rickshaw_annotation_timeline .annotation{position:absolute;height:6px;width:6px;margin-left:-2px;top:-3px;border-radius:5px;background-color:rgba(0,0,0,.25)}.rickshaw_graph .annotation_line{position:absolute;top:0;bottom:-6px;width:0;border-left:2px solid rgba(0,0,0,.3);display:none}.rickshaw_graph .annotation_line.active{display:block}.rickshaw_graph .annotation_range{background:rgba(0,0,0,.1);display:none;position:absolute;top:0;bottom:-6px}.rickshaw_graph .annotation_range.active{display:block}.rickshaw_graph .annotation_range.active.offscreen{display:none}.rickshaw_annotation_timeline .annotation .content{background:#fff;color:#000;opacity:.9;padding:5px;box-shadow:0 0 2px rgba(0,0,0,.8);border-radius:3px;position:relative;z-index:20;font-size:12px;padding:6px 8px 8px;top:18px;left:-11px;width:160px;display:none;cursor:pointer}.rickshaw_annotation_timeline .annotation .content:before{content:"\25b2";position:absolute;top:-11px;color:#fff;text-shadow:0 -1px 1px rgba(0,0,0,.8)}.rickshaw_annotation_timeline .annotation.active,.rickshaw_annotation_timeline .annotation:hover{background-color:rgba(0,0,0,.8);cursor:none}.rickshaw_annotation_timeline .annotation .content:hover{z-index:50}.rickshaw_annotation_timeline .annotation.active .content{display:block}.rickshaw_annotation_timeline .annotation:hover .content{display:block;z-index:50}.rickshaw_graph .y_axis,.rickshaw_graph .x_axis_d3{fill:none}.rickshaw_graph .y_ticks .tick,.rickshaw_graph .x_ticks_d3 .tick{stroke:rgba(0,0,0,.16);stroke-width:2px;shape-rendering:crisp-edges;pointer-events:none}.rickshaw_graph .y_grid .tick,.rickshaw_graph .x_grid_d3 .tick{z-index:-1;stroke:rgba(0,0,0,.2);stroke-width:1px;stroke-dasharray:1 1}.rickshaw_graph .y_grid path,.rickshaw_graph .x_grid_d3 path{fill:none;stroke:none}.rickshaw_graph .y_ticks path,.rickshaw_graph .x_ticks_d3 path{fill:none;stroke:gray}.rickshaw_graph .y_ticks text,.rickshaw_graph .x_ticks_d3 text{opacity:.5;font-size:12px;pointer-events:none}.rickshaw_graph .x_tick.glow .title,.rickshaw_graph .y_ticks.glow text{fill:#000;color:#000;text-shadow:-1px 1px 0 rgba(255,255,255,.1),1px -1px 0 rgba(255,255,255,.1),1px 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1),0 -1px 0 rgba(255,255,255,.1),1px 0 0 rgba(255,255,255,.1),-1px 0 0 rgba(255,255,255,.1),-1px -1px 0 rgba(255,255,255,.1)}.rickshaw_graph .x_tick.inverse .title,.rickshaw_graph .y_ticks.inverse text{fill:#fff;color:#fff;text-shadow:-1px 1px 0 rgba(0,0,0,.8),1px -1px 0 rgba(0,0,0,.8),1px 1px 0 rgba(0,0,0,.8),0 1px 0 rgba(0,0,0,.8),0 -1px 0 rgba(0,0,0,.8),1px 0 0 rgba(0,0,0,.8),-1px 0 0 rgba(0,0,0,.8),-1px -1px 0 rgba(0,0,0,.8)}.rickshaw_legend{font-family:Arial;font-size:12px;color:#fff;background:#404040;display:inline-block;padding:12px 5px;border-radius:2px;position:relative}.rickshaw_legend:hover{z-index:10}.rickshaw_legend .swatch{width:10px;height:10px;border:1px solid rgba(0,0,0,.2)}.rickshaw_legend .line{clear:both;line-height:140%;padding-right:15px}.rickshaw_legend .line .swatch{display:inline-block;margin-right:3px;border-radius:2px}.rickshaw_legend .label{margin:0;white-space:nowrap;display:inline;font-size:inherit;background-color:transparent;color:inherit;font-weight:400;line-height:normal;padding:0;text-shadow:none}.rickshaw_legend .action:hover{opacity:.6}.rickshaw_legend .action{margin-right:.2em;font-size:10px;opacity:.2;cursor:pointer;font-size:14px}.rickshaw_legend .line.disabled{opacity:.4}.rickshaw_legend ul{list-style-type:none;margin:0;padding:0;margin:2px;cursor:pointer}.rickshaw_legend li{padding:0 0 0 2px;min-width:80px;white-space:nowrap}.rickshaw_legend li:hover{background:rgba(255,255,255,.08);border-radius:3px}.rickshaw_legend li:active{background:rgba(255,255,255,.2);border-radius:3px}
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
using System;
using System.Collections.Generic;
using System.Text;
namespace DotNetCore.CAP.Dashboard
{
class DashboardContext
{
}
}
// This file is part of Hangfire.
// Copyright 2013-2014 Sergey Odinokov.
//
// Hangfire is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation, either version 3
// of the License, or any later version.
//
// Hangfire is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with Hangfire. If not, see <http://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using Hangfire.Storage.Monitoring;
namespace Hangfire.Storage
{
public interface IMonitoringApi
{
IList<QueueWithTopEnqueuedJobsDto> Queues();
IList<ServerDto> Servers();
JobDetailsDto JobDetails(string jobId);
StatisticsDto GetStatistics();
JobList<EnqueuedJobDto> EnqueuedJobs(string queue, int from, int perPage);
JobList<FetchedJobDto> FetchedJobs(string queue, int from, int perPage);
JobList<ProcessingJobDto> ProcessingJobs(int from, int count);
JobList<ScheduledJobDto> ScheduledJobs(int from, int count);
JobList<SucceededJobDto> SucceededJobs(int from, int count);
JobList<FailedJobDto> FailedJobs(int from, int count);
JobList<DeletedJobDto> DeletedJobs(int from, int count);
long ScheduledCount();
long EnqueuedCount(string queue);
long FetchedCount(string queue);
long FailedCount();
long ProcessingCount();
long SucceededListCount();
long DeletedListCount();
IDictionary<DateTime, long> SucceededByDatesCount();
IDictionary<DateTime, long> FailedByDatesCount();
IDictionary<DateTime, long> HourlySucceededJobs();
IDictionary<DateTime, long> HourlyFailedJobs();
}
}
\ No newline at end of file
using System;
using Hangfire.Common;
namespace Hangfire.Storage.Monitoring
{
public class DeletedJobDto
{
public DeletedJobDto()
{
InDeletedState = true;
}
public Job Job { get; set; }
public DateTime? DeletedAt { get; set; }
public bool InDeletedState { get; set; }
}
}
// This file is part of Hangfire.
// Copyright © 2013-2014 Sergey Odinokov.
//
// Hangfire is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation, either version 3
// of the License, or any later version.
//
// Hangfire is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with Hangfire. If not, see <http://www.gnu.org/licenses/>.
using System;
using Hangfire.Common;
namespace Hangfire.Storage.Monitoring
{
public class EnqueuedJobDto
{
public EnqueuedJobDto()
{
InEnqueuedState = true;
}
public Job Job { get; set; }
public string State { get; set; }
public DateTime? EnqueuedAt { get; set; }
public bool InEnqueuedState { get; set; }
}
}
\ No newline at end of file
// This file is part of Hangfire.
// Copyright © 2013-2014 Sergey Odinokov.
//
// Hangfire is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation, either version 3
// of the License, or any later version.
//
// Hangfire is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with Hangfire. If not, see <http://www.gnu.org/licenses/>.
using System;
using Hangfire.Common;
namespace Hangfire.Storage.Monitoring
{
public class FailedJobDto
{
public FailedJobDto()
{
InFailedState = true;
}
public Job Job { get; set; }
public string Reason { get; set; }
public DateTime? FailedAt { get; set; }
public string ExceptionType { get; set; }
public string ExceptionMessage { get; set; }
public string ExceptionDetails { get; set; }
public bool InFailedState { get; set; }
}
}
\ No newline at end of file
// This file is part of Hangfire.
// Copyright © 2013-2014 Sergey Odinokov.
//
// Hangfire is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation, either version 3
// of the License, or any later version.
//
// Hangfire is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with Hangfire. If not, see <http://www.gnu.org/licenses/>.
using System;
using Hangfire.Common;
namespace Hangfire.Storage.Monitoring
{
public class FetchedJobDto
{
public Job Job { get; set; }
public string State { get; set; }
public DateTime? FetchedAt { get; set; }
}
}
// This file is part of Hangfire.
// Copyright © 2013-2014 Sergey Odinokov.
//
// Hangfire is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation, either version 3
// of the License, or any later version.
//
// Hangfire is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with Hangfire. If not, see <http://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using Hangfire.Common;
namespace Hangfire.Storage.Monitoring
{
public class JobDetailsDto
{
public Job Job { get; set; }
public DateTime? CreatedAt { get; set; }
public IDictionary<string, string> Properties { get; set; }
public IList<StateHistoryDto> History { get; set; }
public DateTime? ExpireAt { get; set; }
}
}
// This file is part of Hangfire.
// Copyright © 2013-2014 Sergey Odinokov.
//
// Hangfire is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation, either version 3
// of the License, or any later version.
//
// Hangfire is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with Hangfire. If not, see <http://www.gnu.org/licenses/>.
using System.Collections.Generic;
namespace Hangfire.Storage.Monitoring
{
public class JobList<TDto> : List<KeyValuePair<string, TDto>>
{
public JobList(IEnumerable<KeyValuePair<string, TDto>> source)
: base(source)
{
}
}
}
\ No newline at end of file
// This file is part of Hangfire.
// Copyright © 2013-2014 Sergey Odinokov.
//
// Hangfire is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation, either version 3
// of the License, or any later version.
//
// Hangfire is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with Hangfire. If not, see <http://www.gnu.org/licenses/>.
using System;
using Hangfire.Common;
namespace Hangfire.Storage.Monitoring
{
public class ProcessingJobDto
{
public ProcessingJobDto()
{
InProcessingState = true;
}
public Job Job { get; set; }
public bool InProcessingState { get; set; }
public string ServerId { get; set; }
public DateTime? StartedAt { get; set; }
}
}
\ No newline at end of file
// This file is part of Hangfire.
// Copyright © 2013-2014 Sergey Odinokov.
//
// Hangfire is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation, either version 3
// of the License, or any later version.
//
// Hangfire is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with Hangfire. If not, see <http://www.gnu.org/licenses/>.
namespace Hangfire.Storage.Monitoring
{
public class QueueWithTopEnqueuedJobsDto
{
public string Name { get; set; }
public long Length { get; set; }
public long? Fetched { get; set; }
public JobList<EnqueuedJobDto> FirstJobs { get; set; }
}
}
// This file is part of Hangfire.
// Copyright © 2013-2014 Sergey Odinokov.
//
// Hangfire is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation, either version 3
// of the License, or any later version.
//
// Hangfire is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with Hangfire. If not, see <http://www.gnu.org/licenses/>.
using System;
using Hangfire.Common;
namespace Hangfire.Storage.Monitoring
{
public class ScheduledJobDto
{
public ScheduledJobDto()
{
InScheduledState = true;
}
public Job Job { get; set; }
public DateTime EnqueueAt { get; set; }
public DateTime? ScheduledAt { get; set; }
public bool InScheduledState { get; set; }
}
}
\ No newline at end of file
// This file is part of Hangfire.
// Copyright © 2013-2014 Sergey Odinokov.
//
// Hangfire is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation, either version 3
// of the License, or any later version.
//
// Hangfire is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with Hangfire. If not, see <http://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
namespace Hangfire.Storage.Monitoring
{
public class ServerDto
{
public string Name { get; set; }
public int WorkersCount { get; set; }
public DateTime StartedAt { get; set; }
public IList<string> Queues { get; set; }
public DateTime? Heartbeat { get; set; }
}
}
\ No newline at end of file
// This file is part of Hangfire.
// Copyright © 2013-2014 Sergey Odinokov.
//
// Hangfire is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation, either version 3
// of the License, or any later version.
//
// Hangfire is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with Hangfire. If not, see <http://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
namespace Hangfire.Storage.Monitoring
{
public class StateHistoryDto
{
public string StateName { get; set; }
public string Reason { get; set; }
public DateTime CreatedAt { get; set; }
public IDictionary<string, string> Data { get; set; }
}
}
\ No newline at end of file
// This file is part of Hangfire.
// Copyright © 2013-2014 Sergey Odinokov.
//
// Hangfire is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation, either version 3
// of the License, or any later version.
//
// Hangfire is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with Hangfire. If not, see <http://www.gnu.org/licenses/>.
namespace Hangfire.Storage.Monitoring
{
public class StatisticsDto
{
public long Servers { get; set; }
public long Recurring { get; set; }
public long Enqueued { get; set; }
public long Queues { get; set; }
public long Scheduled { get; set; }
public long Processing { get; set; }
public long Succeeded { get; set; }
public long Failed { get; set; }
public long Deleted { get; set; }
}
}
using System;
using Hangfire.Common;
namespace Hangfire.Storage.Monitoring
{
public class SucceededJobDto
{
public SucceededJobDto()
{
InSucceededState = true;
}
public Job Job { get; set; }
public object Result { get; set; }
public long? TotalDuration { get; set; }
public DateTime? SucceededAt { get; set; }
public bool InSucceededState { get; set; }
}
}
\ No newline at end of file
// This file is part of Hangfire.
// Copyright © 2013-2014 Sergey Odinokov.
//
// Hangfire is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation, either version 3
// of the License, or any later version.
//
// Hangfire is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with Hangfire. If not, see <http://www.gnu.org/licenses/>.
using System;
using System.Diagnostics;
using System.Net;
using System.Text;
using Hangfire.Storage.Monitoring;
namespace Hangfire.Dashboard
{
public abstract class RazorPage
{
private Lazy<StatisticsDto> _statisticsLazy;
private readonly StringBuilder _content = new StringBuilder();
private string _body;
protected RazorPage()
{
GenerationTime = Stopwatch.StartNew();
Html = new HtmlHelper(this);
}
public RazorPage Layout { get; protected set; }
public HtmlHelper Html { get; private set; }
public UrlHelper Url { get; private set; }
public JobStorage Storage { get; internal set; }
public string AppPath { get; internal set; }
public int StatsPollingInterval { get; internal set; }
public Stopwatch GenerationTime { get; private set; }
public StatisticsDto Statistics
{
get
{
if (_statisticsLazy == null) throw new InvalidOperationException("Page is not initialized.");
return _statisticsLazy.Value;
}
}
internal DashboardRequest Request { private get; set; }
internal DashboardResponse Response { private get; set; }
public string RequestPath => Request.Path;
/// <exclude />
public abstract void Execute();
public string Query(string key)
{
return Request.GetQuery(key);
}
public override string ToString()
{
return TransformText(null);
}
/// <exclude />
public void Assign(RazorPage parentPage)
{
Request = parentPage.Request;
Response = parentPage.Response;
Storage = parentPage.Storage;
AppPath = parentPage.AppPath;
StatsPollingInterval = parentPage.StatsPollingInterval;
Url = parentPage.Url;
GenerationTime = parentPage.GenerationTime;
_statisticsLazy = parentPage._statisticsLazy;
}
internal void Assign(DashboardContext context)
{
Request = context.Request;
Response = context.Response;
Storage = context.Storage;
AppPath = context.Options.AppPath;
StatsPollingInterval = context.Options.StatsPollingInterval;
Url = new UrlHelper(context);
_statisticsLazy = new Lazy<StatisticsDto>(() =>
{
var monitoring = Storage.GetMonitoringApi();
return monitoring.GetStatistics();
});
}
/// <exclude />
protected void WriteLiteral(string textToAppend)
{
if (string.IsNullOrEmpty(textToAppend))
return;
_content.Append(textToAppend);
}
/// <exclude />
protected virtual void Write(object value)
{
if (value == null)
return;
var html = value as NonEscapedString;
WriteLiteral(html?.ToString() ?? Encode(value.ToString()));
}
protected virtual object RenderBody()
{
return new NonEscapedString(_body);
}
private string TransformText(string body)
{
_body = body;
Execute();
if (Layout != null)
{
Layout.Assign(this);
return Layout.TransformText(_content.ToString());
}
return _content.ToString();
}
private static string Encode(string text)
{
return string.IsNullOrEmpty(text)
? string.Empty
: WebUtility.HtmlEncode(text);
}
}
}
@* Generator: Template TypeVisibility: Internal GeneratePrettyNames: true *@
@using System
@using System.Collections.Generic
@using Hangfire.Dashboard
@using Hangfire.Dashboard.Pages
@using Hangfire.Dashboard.Resources
@using Hangfire.States
@using Hangfire.Storage
@inherits RazorPage
@{
Layout = new LayoutPage(Strings.AwaitingJobsPage_Title);
int from, perPage;
int.TryParse(Query("from"), out from);
int.TryParse(Query("count"), out perPage);
List<string> jobIds = null;
Pager pager = null;
using (var connection = Storage.GetConnection())
{
var storageConnection = connection as JobStorageConnection;
if (storageConnection != null)
{
pager = new Pager(from, perPage, storageConnection.GetSetCount("awaiting"));
jobIds = storageConnection.GetRangeFromSet("awaiting", pager.FromRecord, pager.FromRecord + pager.RecordsPerPage - 1);
}
}
}
<div class="row">
<div class="col-md-3">
@Html.JobsSidebar()
</div>
<div class="col-md-9">
<h1 class="page-header">@Strings.AwaitingJobsPage_Title</h1>
@if (jobIds == null)
{
<div class="alert alert-warning">
<h4>@Strings.AwaitingJobsPage_ContinuationsWarning_Title</h4>
<p>@Strings.AwaitingJobsPage_ContinuationsWarning_Text</p>
</div>
}
else if (jobIds.Count > 0)
{
<div class="js-jobs-list">
<div class="btn-toolbar btn-toolbar-top">
<button class="js-jobs-list-command btn btn-sm btn-primary"
data-url="@Url.To("/jobs/awaiting/enqueue")"
data-loading-text="@Strings.Common_Enqueueing">
<span class="glyphicon glyphicon-repeat"></span>
@Strings.Common_EnqueueButton_Text
</button>
<button class="js-jobs-list-command btn btn-sm btn-default"
data-url="@Url.To("/jobs/awaiting/delete")"
data-loading-text="@Strings.Common_Deleting"
data-confirm="@Strings.Common_DeleteConfirm">
<span class="glyphicon glyphicon-remove"></span>
@Strings.Common_DeleteSelected
</button>
@Html.PerPageSelector(pager)
</div>
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th class="min-width">
<input type="checkbox" class="js-jobs-list-select-all" />
</th>
<th class="min-width">@Strings.Common_Id</th>
<th>@Strings.Common_Job</th>
<th class="min-width">@Strings.AwaitingJobsPage_Table_Options</th>
<th class="min-width">@Strings.AwaitingJobsPage_Table_Parent</th>
<th class="align-right">@Strings.Common_Created</th>
</tr>
</thead>
<tbody>
@foreach (var jobId in jobIds)
{
JobData jobData;
StateData stateData;
StateData parentStateData = null;
using (var connection = Storage.GetConnection())
{
jobData = connection.GetJobData(jobId);
stateData = connection.GetStateData(jobId);
if (stateData != null && stateData.Name == AwaitingState.StateName)
{
parentStateData = connection.GetStateData(stateData.Data["ParentId"]);
}
}
<tr class="js-jobs-list-row @(jobData != null ? "hover" : null)">
<td>
<input type="checkbox" class="js-jobs-list-checkbox" name="jobs[]" value="@jobId" />
</td>
<td class="min-width">
@Html.JobIdLink(jobId)
</td>
@if (jobData == null)
{
<td colspan="2"><em>@Strings.Common_JobExpired</em></td>
}
else
{
<td class="word-break">
@Html.JobNameLink(jobId, jobData.Job)
</td>
<td class="min-width">
@if (stateData != null && stateData.Data.ContainsKey("Options") && !String.IsNullOrWhiteSpace(stateData.Data["Options"]))
{
<code>@stateData.Data["Options"]</code>
}
else
{
<em>@Strings.Common_NotAvailable</em>
}
</td>
<td class="min-width">
@if (parentStateData != null)
{
<a href="@Url.JobDetails(stateData.Data["ParentId"])">
<span class="label label-default label-hover" style="@($"background-color: {JobHistoryRenderer.GetForegroundStateColor(parentStateData.Name)};")">
@parentStateData.Name
</span>
</a>
}
else
{
<em>@Strings.Common_NotAvailable</em>
}
</td>
<td class="min-width align-right">
@Html.RelativeTime(jobData.CreatedAt)
</td>
}
</tr>
}
</tbody>
</table>
</div>
@Html.Paginator(pager)
</div>
}
else
{
<div class="alert alert-info">
@Strings.AwaitingJobsPage_NoJobs
</div>
}
</div>
</div>
namespace Hangfire.Dashboard.Pages
{
partial class BlockMetric
{
public BlockMetric(DashboardMetric dashboardMetric)
{
DashboardMetric = dashboardMetric;
}
public DashboardMetric DashboardMetric { get; }
}
}
using System.Collections.Generic;
namespace Hangfire.Dashboard.Pages
{
partial class Breadcrumbs
{
public Breadcrumbs(string title, IDictionary<string, string> items)
{
Title = title;
Items = items;
}
public string Title { get; }
public IDictionary<string, string> Items { get; }
}
}
This diff is collapsed.
namespace Hangfire.Dashboard.Pages
{
partial class EnqueuedJobsPage
{
public EnqueuedJobsPage(string queue)
{
Queue = queue;
}
public string Queue { get; }
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
namespace Hangfire.Dashboard.Pages
{
partial class FetchedJobsPage
{
public FetchedJobsPage(string queue)
{
Queue = queue;
}
public string Queue { get; }
}
}
This diff is collapsed.
using System.Collections.Generic;
namespace Hangfire.Dashboard.Pages
{
partial class HomePage
{
public static readonly List<DashboardMetric> Metrics = new List<DashboardMetric>();
}
}
This diff is collapsed.
This diff is collapsed.
namespace Hangfire.Dashboard.Pages
{
partial class InlineMetric
{
public InlineMetric(DashboardMetric dashboardMetric)
{
DashboardMetric = dashboardMetric;
}
public DashboardMetric DashboardMetric { get; }
}
}
using Hangfire.Annotations;
namespace Hangfire.Dashboard.Pages
{
partial class JobDetailsPage
{
public JobDetailsPage(string jobId)
{
JobId = jobId;
}
public string JobId { get; }
}
}
This diff is collapsed.
namespace Hangfire.Dashboard.Pages
{
partial class LayoutPage
{
public LayoutPage(string title)
{
Title = title;
}
public string Title { get; }
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
@* Generator: Template TypeVisibility: Internal GeneratePrettyNames: True TrimLeadingUnderscores : true *@
@using Hangfire.Dashboard
@inherits RazorPage
@{
var metric = DashboardMetric.Func(this);
var className = metric == null ? "metric-null" : metric.Style.ToClassName();
var highlighted = metric != null && metric.Highlighted ? "highlighted" : null;
}
<span data-metric="@DashboardMetric.Name" class="metric @className @highlighted">@(metric?.Value)</span>
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment