Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions pack-local.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#!/usr/bin/env bash
set -euo pipefail

repo_root="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
feed="${SHEDDUELLER_LOCAL_FEED:-"$HOME/.nuget/local-sheddueller"}"
version="${1:-${SHEDDUELLER_LOCAL_VERSION:-"0.1.0-local.$(date -u +%Y%m%d).$(date -u +%s)"}}"
configuration="${CONFIGURATION:-Release}"

projects=(
"src/Sheddueller/Sheddueller.csproj"
"src/Sheddueller.Worker/Sheddueller.Worker.csproj"
"src/Sheddueller.Postgres/Sheddueller.Postgres.csproj"
"src/Sheddueller.Dashboard/Sheddueller.Dashboard.csproj"
"src/Sheddueller.Testing/Sheddueller.Testing.csproj"
)

mkdir -p "$feed"

{
printf 'Packing Sheddueller local packages\n'
printf ' Version: %s\n' "$version"
printf ' Feed: %s\n' "$feed"
printf ' Configuration: %s\n' "$configuration"
} >&2

cd "$repo_root"

for project in "${projects[@]}"; do
printf 'Packing %s\n' "$project" >&2
dotnet pack "$project" \
--configuration "$configuration" \
--output "$feed" \
-p:Version="$version" \
-p:PackageVersion="$version" >&2
done

printf '%s\n' "$version"
20 changes: 19 additions & 1 deletion src/Sheddueller.Dashboard/Components/DashboardApp.razor
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<script src="https://cdn.jsdelivr.net/npm/uplot@1.6.32/dist/uPlot.iife.min.js"></script>
<script src="_content/Sheddueller.Dashboard/vendor/prism/prism.js" data-manual></script>
<script src="_content/Sheddueller.Dashboard/vendor/prism/sheddueller-prism.js"></script>
<script src="_content/Sheddueller.Dashboard/vendor/sheddueller-throughput-chart.js"></script>
<script src="_content/Sheddueller.Dashboard/vendor/sheddueller-throughput-chart.js?v=@DashboardAssetVersion"></script>
<script src="_framework/blazor.web.js"></script>
</body>
</html>
Expand All @@ -31,4 +31,22 @@
=> DashboardOptions.Value.Prerender
? InteractiveServer
: new InteractiveServerRenderMode(prerender: false);

private static string DashboardAssetVersion
{
get
{
var assembly = typeof(ShedduellerDashboardOptions).Assembly;
var attribute = (System.Reflection.AssemblyInformationalVersionAttribute?)Attribute.GetCustomAttribute(
assembly,
typeof(System.Reflection.AssemblyInformationalVersionAttribute));
var version = attribute?.InformationalVersion ?? assembly.GetName().Version?.ToString() ?? "dev";
var location = assembly.Location;
var stamp = string.IsNullOrEmpty(location) || !File.Exists(location)
? assembly.ManifestModule.ModuleVersionId.ToString("N")
: File.GetLastWriteTimeUtc(location).Ticks.ToString(System.Globalization.CultureInfo.InvariantCulture);

return Uri.EscapeDataString(string.Concat(version, ".", stamp));
}
}
}
9 changes: 6 additions & 3 deletions src/Sheddueller.Dashboard/Components/DashboardLayout.razor
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<aside class="sd-sidebar" aria-label="Dashboard navigation">
<div class="sd-sidebar__brand">
<span class="sd-sidebar__title">Sheddueller</span>
<span class="sd-sidebar__subtitle">Operational Control</span>
<span class="sd-sidebar__subtitle">Dashboard</span>
</div>

