Skip to content

Commit

Permalink
feat: search
Browse files Browse the repository at this point in the history
  • Loading branch information
IvanJosipovic committed Jun 24, 2024
1 parent 2e097f6 commit da34447
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 22 deletions.
2 changes: 1 addition & 1 deletion src/KubeUI/Client/Cluster.cs
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ public void Seed(Type type)
await Dispatcher.UIThread.InvokeAsync(() => items[name] = item);
break;
case WatchEventType.Deleted:
await Dispatcher.UIThread.InvokeAsync(() => items.TryRemove(name, out var old));
await Dispatcher.UIThread.InvokeAsync(() => items.Remove(name));
//todo Check if CRD and remove from menu etc
break;
case WatchEventType.Error:
Expand Down
2 changes: 1 addition & 1 deletion src/KubeUI/ViewModels/NavigationViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ private static object GetContext(Type type, object list, GroupApiVersionKind kin
constructedType.GetProperty(nameof(ResourceListViewModel<V1Pod>.Objects))?.SetValue(instance, list);
constructedType.GetProperty(nameof(ResourceListViewModel<V1Pod>.Kind))?.SetValue(instance, kind);

constructedType.GetMethod("Initialize")?.Invoke(instance, null);
constructedType.GetMethod(nameof(ResourceListViewModel<V1Pod>.Initialize))?.Invoke(instance, null);

return instance;
}
Expand Down
116 changes: 98 additions & 18 deletions src/KubeUI/ViewModels/ResourceListViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ internal class DemoResourceListViewModel : ResourceListViewModel<V1Pod> { public
[ObservableProperty]
private string _searchQuery;

[ObservableProperty]
private ResourceListViewDefinition<T> _viewDefinitions;

private IDisposable _filter;

public ResourceListViewModel()
Expand All @@ -82,28 +85,96 @@ public void Initialize()
DataGridObjects = filteredObjects;

Namespaces = Cluster.GetObjectDictionary<V1Namespace>();

ViewDefinitions = GetViewDefinition<T>();
}

private void SetFilter()
{
_filter.Dispose();

_filter = Objects.ToObservableChangeSet<ConcurrentObservableDictionary<NamespacedName, T>, KeyValuePair<NamespacedName, T>>()
.Filter(GenerateFilter())
.Bind(out var filteredObjects)
.Subscribe();

DataGridObjects = filteredObjects;
}

private Func<KeyValuePair<NamespacedName, T>, bool> GenerateFilter()
{
var param = Expression.Parameter(typeof(KeyValuePair<NamespacedName, T>), "p");

var key = Expression.PropertyOrField(param, "Key");

var value = Expression.PropertyOrField(param, "Value");

BinaryExpression? body = null;

BinaryExpression? namespaceFilter = null;

BinaryExpression? searchFilter = null;

if (SelectedNamespaces != null)
{
if (SelectedNamespaces is ICollection)
{
throw new NotImplementedException();
}
else if(SelectedNamespaces is V1Namespace @namespace)
namespaceFilter = Expression.Equal(
Expression.PropertyOrField(key, "Namespace"),
Expression.Constant(((V1Namespace)SelectedNamespaces).Name())
);
}

if(!string.IsNullOrEmpty(SearchQuery))
{
var method = typeof(string).GetMethod(nameof(string.IndexOf), [typeof(string), typeof(StringComparison)]);

foreach (var query in SearchQuery.Split(' '))
{
_filter.Dispose();
if (string.IsNullOrEmpty(query))
{
continue;
}

BinaryExpression? wordFilter = null;

foreach (var column in ViewDefinitions.Columns)
{
var someValue = Expression.Constant(query, typeof(string));

_filter = Objects.ToObservableChangeSet<ConcurrentObservableDictionary<NamespacedName, T>, KeyValuePair<NamespacedName, T>>()
.Filter(x => x.Key.Namespace == @namespace.Metadata.Name)
.Bind(out var filteredObjects)
.Subscribe();
var colType = column.GetType();

var columnDisplay = (Func<T, string>)colType.GetProperty(nameof(ResourceListViewDefinitionColumn<V1Pod, string>.Display)).GetValue(column);

columnDisplay ??= (Func<T, string>)colType.GetProperty(nameof(ResourceListViewDefinitionColumn<V1Pod, string>.Field)).GetValue(column);

var funcCall = Expression.Call(Expression.Constant(columnDisplay), columnDisplay.GetType().GetMethod("Invoke"), value);

var expression = Expression.GreaterThanOrEqual(Expression.Call(funcCall, method, someValue, Expression.Constant(StringComparison.OrdinalIgnoreCase)), Expression.Constant(0));

wordFilter = wordFilter == null ? expression : Expression.OrElse(wordFilter, expression);
}

DataGridObjects = filteredObjects;
searchFilter = searchFilter == null ? wordFilter : Expression.AndAlso(searchFilter, wordFilter);
}
}

if (namespaceFilter != null && searchFilter == null)
{
body = namespaceFilter;
}
else if (namespaceFilter == null && searchFilter != null)
{
body = searchFilter;
}
else if (namespaceFilter != null && searchFilter != null)
{
body = Expression.AndAlso(namespaceFilter, searchFilter);
}
else
{
body = Expression.Equal(Expression.Constant(true), Expression.Constant(true));
}

return Expression.Lambda<Func<KeyValuePair<NamespacedName, T>, bool>>(body, param).Compile();
}

