Skip to content

Commit

Permalink
Enable strong typing in comparing resources by using identifier with …
Browse files Browse the repository at this point in the history
…namespace
  • Loading branch information
smitpatel committed Oct 6, 2023
1 parent bd66a2d commit b3e76f5
Show file tree
Hide file tree
Showing 11 changed files with 90 additions and 92 deletions.
8 changes: 4 additions & 4 deletions src/Aspire.Dashboard/Components/Pages/ContainerLogs.razor
Original file line number Diff line number Diff line change
Expand Up @@ -45,23 +45,23 @@

foreach (var result in initialList)
{
_containerNameMapping[result.ViewModel.Name] = result.ViewModel;
_containerNameMapping[result.Name] = result;
}

if (ContainerId is not null)
{
_selectedContainer = initialList?.FirstOrDefault(c => string.Equals(ContainerId, c.ViewModel.ContainerID, StringComparison.Ordinal))?.ViewModel;
_selectedContainer = initialList?.FirstOrDefault(c => string.Equals(ContainerId, c.ContainerID, StringComparison.Ordinal));
}
else if (initialList?.Count > 0)
{
_selectedContainer = initialList[0].ViewModel;
_selectedContainer = initialList[0];
}

await LoadLogsAsync();

_ = Task.Run(async () =>
{
await foreach (var componentChanged in DashboardViewModelService.WatchContainersAsync(existingContainers: initialList?.Select(t => t.Model), cancellationToken: _watchContainersTokenSource.Token))
await foreach (var componentChanged in DashboardViewModelService.WatchContainersAsync(existingContainers: initialList?.Select(t => t.NamespacedName), cancellationToken: _watchContainersTokenSource.Token))
{
await OnContainerListChanged(componentChanged.ObjectChangeType, componentChanged.Component);
}
Expand Down
8 changes: 4 additions & 4 deletions src/Aspire.Dashboard/Components/Pages/ExecutableLogs.razor
Original file line number Diff line number Diff line change
Expand Up @@ -45,23 +45,23 @@

foreach (var result in initialList)
{
_executableNameMapping[result.ViewModel.Name] = result.ViewModel;
_executableNameMapping[result.Name] = result;
}

if (ExecutableName is not null)
{
_selectedExecutable = initialList?.FirstOrDefault(c => string.Equals(ExecutableName, c.ViewModel.Name, StringComparison.Ordinal))?.ViewModel;
_selectedExecutable = initialList?.FirstOrDefault(c => string.Equals(ExecutableName, c.Name, StringComparison.Ordinal));
}
else if (initialList?.Count > 0)
{
_selectedExecutable = initialList[0].ViewModel;
_selectedExecutable = initialList[0];
}

await LoadLogsAsync();

_ = Task.Run(async () =>
{
await foreach (var componentChanged in DashboardViewModelService.WatchExecutablesAsync(existingExecutables: initialList?.Select(t => t.Model), cancellationToken: _watchExecutablesTokenSource.Token))
await foreach (var componentChanged in DashboardViewModelService.WatchExecutablesAsync(existingExecutables: initialList?.Select(t => t.NamespacedName), cancellationToken: _watchExecutablesTokenSource.Token))
{
await OnExecutableListChanged(componentChanged.ObjectChangeType, componentChanged.Component);
}
Expand Down
8 changes: 4 additions & 4 deletions src/Aspire.Dashboard/Components/Pages/ProjectLogs.razor
Original file line number Diff line number Diff line change
Expand Up @@ -45,23 +45,23 @@

foreach (var result in initialList)
{
_projectNameMapping[result.ViewModel.Name] = result.ViewModel;
_projectNameMapping[result.Name] = result;
}

if (ProjectName is not null)
{
_selectedProject = initialList?.FirstOrDefault(c => string.Equals(ProjectName, c.ViewModel.Name, StringComparison.Ordinal))?.ViewModel;
_selectedProject = initialList?.FirstOrDefault(c => string.Equals(ProjectName, c.Name, StringComparison.Ordinal));
}
else if (initialList?.Count > 0)
{
_selectedProject = initialList[0].ViewModel;
_selectedProject = initialList[0];
}

await LoadLogsAsync();

_ = Task.Run(async () =>
{
await foreach (var componentChanged in DashboardViewModelService.WatchProjectsAsync(existingProjects: initialList?.Select(t => t.Model), cancellationToken: _watchProjectsTokenSource.Token))
await foreach (var componentChanged in DashboardViewModelService.WatchProjectsAsync(existingProjects: initialList?.Select(t => t.NamespacedName), cancellationToken: _watchProjectsTokenSource.Token))
{
await OnProjectListChanged(componentChanged.ObjectChangeType, componentChanged.Component);
}
Expand Down
7 changes: 1 addition & 6 deletions src/Aspire.Dashboard/Model/ContainerViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,9 @@

namespace Aspire.Dashboard.Model;

public class ContainerViewModel
public class ContainerViewModel : ResourceViewModel
{
public required string Name { get; init; }
public string? State { get; init; }
public string? ContainerID { get; init; }
public DateTime? CreationTimeStamp { get; init; }
public required string Image { get; init; }
public List<int> Ports { get; } = new();
public required ILogSource LogSource { get; init; }
public List<EnvironmentVariableViewModel> Environment { get; } = new();
}
7 changes: 1 addition & 6 deletions src/Aspire.Dashboard/Model/ExecutableViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,8 @@

namespace Aspire.Dashboard.Model;

public class ExecutableViewModel
public class ExecutableViewModel : ResourceViewModel
{
public required string Name { get; init; }
public string? State { get; init; }
public DateTime? CreationTimeStamp { get; set; }
public string? ExecutablePath { get; set; }
public List<EnvironmentVariableViewModel> Environment { get; } = new();
public required ILogSource LogSource { get; init; }
}

12 changes: 6 additions & 6 deletions src/Aspire.Dashboard/Model/IDashboardViewModelService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ namespace Aspire.Dashboard.Model;

public interface IDashboardViewModelService
{
public Task<List<ResultWithSource<ContainerViewModel>>> GetContainersAsync();
public Task<List<ResultWithSource<ExecutableViewModel>>> GetExecutablesAsync();
public Task<List<ResultWithSource<ProjectViewModel>>> GetProjectsAsync();
public IAsyncEnumerable<ComponentChanged<ContainerViewModel>> WatchContainersAsync(IEnumerable<object>? existingContainers = null, CancellationToken cancellationToken = default);
public IAsyncEnumerable<ComponentChanged<ExecutableViewModel>> WatchExecutablesAsync(IEnumerable<object>? existingExecutables = null, CancellationToken cancellationToken = default);
public IAsyncEnumerable<ComponentChanged<ProjectViewModel>> WatchProjectsAsync(IEnumerable<object>? existingProjects = null, CancellationToken cancellationToken = default);
public Task<List<ContainerViewModel>> GetContainersAsync();
public Task<List<ExecutableViewModel>> GetExecutablesAsync();
public Task<List<ProjectViewModel>> GetProjectsAsync();
public IAsyncEnumerable<ComponentChanged<ContainerViewModel>> WatchContainersAsync(IEnumerable<NamespacedName>? existingContainers = null, CancellationToken cancellationToken = default);
public IAsyncEnumerable<ComponentChanged<ExecutableViewModel>> WatchExecutablesAsync(IEnumerable<NamespacedName>? existingExecutables = null, CancellationToken cancellationToken = default);
public IAsyncEnumerable<ComponentChanged<ProjectViewModel>> WatchProjectsAsync(IEnumerable<NamespacedName>? existingProjects = null, CancellationToken cancellationToken = default);
}
11 changes: 1 addition & 10 deletions src/Aspire.Dashboard/Model/ProjectViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,10 @@

namespace Aspire.Dashboard.Model;

public class ProjectViewModel
public class ProjectViewModel : ResourceViewModel
{
public required string Name { get; init; }
public string? State { get; init; }
public DateTime? CreationTimeStamp { get; init; }

public required string ProjectPath { get; init; }

public List<string> Addresses { get; } = new();

public List<ServiceEndpoint> Endpoints { get; } = new();
public List<EnvironmentVariableViewModel> Environment { get; } = new();
public required ILogSource LogSource { get; init; }
public required int ExpectedEndpointCount { get; init; }
}

16 changes: 16 additions & 0 deletions src/Aspire.Dashboard/Model/ResourceViewModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace Aspire.Dashboard.Model;

public abstract class ResourceViewModel
{
public required string Name { get; init; }
public required NamespacedName NamespacedName { get; init; }
public string? State { get; init; }
public DateTime? CreationTimeStamp { get; init; }
public List<EnvironmentVariableViewModel> Environment { get; } = new();
public required ILogSource LogSource { get; init; }
}

public sealed record NamespacedName(string Name, string? Namespace);
6 changes: 0 additions & 6 deletions src/Aspire.Dashboard/Model/ResultWithSource.cs

This file was deleted.

92 changes: 49 additions & 43 deletions src/Aspire.Hosting/Dashboard/DashboardViewModelService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,45 +22,46 @@ public DashboardViewModelService(DistributedApplicationModel applicationModel)
_kubernetesService = new KubernetesService();
}

public async Task<List<ResultWithSource<ExecutableViewModel>>> GetExecutablesAsync()
public async Task<List<ExecutableViewModel>> GetExecutablesAsync()
{
var executables = await _kubernetesService.ListAsync<Executable>().ConfigureAwait(false);
return executables
.Where(exe => exe.Metadata.Annotations?.ContainsKey(Executable.CSharpProjectPathAnnotation) == false)
.Select(exe =>
{
var model = new ExecutableViewModel()
.Where(executable => executable.Metadata.Annotations?.ContainsKey(Executable.CSharpProjectPathAnnotation) == false)
.Select(executable =>
{
Name = exe.Metadata.Name,
CreationTimeStamp = exe.Metadata?.CreationTimestamp?.ToLocalTime(),
ExecutablePath = exe.Spec.ExecutablePath,
State = exe.Status?.State,
LogSource = new FileLogSource(exe.Status?.StdOutFile, exe.Status?.StdErrFile)
};
var model = new ExecutableViewModel()
{
Name = executable.Metadata.Name,
NamespacedName = new(executable.Metadata.Name, null),
CreationTimeStamp = executable.Metadata?.CreationTimestamp?.ToLocalTime(),
ExecutablePath = executable.Spec.ExecutablePath,
State = executable.Status?.State,
LogSource = new FileLogSource(executable.Status?.StdOutFile, executable.Status?.StdErrFile)
};
if (exe.Status?.EffectiveEnv is not null)
{
FillEnvironmentVariables(model.Environment, exe.Status.EffectiveEnv);
}
if (executable.Status?.EffectiveEnv is not null)
{
FillEnvironmentVariables(model.Environment, executable.Status.EffectiveEnv);
}
return new ResultWithSource<ExecutableViewModel>(model, exe);
})
.OrderBy(e => e.ViewModel.Name)
.ToList();
return model;
})
.OrderBy(e => e.Name)
.ToList();
}

public async Task<List<ResultWithSource<ProjectViewModel>>> GetProjectsAsync()
public async Task<List<ProjectViewModel>> GetProjectsAsync()
{
var executables = await _kubernetesService.ListAsync<Executable>().ConfigureAwait(false);

var endpoints = await _kubernetesService.ListAsync<Endpoint>().ConfigureAwait(false);

return executables
.Where(exe => exe.Metadata.Annotations?.ContainsKey(Executable.CSharpProjectPathAnnotation) == true)
.Select(exe =>
.Where(executable => executable.Metadata.Annotations?.ContainsKey(Executable.CSharpProjectPathAnnotation) == true)
.Select(executable =>
{
var expectedEndpointCount = 0;
if (exe.Metadata?.Annotations?.TryGetValue(Executable.ServiceProducerAnnotation, out var annotationJson) == true)
if (executable.Metadata?.Annotations?.TryGetValue(Executable.ServiceProducerAnnotation, out var annotationJson) == true)
{
var serviceProducerAnnotations = JsonSerializer.Deserialize<ServiceProducerAnnotation[]>(annotationJson);
if (serviceProducerAnnotations is not null)
Expand All @@ -71,11 +72,12 @@ public async Task<List<ResultWithSource<ProjectViewModel>>> GetProjectsAsync()
var model = new ProjectViewModel
{
Name = exe.Metadata!.Name,
CreationTimeStamp = exe.Metadata?.CreationTimestamp?.ToLocalTime(),
ProjectPath = exe.Metadata?.Annotations?[Executable.CSharpProjectPathAnnotation] ?? "",
State = exe.Status?.State,
LogSource = new FileLogSource(exe.Status?.StdOutFile, exe.Status?.StdErrFile),
Name = executable.Metadata!.Name,
NamespacedName = new(executable.Metadata.Name, null),
CreationTimeStamp = executable.Metadata?.CreationTimestamp?.ToLocalTime(),
ProjectPath = executable.Metadata?.Annotations?[Executable.CSharpProjectPathAnnotation] ?? "",
State = executable.Status?.State,
LogSource = new FileLogSource(executable.Status?.StdOutFile, executable.Status?.StdErrFile),
ExpectedEndpointCount = expectedEndpointCount
};
Expand All @@ -85,7 +87,7 @@ public async Task<List<ResultWithSource<ProjectViewModel>>> GetProjectsAsync()
}
model.Endpoints.AddRange(endpoints
.Where(ep => ep.Metadata.OwnerReferences.Any(or => or.Kind == exe.Kind && or.Name == exe.Metadata?.Name))
.Where(ep => ep.Metadata.OwnerReferences.Any(or => or.Kind == executable.Kind && or.Name == executable.Metadata?.Name))
.Select(ep =>
{
// CONSIDER: a more robust way to store application protocol information in DCP model
Expand All @@ -99,18 +101,18 @@ public async Task<List<ResultWithSource<ProjectViewModel>>> GetProjectsAsync()
})
);
if (exe.Status?.EffectiveEnv is not null)
if (executable.Status?.EffectiveEnv is not null)
{
FillEnvironmentVariables(model.Environment, exe.Status.EffectiveEnv);
FillEnvironmentVariables(model.Environment, executable.Status.EffectiveEnv);
}
return new ResultWithSource<ProjectViewModel>(model, exe);
return model;
})
.OrderBy(m => m.ViewModel.Name)
.OrderBy(m => m.Name)
.ToList();
}

public async Task<List<ResultWithSource<ContainerViewModel>>> GetContainersAsync()
public async Task<List<ContainerViewModel>> GetContainersAsync()
{
var containers = await _kubernetesService.ListAsync<Container>().ConfigureAwait(false);

Expand All @@ -120,6 +122,7 @@ public async Task<List<ResultWithSource<ContainerViewModel>>> GetContainersAsync
var model = new ContainerViewModel
{
Name = container.Metadata.Name,
NamespacedName = new(container.Metadata.Name, null),
ContainerID = container.Status?.ContainerID,
CreationTimeStamp = container.Metadata.CreationTimestamp?.ToLocalTime(),
Image = container.Spec.Image!,
Expand All @@ -143,17 +146,17 @@ public async Task<List<ResultWithSource<ContainerViewModel>>> GetContainersAsync
FillEnvironmentVariables(model.Environment, container.Spec.Env);
}
return new ResultWithSource<ContainerViewModel>(model, container);
return model;
})
.OrderBy(e => e.ViewModel.Name)
.OrderBy(e => e.Name)
.ToList();
}

public async IAsyncEnumerable<ComponentChanged<ContainerViewModel>> WatchContainersAsync(
IEnumerable<object>? existingContainers = null,
IEnumerable<NamespacedName>? existingContainers = null,
[EnumeratorCancellation] CancellationToken cancellationToken = default)
{
await foreach (var (watchEventType, container) in _kubernetesService.WatchAsync<Container>(existingObjects: existingContainers?.Cast<Container>(), cancellationToken: cancellationToken))
await foreach (var (watchEventType, container) in _kubernetesService.WatchAsync<Container>(existingObjects: existingContainers, cancellationToken: cancellationToken))
{
var objectChangeType = ToObjectChangeType(watchEventType);
if (objectChangeType == ObjectChangeType.Other)
Expand All @@ -164,6 +167,7 @@ public async IAsyncEnumerable<ComponentChanged<ContainerViewModel>> WatchContain
var containerViewModel = new ContainerViewModel
{
Name = container.Metadata.Name,
NamespacedName = new(container.Metadata.Name, null),
ContainerID = container.Status?.ContainerID,
CreationTimeStamp = container.Metadata.CreationTimestamp?.ToLocalTime(),
Image = container.Spec.Image!,
Expand Down Expand Up @@ -192,10 +196,10 @@ public async IAsyncEnumerable<ComponentChanged<ContainerViewModel>> WatchContain
}

public async IAsyncEnumerable<ComponentChanged<ExecutableViewModel>> WatchExecutablesAsync(
IEnumerable<object>? existingExecutables = null,
IEnumerable<NamespacedName>? existingExecutables = null,
[EnumeratorCancellation] CancellationToken cancellationToken = default)
{
await foreach (var (watchEventType, executable) in _kubernetesService.WatchAsync<Executable>(existingObjects: existingExecutables?.Cast<Executable>(), cancellationToken: cancellationToken))
await foreach (var (watchEventType, executable) in _kubernetesService.WatchAsync<Executable>(existingObjects: existingExecutables, cancellationToken: cancellationToken))
{
var objectChangeType = ToObjectChangeType(watchEventType);
if (objectChangeType == ObjectChangeType.Other)
Expand All @@ -208,9 +212,10 @@ public async IAsyncEnumerable<ComponentChanged<ExecutableViewModel>> WatchExecut
continue;
}

var executableViewModel = new ExecutableViewModel()
var executableViewModel = new ExecutableViewModel
{
Name = executable.Metadata.Name,
NamespacedName = new(executable.Metadata.Name, null),
CreationTimeStamp = executable.Metadata?.CreationTimestamp?.ToLocalTime(),
ExecutablePath = executable.Spec.ExecutablePath,
State = executable.Status?.State,
Expand All @@ -227,10 +232,10 @@ public async IAsyncEnumerable<ComponentChanged<ExecutableViewModel>> WatchExecut
}

public async IAsyncEnumerable<ComponentChanged<ProjectViewModel>> WatchProjectsAsync(
IEnumerable<object>? existingProjects = null,
IEnumerable<NamespacedName>? existingProjects = null,
[EnumeratorCancellation] CancellationToken cancellationToken = default)
{
await foreach (var (watchEventType, executable) in _kubernetesService.WatchAsync<Executable>(existingObjects: existingProjects?.Cast<Executable>(), cancellationToken: cancellationToken))
await foreach (var (watchEventType, executable) in _kubernetesService.WatchAsync<Executable>(existingObjects: existingProjects, cancellationToken: cancellationToken))
{
var objectChangeType = ToObjectChangeType(watchEventType);
if (objectChangeType == ObjectChangeType.Other)
Expand All @@ -256,6 +261,7 @@ public async IAsyncEnumerable<ComponentChanged<ProjectViewModel>> WatchProjectsA
var projectViewModel = new ProjectViewModel
{
Name = executable.Metadata!.Name,
NamespacedName = new(executable.Metadata.Name, null),
CreationTimeStamp = executable.Metadata?.CreationTimestamp?.ToLocalTime(),
ProjectPath = executable.Metadata?.Annotations?[Executable.CSharpProjectPathAnnotation] ?? "",
State = executable.Status?.State,
Expand Down
Loading

0 comments on commit b3e76f5

Please sign in to comment.