<nav class="sd-sidebar__nav" aria-label="Primary">
Expand Down Expand Up @@ -41,8 +41,10 @@
<nav class="sd-sidebar__nav sd-sidebar__nav--footer" aria-label="Refresh controls">
<div class="sd-shell-refresh">
<span class="sd-shell-refresh__label">Live Refresh</span>
<LiveStatus IsRefreshing="refresh.Coordinator.IsRefreshing" ShowRefreshing="refresh.ShowRefreshing" LastUpdatedUtc="@refresh.GetLastUpdatedUtc(DateTimeOffset.UtcNow)" />
<button class="@ShellRefreshButtonClass(refresh)" type="button" @onclick="ToggleShellAutoRefreshAsync" aria-pressed="@refresh.Coordinator.AutoRefreshEnabled">
<LiveStatus IsRefreshing="refresh.Coordinator.IsRefreshing" ShowRefreshing="refresh.ShowRefreshing"
LastUpdatedUtc="@refresh.GetLastUpdatedUtc(DateTimeOffset.UtcNow)" />
<button class="@ShellRefreshButtonClass(refresh)" type="button"
@onclick="ToggleShellAutoRefreshAsync" aria-pressed="@refresh.Coordinator.AutoRefreshEnabled">
<span class="material-symbols-outlined" aria-hidden="true">sync</span>
<span>Auto-refresh @AutoRefreshStateText(refresh)</span>
</button>
Expand Down Expand Up @@ -701,6 +703,7 @@
}

@@media (max-width: 720px) {

.sd-table-controls,
.sd-table-search,
.sd-table-select,
Expand Down
105 changes: 62 additions & 43 deletions src/Sheddueller.Dashboard/Components/Pages/Metrics.razor
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
@page "/metrics"
@inherits DashboardPageComponent
@inject IMetricsInspectionReader Reader
@inject IDashboardThroughputReader ThroughputReader

<div class="metrics-page">
<header class="metrics-header">
Expand Down Expand Up @@ -85,7 +84,6 @@
</div>
<strong>@DashboardFormat.Count(selectedWindow.QueuedCount)</strong>
<div class="metrics-summary-card__detail">
<span aria-hidden="true"></span>
<span>Oldest queued: <em>@DashboardMetricsFormat.Duration(selectedWindow.OldestQueuedAge)</em></span>
</div>
</article>
Expand All @@ -109,7 +107,6 @@
</div>
<strong>@DashboardMetricsFormat.Duration(selectedWindow.P95ScheduleFireLag)</strong>
<div class="metrics-summary-card__detail">
<span aria-hidden="true"></span>
<span>p95 over @DashboardMetricsFormat.WindowLabel(selectedWindow.Window)</span>
</div>
</article>
Expand Down Expand Up @@ -142,10 +139,10 @@
<section class="metrics-throughput-panel" aria-label="Live throughput graph">
<div class="metrics-panel__header">
<h2>Live Throughput</h2>
<span>1s Buckets / 1h Window</span>
<span>5s Buckets / 1h Window</span>
</div>

<ThroughputChart Snapshot="_throughputSnapshot" />
<ThroughputChart AutoRefreshEnabledProvider="@(() => LiveRefresh.AutoRefreshEnabled)" />
</section>

<section class="metrics-panel-grid" aria-label="Latency and duration metrics">
Expand Down Expand Up @@ -477,14 +474,6 @@
line-height: 16px;
}

.metrics-summary-card__detail>span:first-child {
width: 6px;
height: 6px;
flex: 0 0 auto;
border-radius: 999px;
background: var(--sd-outline);
}

.metrics-summary-card__detail em,
.metrics-rate-stack em {
color: var(--sd-on-surface);
Expand All @@ -493,21 +482,20 @@
}

.metrics-rate-stack {
flex-wrap: wrap;
gap: 8px;
display: grid;
min-height: 36px;
align-content: start;
gap: 4px;
color: var(--sd-on-surface-variant);
font-size: 12px;
line-height: 16px;
}

.metrics-rate-stack span {
padding-right: 8px;
border-right: 1px solid var(--sd-outline-variant);
}

.metrics-rate-stack span:last-child {
padding-right: 0;
border-right: 0;
display: grid;
grid-template-columns: 52px max-content;
gap: 6px;
white-space: nowrap;
}

.metrics-node-health {
Expand Down Expand Up @@ -697,7 +685,12 @@
overflow: hidden;
}

.throughput-chart>div.uplot {
.throughput-chart__plot {
position: absolute;
inset: 0;
}

.throughput-chart__plot>div.uplot {
width: 100%;
}

Expand All @@ -707,6 +700,24 @@
height: 220px;
}

