1
0
mirror of git://f0xx.org/android_cast synced 2026-07-29 05:58:14 +03:00

AI: polish mobile parts

This commit is contained in:
Anton Afanasyeu
2026-05-23 17:05:31 +02:00
parent a698803d19
commit 324f64e802
18 changed files with 290 additions and 237 deletions

View File

@@ -0,0 +1,15 @@
<?php
declare(strict_types=1);
require_once __DIR__ . '/../../src/bootstrap.php';
if (!Auth::user()) {
json_out(['ok' => false, 'error' => 'unauthorized'], 401);
}
json_out([
'ok' => true,
'workflow' => TagCatalog::workflowPresets(),
'presets' => TagCatalog::editorPresets(),
'filter_mode_default' => 'and',
'filter_mode_help' => 'AND = report has all listed tags; OR = any listed tag',
]);

View File

@@ -0,0 +1,59 @@
#!/usr/bin/env bash
# Smoke-test reports list + tag edit API (session cookie after login).
#
# Usage:
# export CRASH_BASE="https://f0xx.org/app/androidcast_project/crashes"
# export CRASH_USER="admin"
# export CRASH_PASS="secret"
# ./scripts/test_tags_api.sh
#
# Or pass a browser session cookie:
# export CRASH_COOKIE="PHPSESSID=..."
# ./scripts/test_tags_api.sh
set -euo pipefail
BASE="${CRASH_BASE:-http://127.0.0.1:8080}"
COOKIE_JAR="${TMPDIR:-/tmp}/crash_api_cookies_$$.txt"
trap 'rm -f "$COOKIE_JAR"' EXIT
if [[ -z "${CRASH_COOKIE:-}" ]]; then
if [[ -z "${CRASH_USER:-}" || -z "${CRASH_PASS:-}" ]]; then
echo "Set CRASH_USER + CRASH_PASS or CRASH_COOKIE" >&2
exit 1
fi
curl -sS -c "$COOKIE_JAR" -b "$COOKIE_JAR" -X POST \
-d "username=${CRASH_USER}&password=${CRASH_PASS}" \
"${BASE}/login" -o /dev/null
CURL_AUTH=(-b "$COOKIE_JAR")
else
CURL_AUTH=(-H "Cookie: ${CRASH_COOKIE}")
fi
echo "== tag catalog =="
curl -sS "${CURL_AUTH[@]}" "${BASE}/api/tag_catalog.php" | head -c 400
echo ""
echo "== reports (first page) =="
LIST=$(curl -sS "${CURL_AUTH[@]}" "${BASE}/api/reports.php?page=1&per_page=5")
echo "$LIST" | head -c 500
echo ""
ID=$(echo "$LIST" | sed -n 's/.*"id":\([0-9][0-9]*\).*/\1/p' | head -1)
if [[ -z "$ID" ]]; then
echo "No report id in list; skip tag write test"
exit 0
fi
echo "== set tags on report #$ID (duplicate + fixed) =="
BODY='{"id":'"$ID"',"tags":[{"id":"duplicate","label":"duplicate","bg":"#6d28d9"},{"id":"fixed","label":"fixed","bg":"#047857"}]}'
curl -sS "${CURL_AUTH[@]}" -X POST -H "Content-Type: application/json" \
-d "$BODY" "${BASE}/api/report_tags.php"
echo ""
echo "== filter AND duplicate+fixed =="
curl -sS "${CURL_AUTH[@]}" \
"${BASE}/api/reports.php?tag=duplicate&tag=fixed&tag_mode=and&per_page=3" | head -c 400
echo ""
echo "OK"

View File

@@ -0,0 +1,84 @@
<?php
declare(strict_types=1);
/** Workflow triage tags — multiple labels per report allowed (e.g. duplicate + fixed). */
final class TagCatalog {
/** @var list<array{id:string,label:string,bg:string}>|null */
private static ?array $workflow = null;
/** @return list<array{id:string,label:string,bg:string}> */
public static function workflowPresets(): array {
if (self::$workflow !== null) {
return self::$workflow;
}
self::$workflow = [
['id' => 'in-progress', 'label' => 'in progress', 'bg' => '#3d8bfd'],
['id' => 'fixed', 'label' => 'fixed', 'bg' => '#047857'],
['id' => 'rejected', 'label' => 'rejected', 'bg' => '#dc2626'],
['id' => 'done', 'label' => 'done', 'bg' => '#5c6b82'],
['id' => 'not-reproducible', 'label' => 'not reproducible', 'bg' => '#d97706'],
['id' => 'not-a-bug', 'label' => 'not a bug', 'bg' => '#6b7280'],
['id' => 'duplicate', 'label' => 'duplicate', 'bg' => '#6d28d9'],
];
return self::$workflow;
}
/** @return array<string, true> */
public static function workflowIds(): array {
$map = [];
foreach (self::workflowPresets() as $tag) {
$map[$tag['id']] = true;
}
return $map;
}
public static function isWorkflowId(string $id): bool {
return isset(self::workflowIds()[$id]);
}
/**
* @param list<string> $raw from query (?tag=fixed&tag=duplicate)
* @return list<string>
*/
public static function normalizeFilterIds(array $raw): array {
$out = [];
$seen = [];
foreach ($raw as $item) {
$id = strtolower(trim((string) $item));
$id = preg_replace('/[^a-z0-9_-]+/i', '-', $id) ?? '';
$id = trim($id, '-');
if ($id === '' || strlen($id) > 32 || isset($seen[$id])) {
continue;
}
if (isset(array_flip(report_reserved_tag_ids())[$id])) {
continue;
}
$seen[$id] = true;
$out[] = $id;
if (count($out) >= 8) {
break;
}
}
return $out;
}
/**
* Workflow presets first, then distinct custom tags from DB (excluding workflow ids).
*
* @return list<array{id:string,label:string,bg:string}>
*/
public static function editorPresets(int $historicalLimit = 32): array {
$map = [];
foreach (self::workflowPresets() as $tag) {
$map[$tag['id']] = $tag;
}
foreach (ReportRepository::listTagPresets($historicalLimit + 20) as $tag) {
$id = (string) ($tag['id'] ?? '');
if ($id === '' || isset($map[$id])) {
continue;
}
$map[$id] = $tag;
}
return array_values($map);
}
}