feat(knowledge): add KnowledgeApi, KnowledgeRepository, wire providers

This commit is contained in:
2026-04-04 23:39:43 -04:00
parent 2920252f13
commit deec2318f7
3 changed files with 129 additions and 0 deletions
+86
View File
@@ -0,0 +1,86 @@
import 'package:dio/dio.dart';
import '../models/knowledge_item.dart';
import 'api_client.dart';
class KnowledgeApi {
final Dio _dio;
const KnowledgeApi(this._dio);
/// Fetch a page of IDs. Returns (ids, total).
Future<(List<int>, int)> fetchIds({
String? noteType,
List<String> tags = const [],
String sort = 'modified',
String? q,
int limit = 50,
int offset = 0,
}) async {
try {
final params = <String, dynamic>{
'limit': limit,
'offset': offset,
'sort': sort,
if (noteType != null) 'type': noteType,
if (tags.isNotEmpty) 'tags': tags.join(','),
if (q != null && q.isNotEmpty) 'q': q,
};
final response =
await _dio.get('/api/knowledge/ids', queryParameters: params);
final data = response.data as Map<String, dynamic>;
final ids =
(data['ids'] as List<dynamic>).map((e) => e as int).toList();
final total = data['total'] as int;
return (ids, total);
} on DioException catch (e) {
throw dioToApp(e);
}
}
/// Batch-hydrate up to 100 IDs into full items.
Future<List<KnowledgeItem>> fetchBatch(List<int> ids) async {
if (ids.isEmpty) return [];
try {
final response = await _dio.get(
'/api/knowledge/batch',
queryParameters: {'ids': ids.join(',')},
);
final data = response.data as Map<String, dynamic>;
return (data['items'] as List<dynamic>)
.map((e) => KnowledgeItem.fromJson(e as Map<String, dynamic>))
.toList();
} on DioException catch (e) {
throw dioToApp(e);
}
}
/// Per-type counts for tab labels.
Future<Map<String, int>> fetchCounts({List<String> tags = const []}) async {
try {
final params = <String, dynamic>{
if (tags.isNotEmpty) 'tags': tags.join(','),
};
final response = await _dio.get('/api/knowledge/counts',
queryParameters: params);
return (response.data as Map<String, dynamic>)
.map((k, v) => MapEntry(k, (v as num).toInt()));
} on DioException catch (e) {
throw dioToApp(e);
}
}
/// All tags for the current type filter.
Future<List<String>> fetchTags({String? noteType}) async {
try {
final response = await _dio.get(
'/api/knowledge/tags',
queryParameters: {if (noteType != null) 'type': noteType},
);
return (response.data['tags'] as List<dynamic>)
.map((e) => e as String)
.toList();
} on DioException catch (e) {
throw dioToApp(e);
}
}
}
@@ -0,0 +1,33 @@
import '../api/knowledge_api.dart';
import '../models/knowledge_item.dart';
class KnowledgeRepository {
final KnowledgeApi _api;
const KnowledgeRepository(this._api);
Future<(List<int>, int)> fetchIds({
String? noteType,
List<String> tags = const [],
String sort = 'modified',
String? q,
int limit = 50,
int offset = 0,
}) =>
_api.fetchIds(
noteType: noteType,
tags: tags,
sort: sort,
q: q,
limit: limit,
offset: offset,
);
Future<List<KnowledgeItem>> fetchBatch(List<int> ids) =>
_api.fetchBatch(ids);
Future<Map<String, int>> fetchCounts({List<String> tags = const []}) =>
_api.fetchCounts(tags: tags);
Future<List<String>> fetchTags({String? noteType}) =>
_api.fetchTags(noteType: noteType);
}
+10
View File
@@ -6,6 +6,7 @@ import '../data/api/api_client.dart';
import '../data/api/auth_api.dart';
import '../data/api/briefing_api.dart';
import '../data/api/chat_api.dart';
import '../data/api/knowledge_api.dart';
import '../data/api/milestones_api.dart';
import '../data/api/notes_api.dart';
import '../data/api/projects_api.dart';
@@ -14,6 +15,7 @@ import '../data/api/settings_api.dart';
import '../data/api/tasks_api.dart';
import '../data/repositories/auth_repository.dart';
import '../data/repositories/chat_repository.dart';
import '../data/repositories/knowledge_repository.dart';
import '../data/repositories/milestones_repository.dart';
import '../data/repositories/notes_repository.dart';
import '../data/repositories/projects_repository.dart';
@@ -83,6 +85,14 @@ final milestonesRepositoryProvider = Provider<MilestonesRepository>((ref) {
return MilestonesRepository(ref.watch(milestonesApiProvider));
});
final knowledgeApiProvider = Provider<KnowledgeApi>((ref) {
return KnowledgeApi(ref.watch(dioProvider));
});
final knowledgeRepositoryProvider = Provider<KnowledgeRepository>((ref) {
return KnowledgeRepository(ref.watch(knowledgeApiProvider));
});
final briefingApiProvider = Provider<BriefingApi>((ref) {
return BriefingApi(ref.watch(dioProvider));
});