.throughput-chart__clip-layer {
position: absolute;
inset: 0;
z-index: 1;
pointer-events: none;
}

.throughput-chart__clip-marker {
position: absolute;
width: 7px;
height: 7px;
border: 1px solid var(--sd-surface-lowest);
border-radius: 999px;
box-shadow: 0 0 0 1px var(--sd-background);
pointer-events: auto;
transform: translate(-50%, 0);
}

.throughput-chart__empty,
.throughput-chart--empty {
position: absolute;
Expand Down Expand Up @@ -740,10 +751,26 @@
background: var(--sd-surface);
padding: 6px 8px;
color: var(--sd-on-surface-variant);
cursor: pointer;
font: inherit;
font-size: 12px;
line-height: 16px;
}

.throughput-chart-legend__item:hover {
border-color: var(--sd-outline);
background: var(--sd-surface-high);
}

.throughput-chart-legend__item:focus-visible {
outline: 2px solid var(--sd-primary);
outline-offset: 2px;
}

.throughput-chart-legend__item--muted {
opacity: 0.55;
}

.throughput-chart-legend__item>span {
width: 8px;
height: 8px;
Expand All @@ -752,6 +779,10 @@
background: var(--sd-outline);
}

.throughput-chart-legend__item.throughput-chart-legend__item--muted>span {
background: var(--sd-outline);
}

.throughput-chart-legend__item em {
font-style: normal;
}
Expand Down Expand Up @@ -949,7 +980,6 @@
TimeSpan.FromHours(24)];

private MetricsInspectionSnapshot? _snapshot;
private DashboardThroughputSnapshot? _throughputSnapshot;
private string? _loadError;
private TimeSpan _selectedWindow = TimeSpan.FromHours(1);
private bool _isLoading;
Expand Down Expand Up @@ -985,8 +1015,10 @@ TimeSpan.FromHours(24)];

try
{
var snapshot = await this.ReadPageSnapshotAsync(CancellationToken.None);
this.ApplySnapshot(snapshot.Metrics, snapshot.Throughput);
var snapshot = await Reader.GetMetricsAsync(
new MetricsInspectionQuery(DefaultMetricWindows),
CancellationToken.None);
this.ApplySnapshot(snapshot);
this.LiveRefresh.MarkUpdated();
}
catch (NotSupportedException)
Expand All @@ -1006,25 +1038,15 @@ TimeSpan.FromHours(24)];

private async Task RefreshCurrentQueryAsync(CancellationToken cancellationToken)
{
var snapshot = await this.ReadPageSnapshotAsync(cancellationToken);
await this.ApplyPageStateAsync(() => this.ApplySnapshot(snapshot.Metrics, snapshot.Throughput));
}

private async Task<MetricsPageSnapshot> ReadPageSnapshotAsync(CancellationToken cancellationToken)
{
var metrics = await Reader.GetMetricsAsync(
var snapshot = await Reader.GetMetricsAsync(
new MetricsInspectionQuery(DefaultMetricWindows),
cancellationToken)
;
return new MetricsPageSnapshot(metrics, ThroughputReader.GetSnapshot());
cancellationToken);
await this.ApplyPageStateAsync(() => this.ApplySnapshot(snapshot));
}

private void ApplySnapshot(
MetricsInspectionSnapshot snapshot,
DashboardThroughputSnapshot throughputSnapshot)
private void ApplySnapshot(MetricsInspectionSnapshot snapshot)
{
this._snapshot = snapshot;
this._throughputSnapshot = throughputSnapshot;
this._loadError = null;
this._metricsUnsupported = false;

Expand All @@ -1037,7 +1059,4 @@ TimeSpan.FromHours(24)];
private string WindowRowClass(MetricsInspectionWindow window)
=> window.Window == (this.SelectedWindow?.Window ?? this._selectedWindow) ? "metrics-row--selected" : string.Empty;

private sealed record MetricsPageSnapshot(
MetricsInspectionSnapshot Metrics,
DashboardThroughputSnapshot Throughput);
}
Loading