feat: add frontend app, improve static file serving with lazy loading and root redirect
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
import 'dart:convert';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'models.dart';
|
||||
|
||||
class APIError implements Exception {
|
||||
final int statusCode;
|
||||
final String message;
|
||||
APIError(this.statusCode, this.message);
|
||||
@override
|
||||
String toString() => 'APIError $statusCode: $message';
|
||||
}
|
||||
|
||||
class APIClient {
|
||||
final String baseUrl;
|
||||
|
||||
APIClient({this.baseUrl = 'http://localhost:8000'});
|
||||
|
||||
String _url(String path) => '$baseUrl$path';
|
||||
|
||||
static dynamic _decodeBody(http.Response response) {
|
||||
return jsonDecode(response.body);
|
||||
}
|
||||
|
||||
static Map<String, dynamic>? _asMap(dynamic d) {
|
||||
if (d is Map<String, dynamic>) return d;
|
||||
if (d is Map) return d.cast<String, dynamic>();
|
||||
return null;
|
||||
}
|
||||
|
||||
static void _checkError(http.Response response) {
|
||||
if (response.statusCode >= 400) {
|
||||
final body = _decodeBody(response);
|
||||
final map = _asMap(body) ?? {};
|
||||
throw APIError(
|
||||
response.statusCode,
|
||||
map['error'] as String? ?? 'Request failed',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<Pipeline>> listPipelines() async {
|
||||
final res = await http.get(Uri.parse(_url('/api/pipelines')));
|
||||
_checkError(res);
|
||||
final data = _decodeBody(res);
|
||||
final arr = data is List ? data : [];
|
||||
final result = <Pipeline>[];
|
||||
for (final e in arr) {
|
||||
final m = _asMap(e);
|
||||
if (m != null) result.add(Pipeline.fromJson(m));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Future<Pipeline> getPipeline(String id) async {
|
||||
final res = await http.get(Uri.parse(_url('/api/pipelines/$id')));
|
||||
_checkError(res);
|
||||
final data = _decodeBody(res);
|
||||
final map = _asMap(data) ?? {};
|
||||
final inner = _asMap(map['data']) ?? map;
|
||||
return Pipeline.fromJson(inner);
|
||||
}
|
||||
|
||||
Future<Pipeline> createPipeline(Pipeline pipeline) async {
|
||||
final res = await http.post(
|
||||
Uri.parse(_url('/api/pipelines')),
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: jsonEncode(pipeline.toJson()),
|
||||
);
|
||||
_checkError(res);
|
||||
final data = _decodeBody(res);
|
||||
final map = _asMap(data) ?? {};
|
||||
final inner = _asMap(map['data']) ?? map;
|
||||
return Pipeline.fromJson(inner);
|
||||
}
|
||||
|
||||
Future<void> deletePipeline(String id) async {
|
||||
final res = await http.delete(Uri.parse(_url('/api/pipelines/$id')));
|
||||
_checkError(res);
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> startRun(String pipelineId) async {
|
||||
final res = await http.post(
|
||||
Uri.parse(_url('/api/runs')),
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: jsonEncode({'pipeline_id': pipelineId}),
|
||||
);
|
||||
_checkError(res);
|
||||
final data = _decodeBody(res);
|
||||
final map = _asMap(data) ?? {};
|
||||
return _asMap(map['data']) ?? map;
|
||||
}
|
||||
|
||||
Future<RunState> getRunStatus(String runId) async {
|
||||
final res = await http.get(Uri.parse(_url('/api/runs/$runId/status')));
|
||||
_checkError(res);
|
||||
final data = _decodeBody(res);
|
||||
final map = _asMap(data) ?? {};
|
||||
final inner = _asMap(map['data']) ?? map;
|
||||
return RunState.fromJson(inner);
|
||||
}
|
||||
|
||||
Future<String> getRunLog(String runId) async {
|
||||
final res = await http.get(Uri.parse(_url('/api/runs/$runId/log')));
|
||||
_checkError(res);
|
||||
return res.body;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user