1
0
mirror of git://f0xx.org/android_cast synced 2026-07-29 04:38:53 +03:00

sync with BE / AI request

This commit is contained in:
Anton Afanasyeu
2026-06-04 22:30:03 +02:00
parent 44bdfbb939
commit 9eca43b9f8
10 changed files with 124 additions and 17 deletions

View File

@@ -11,7 +11,7 @@
* Digest: SHA256 fcd4a89ef4201736923d0e7e1ad88868bba7e39eadb9fcf0ffb9d1ba7efecd12
*/
return [
'app_name' => 'Android Cast Crashes',
'app_name' => 'Android Cast Issues',
// Production: '/app/androidcast_project/crashes' — Local php -S: use '' (empty string)
'base_path' => '/app/androidcast_project/crashes',
'db' => [

View File

@@ -1,7 +1,7 @@
{
"app_name": "Android Cast Crashes",
"app_name": "Android Cast Issues",
"nav.home": "Home",
"nav.reports": "Reports",
"nav.reports": "Issues",
"nav.tickets": "Tickets",
"nav.logout": "Logout",
"nav.toggle": "Navigation",
@@ -11,12 +11,12 @@
"lang.label": "Language",
"lang.en": "English",
"lang.ru": "Russian",
"home.title": "Crash console",
"home.title": "Issues console",
"home.intro": "Anonymous Android Cast crash ingest is active. Use Reports to analyze grouped fingerprints.",
"home.upload_api": "Upload API:",
"home.schema": "Schema:",
"home.ticket_upload_api": "Ticket upload API:",
"reports.title": "Crash reports",
"reports.title": "Issues",
"reports.by_time": "By time",
"reports.grouped": "Grouped",
"reports.per_page": "Per page",

View File

@@ -1,7 +1,7 @@
{
"app_name": "Сбои Android Cast",
"nav.home": "Главная",
"nav.reports": "Отчёты",
"nav.reports": "Задачи (Issues)",
"nav.tickets": "Задачи",
"tickets.title": "Задачи",
"tickets.empty": "Задач пока нет.",
@@ -18,7 +18,7 @@
"home.intro": "Приём анонимных отчётов Android Cast активен. Откройте «Отчёты» для анализа сгруппированных отпечатков.",
"home.upload_api": "API загрузки:",
"home.schema": "Схема:",
"reports.title": "Отчёты о сбоях",
"reports.title": "Issues",
"reports.by_time": "По времени",
"reports.grouped": "Группы",
"reports.per_page": "На странице",

View File

@@ -209,7 +209,7 @@ $pageTitle = match ($view) {
'graphs' => 'Graphs',
'remote_access' => 'Remote access',
'rbac' => 'Access control',
'reports', 'report' => 'Crash reports',
'reports', 'report' => 'Issues',
default => 'Console',
};
require __DIR__ . '/../views/layout.php';

View File

@@ -0,0 +1,111 @@
#!/usr/bin/env php
<?php
/**
* Ingest roadmap tasks as tickets tagged 20260604 (filter in Tickets UI).
*
* Usage:
* php scripts/ingest_roadmap_tickets_20260604.php [--url=BASE] [--owner=admin] [--dry-run]
*/
declare(strict_types=1);
$opts = getopt('', ['url::', 'owner::', 'dry-run']);
$base = rtrim($opts['url'] ?? 'https://apps.f0xx.org/app/androidcast_project/crashes', '/');
$owner = $opts['owner'] ?? 'admin';
$dryRun = isset($opts['dry-run']);
$uploadUrl = $base . '/api/ticket_upload.php';
/** @return list<array{id:string,label:string,bg:string}> */
function roadmap_tags(string $status): array {
$statusMap = [
'open' => ['id' => 'open', 'label' => 'open', 'bg' => '#22c55e'],
'in-progress' => ['id' => 'in-progress', 'label' => 'in progress', 'bg' => '#3b82f6'],
'closed' => ['id' => 'closed', 'label' => 'closed', 'bg' => '#6b7280'],
];
return [
['id' => 'ticket', 'label' => 'ticket', 'bg' => '#6366f1'],
['id' => '20260604', 'label' => '20260604', 'bg' => '#0ea5e9'],
$statusMap[$status] ?? $statusMap['open'],
];
}
/** title + body are the same description text */
$tasks = [
['key' => 'bug-ticket-detail-500', 'status' => 'closed', 'text' => 'ISSUE: Ticket detail page HTTP 500 (?view=ticket&id=N). Fix recursion in comment/attachment loaders when rendering detail.'],
['key' => '8', 'status' => 'closed', 'text' => 'COMPLETED: Orchestration branch feature/20260527_orchestration — merged to next; work lives under orchestration/; close/delete branch.'],
['key' => '1', 'status' => 'open', 'text' => 'BE/builder deployment phases — dedicated services on BE; WIP verifying (Docker, out/builds, runner_script).'],
['key' => '2', 'status' => 'open', 'text' => 'OTA checks — part of builder/deploy path; verify artifacts and device OTA flow.'],
['key' => '3', 'status' => 'open', 'text' => 'Opus/Speex validation — E2E, encryption, FEC, NACK, negotiations; user and developer controls.'],
['key' => '4', 'status' => 'open', 'text' => 'RSSH/WG (WireGuard v1) — finish deploy, prod validations, minimal tests; RA E2E CLI + Android poll.'],
['key' => '5', 'status' => 'open', 'text' => 'Data visualization / graphs — WIP; issues found on drill-down and layout.'],
['key' => '5.1', 'status' => 'open', 'text' => 'ISSUE 5.1: Graph brick click must open full-browser detailed chart (axis, legend, hover per point like Java visualizer).'],
['key' => '5.2', 'status' => 'open', 'text' => 'REQUIREMENT 5.2: All graph preview bricks clickable; Columns combo (1/2/4) after Window default 2; grid uses full width.'],
['key' => '5.3', 'status' => 'closed', 'text' => 'ISSUE 5.3: Remove Direct DB metrics / graph_upload / graphs.php footnote from graphs page.'],
['key' => '6', 'status' => 'open', 'text' => 'Landing page checks, fixes, improvements — hub, styling, integration with dashboards.'],
['key' => '6.1', 'status' => 'open', 'text' => 'Landing 6.1: Hub dashboards for graphs, builder, remote access — partially done.'],
['key' => '6.1.1', 'status' => 'closed', 'text' => 'ISSUE 6.1.1: Remote access / graphs quick links — shell nav icons and 8px spacing.'],
['key' => '6.1.2', 'status' => 'closed', 'text' => 'ISSUE 6.1.2: Remove device poll / heartbeat dev footnote from Remote access page.'],
['key' => '6.2', 'status' => 'open', 'text' => 'Landing 6.2: Globe/earth animations — choose base on next; branch cleanup (3d_earth vs 20260531_globe_animation); clock/footer styling.'],
['key' => '6.3', 'status' => 'open', 'text' => 'Landing 6.3: Mobile device validations (mobile chrome) — LOW priority.'],
['key' => '7', 'status' => 'open', 'text' => 'BE roles RBAC — admin/root, slug admins, privilege sets; finish after related pages stable.'],
['key' => 'net-slowness', 'status' => 'open', 'text' => 'ISSUE: Sporadic FE/BE slowness (SSH, sshfs, web) — WAN/modem queueing suspected; investigate bufferbloat and paths.'],
];
$device = [
'manufacturer' => 'roadmap',
'model' => 'planning',
'sdk_int' => 34,
'release' => '14',
];
$app = ['package' => 'com.foxx.androidcast', 'version_name' => 'roadmap', 'version_code' => 1];
$now = (int) round(microtime(true) * 1000);
$ok = 0;
$fail = 0;
foreach ($tasks as $task) {
$text = trim($task['text']);
$key = $task['key'];
$status = $task['status'];
$payload = [
'schema_version' => 1,
'ingest_kind' => 'ticket',
'ticket_id' => 'roadmap-20260604-' . preg_replace('/[^a-z0-9.-]+/i', '-', $key),
'title' => mb_substr($text, 0, 256),
'brief' => mb_substr($text, 0, 512),
'body' => $text,
'opened_at_epoch_ms' => $now,
'rating' => $status === 'closed' ? 1 : 3,
'owner' => $owner,
'tags' => roadmap_tags($status),
'device' => $device,
'app' => $app,
];
$json = json_encode($payload, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
if ($dryRun) {
echo "DRY {$key} [{$status}]\n";
$ok++;
continue;
}
$ctx = stream_context_create([
'http' => [
'method' => 'POST',
'header' => "Content-Type: application/json\r\n",
'content' => $json,
'ignore_errors' => true,
],
]);
$resp = @file_get_contents($uploadUrl, false, $ctx);
$code = 0;
if (isset($http_response_header[0]) && preg_match('/\s(\d{3})\s/', $http_response_header[0], $m)) {
$code = (int) $m[1];
}
if ($code === 200 || $code === 409) {
echo ($code === 409 ? 'DUP ' : 'OK ') . "{$key}\n";
$ok++;
} else {
echo "FAIL {$key} HTTP {$code}{$resp}\n";
$fail++;
}
}
echo "Done: ok={$ok} fail={$fail}\n";
exit($fail > 0 ? 1 : 0);

View File

@@ -22,9 +22,7 @@ final class TicketAttachmentRepository {
}
public static function listForTicket(int $ticketId): array {
if (!TicketRepository::getById($ticketId)) {
return [];
}
// Do not call TicketRepository::getById here — avoids recursion from mapDetailRow.
$pdo = Database::pdo();
$stmt = $pdo->prepare(
'SELECT * FROM ticket_attachments WHERE ticket_id = ? ORDER BY created_at_ms ASC, id ASC'

View File

@@ -3,10 +3,7 @@ declare(strict_types=1);
final class TicketCommentRepository {
public static function listForTicket(int $ticketId): array {
$ticket = TicketRepository::getById($ticketId);
if (!$ticket) {
return [];
}
// Do not call TicketRepository::getById here — mapDetailRow already loads comments.
$pdo = Database::pdo();
$stmt = $pdo->prepare(
'SELECT id, ticket_id, author_username, body, created_at_ms, updated_at_ms

View File

@@ -202,6 +202,7 @@
<option value="confirmed">confirmed</option>
<option value="closed">closed</option>
<option value="urgent">urgent</option>
<option value="20260604">20260604 (roadmap)</option>
</select>
</label>
</div>

View File

@@ -9,7 +9,7 @@ $proj = '/app/androidcast_project';
$navClass = 'console-quick-links graphs-quick-links' . (isset($extra_class) ? ' ' . $extra_class : '');
$items = [
['Console home', $bp . '/?view=home', 'nav-icon--home'],
['Crash reports', $bp . '/?view=reports', 'nav-icon--reports'],
['Issues', $bp . '/?view=reports', 'nav-icon--reports'],
['Tickets', $bp . '/?view=tickets', 'nav-icon--tickets'],
['Graphs', $proj . '/graphs/', 'nav-icon--graphs'],
['Builder', $proj . '/build/', 'nav-icon--builder'],

View File

@@ -4,7 +4,7 @@ $p = is_array($ticket['payload'] ?? null) ? $ticket['payload'] : [];
$device = is_array($p['device'] ?? null) ? $p['device'] : [];
$app = is_array($p['app'] ?? null) ? $p['app'] : [];
$pageTitle = 'Ticket';
$view = 'tickets';
$view = 'ticket';
$jsonFlags = JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE;
$rawJson = safe_json_encode($p, $jsonFlags);
$bp = Auth::basePath();