protected override void OnPropertyChanged(PropertyChangedEventArgs e)
Expand All @@ -117,11 +188,11 @@ protected override void OnPropertyChanged(PropertyChangedEventArgs e)

if (e.PropertyName == nameof(SearchQuery))
{
//SetFilter();
SetFilter();
}
}

public ResourceListViewDefinition<T> GetResourceListViewDefinition<T>() where T : class, IKubernetesObject<V1ObjectMeta>, new()
private ResourceListViewDefinition<T> GetViewDefinition<T>() where T : class, IKubernetesObject<V1ObjectMeta>, new()
{
var resourceType = typeof(T);

Expand Down Expand Up @@ -177,14 +248,15 @@ protected override void OnPropertyChanged(PropertyChangedEventArgs e)
new ResourceListViewDefinitionColumn<V1Node, string>()
{
Name = "Status",
Field = x => x.Status.Conditions.FirstOrDefault(x => x.Type == "Ready")?.Reason,
Field = x => x.Status.Conditions.FirstOrDefault(x => x.Type == "Ready")?.Reason ?? "",
Width = nameof(DataGridLengthUnitType.SizeToHeader)
},
new ResourceListViewDefinitionColumn<V1Node, DateTime?>()
{
Name = "Age",
CustomControl = typeof(AgeCell),
Field = x => x.Metadata.CreationTimestamp,
Display = x => x.Metadata.CreationTimestamp?.ToString("yyyy-MM-dd HH:mm:ss") ?? "",
Width = "80"
}
};
Expand Down Expand Up @@ -217,6 +289,7 @@ protected override void OnPropertyChanged(PropertyChangedEventArgs e)
Name = "Age",
CustomControl = typeof(AgeCell),
Field = x => x.Metadata.CreationTimestamp,
Display = x => x.Metadata.CreationTimestamp?.ToString("yyyy-MM-dd HH:mm:ss"),
Width = "80"
}
};
Expand All @@ -237,6 +310,7 @@ protected override void OnPropertyChanged(PropertyChangedEventArgs e)
Name = "Containers",
CustomControl = typeof(PodContainerCell),
Field = x => x.Spec.Containers.Count + ((x.Spec.InitContainers?.Count) ?? 0),
Display = x => (x.Spec.Containers.Count + ((x.Spec.InitContainers?.Count) ?? 0)).ToString(),
Width = nameof(DataGridLengthUnitType.SizeToCells)
},
new ResourceListViewDefinitionColumn<V1Pod, string>()
Expand All @@ -249,13 +323,13 @@ protected override void OnPropertyChanged(PropertyChangedEventArgs e)
{
Name = "Restarts",
Field = x => x.Status.ContainerStatuses.Sum(x => x.RestartCount),
Display = x => x.Status?.ContainerStatuses?.Sum(x => x.RestartCount).ToString(),
Display = x => x.Status.ContainerStatuses?.Sum(x => x.RestartCount).ToString() ?? "0",
Width = nameof(DataGridLengthUnitType.SizeToHeader)
},
new ResourceListViewDefinitionColumn<V1Pod, string>()
{
Name = "Controlled By",
Field = x => x.Metadata.OwnerReferences.FirstOrDefault()?.Name,
Field = x => x.Metadata.OwnerReferences.FirstOrDefault()?.Name ?? "",
Width = nameof(DataGridLengthUnitType.SizeToHeader)
},
new ResourceListViewDefinitionColumn<V1Pod, string>()
Expand All @@ -281,6 +355,7 @@ protected override void OnPropertyChanged(PropertyChangedEventArgs e)
Name = "Age",
CustomControl = typeof(AgeCell),
Field = x => x.Metadata.CreationTimestamp,
Display = x => x.Metadata.CreationTimestamp?.ToString("yyyy-MM-dd HH:mm:ss") ?? "",
Width = "80"
}
};
Expand Down Expand Up @@ -365,14 +440,15 @@ protected override void OnPropertyChanged(PropertyChangedEventArgs e)
new ResourceListViewDefinitionColumn<V1Deployment, string>()
{
Name = "Available",
Field = x => x.Status.Conditions.FirstOrDefault(x => x.Type == "Available").Status,
Field = x => x.Status.Conditions.FirstOrDefault(x => x.Type == "Available")?.Status ?? "",
Width = nameof(DataGridLengthUnitType.SizeToHeader)
},
new ResourceListViewDefinitionColumn<V1Deployment, DateTime?>()
{
Name = "Age",
CustomControl = typeof(AgeCell),
Field = x => x.Metadata.CreationTimestamp,
Display = x => x.Metadata.CreationTimestamp?.ToString("yyyy-MM-dd HH:mm:ss") ?? "",
Width = "80"
}
};
Expand Down Expand Up @@ -411,6 +487,7 @@ protected override void OnPropertyChanged(PropertyChangedEventArgs e)
Name = "Age",
CustomControl = typeof(AgeCell),
Field = x => x.Metadata.CreationTimestamp,
Display = x => x.Metadata.CreationTimestamp?.ToString("yyyy-MM-dd HH:mm:ss") ?? "",
Width = "80"
}
};
Expand Down Expand Up @@ -446,7 +523,7 @@ protected override void OnPropertyChanged(PropertyChangedEventArgs e)
new ResourceListViewDefinitionColumn<Corev1Event, string>()
{
Name = "Source",
Field = x => x.Source.Component,
Field = x => x.Source.Component ?? "",
Width = "*"
},
new ResourceListViewDefinitionColumn<Corev1Event, int>()
Expand All @@ -461,6 +538,7 @@ protected override void OnPropertyChanged(PropertyChangedEventArgs e)
Name = "Last Seen",
CustomControl = typeof(LastSeenCell),
Field = x => x.LastTimestamp,
Display = x => x.LastTimestamp?.ToString("yyyy-MM-dd HH:mm:ss") ?? "",
Sort = SortDirection.Descending,
Width = "80"
},
Expand All @@ -469,6 +547,7 @@ protected override void OnPropertyChanged(PropertyChangedEventArgs e)
Name = "Age",
CustomControl = typeof(AgeCell),
Field = x => x.Metadata.CreationTimestamp,
Display = x => x.Metadata.CreationTimestamp?.ToString("yyyy-MM-dd HH:mm:ss") ?? "",
Width = "80"
},
};
Expand Down Expand Up @@ -625,6 +704,7 @@ protected override void OnPropertyChanged(PropertyChangedEventArgs e)
Name = "Age",
CustomControl = typeof(AgeCell),
Field = x => x.Metadata.CreationTimestamp,
Display = x => x.Metadata.CreationTimestamp?.ToString("yyyy-MM-dd HH:mm:ss") ?? "",
Width = "80"
};

Expand Down
2 changes: 1 addition & 1 deletion src/KubeUI/Views/ResourceListView.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
Grid.Column="0"
Width="200"
HorizontalAlignment="Right"
IsEnabled="False"
Text="{ReflectionBinding SearchQuery}"
Watermark="Search" />
<ComboBox
Name="Namespaces"
Expand Down
2 changes: 1 addition & 1 deletion src/KubeUI/Views/ResourceListView.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ protected override void OnDataContextChanged(EventArgs e)
{
var resourceType = typeof(T);

var definition = ((ResourceListViewModel<T>)DataContext!).GetResourceListViewDefinition<T>();
var definition = ((ResourceListViewModel<T>)DataContext!).ViewDefinitions;

Grid.Columns.Clear();

Expand Down

0 comments on commit da34447

Please sign in to comment.