Features: - Health check endpoint for Portainer monitoring - Local search filtering in DataGrid - Container status badges reflect health (green/orange/blue) Improvements: - Standardized 56px header heights across panels - Container grid parses Docker API format correctly - Search bar styling improvements - Status badges have consistent width Fixes: - Quick links persistence (link type, form refresh) - Iframe switching closes existing content first - ContainerState type conflict resolved Branding: - Updated favicon and icons with Tatlock bucket logo 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.5
parent
0d15d3dbb5
commit
bdced8739c
@@ -35,6 +35,9 @@ class DataGridController<T> extends StateNotifier<DataGridState<T>> {
|
||||
/// Debounce timer for search.
|
||||
Timer? _searchDebounce;
|
||||
|
||||
/// All items before local filtering (for local search).
|
||||
List<T> _allItems = [];
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_searchDebounce?.cancel();
|
||||
@@ -57,16 +60,21 @@ class DataGridController<T> extends StateNotifier<DataGridState<T>> {
|
||||
final (offset, limit) = _getPaginationParams();
|
||||
|
||||
final result = await source.fetch(
|
||||
searchQuery: state.searchQuery.isEmpty ? null : state.searchQuery,
|
||||
sortField: sortField,
|
||||
sortDescending: state.sortDescending,
|
||||
offset: offset,
|
||||
limit: limit,
|
||||
);
|
||||
|
||||
// Store all items for local filtering
|
||||
_allItems = result.items;
|
||||
|
||||
// Apply local filter if search query exists
|
||||
final filteredItems = _applyLocalFilter(_allItems);
|
||||
|
||||
state = state.copyWith(
|
||||
items: result.items,
|
||||
totalCount: result.totalCount,
|
||||
items: filteredItems,
|
||||
totalCount: filteredItems.length,
|
||||
hasMore: result.hasMore,
|
||||
isLoading: false,
|
||||
isInitialLoad: false,
|
||||
@@ -82,6 +90,26 @@ class DataGridController<T> extends StateNotifier<DataGridState<T>> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Applies local filtering based on search query.
|
||||
List<T> _applyLocalFilter(List<T> items) {
|
||||
if (state.searchQuery.isEmpty) return items;
|
||||
|
||||
final query = state.searchQuery.toLowerCase();
|
||||
|
||||
return items.where((item) {
|
||||
// Check all searchable columns
|
||||
for (final column in config.columns) {
|
||||
if (column.searchable) {
|
||||
final value = column.valueBuilder(item);
|
||||
if (value.toLowerCase().contains(query)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}).toList();
|
||||
}
|
||||
|
||||
/// Gets pagination parameters based on data mode.
|
||||
(int?, int?) _getPaginationParams() {
|
||||
return switch (config.dataMode) {
|
||||
@@ -97,13 +125,13 @@ class DataGridController<T> extends StateNotifier<DataGridState<T>> {
|
||||
/// Refreshes the grid data.
|
||||
Future<void> refresh() => _load(refresh: true);
|
||||
|
||||
/// Sets the search query with debouncing.
|
||||
/// Sets the search query with debouncing (filters locally).
|
||||
void search(String query) {
|
||||
_searchDebounce?.cancel();
|
||||
_searchDebounce = Timer(const Duration(milliseconds: 300), () {
|
||||
_searchDebounce = Timer(const Duration(milliseconds: 150), () {
|
||||
if (state.searchQuery != query) {
|
||||
state = state.copyWith(searchQuery: query, currentPage: 0);
|
||||
_load(refresh: true);
|
||||
_applyFilterAndUpdateState();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -113,10 +141,19 @@ class DataGridController<T> extends StateNotifier<DataGridState<T>> {
|
||||
_searchDebounce?.cancel();
|
||||
if (state.searchQuery.isNotEmpty) {
|
||||
state = state.copyWith(searchQuery: '', currentPage: 0);
|
||||
_load(refresh: true);
|
||||
_applyFilterAndUpdateState();
|
||||
}
|
||||
}
|
||||
|
||||
/// Applies local filter and updates state with filtered items.
|
||||
void _applyFilterAndUpdateState() {
|
||||
final filteredItems = _applyLocalFilter(_allItems);
|
||||
state = state.copyWith(
|
||||
items: filteredItems,
|
||||
totalCount: filteredItems.length,
|
||||
);
|
||||
}
|
||||
|
||||
/// Sorts by the given column index.
|
||||
void sortBy(int columnIndex) {
|
||||
final column = config.columns[columnIndex];
|
||||
|
||||
Reference in New Issue
Block a user