From 6182c38366812a0e2ed3c701b1bccd1316a62d17 Mon Sep 17 00:00:00 2001 From: tech Date: Wed, 4 Mar 2026 20:16:53 +0800 Subject: [PATCH] docs: add design document for enhanced download UI Add comprehensive design document for project aliases and APK environment classification feature. Co-Authored-By: Claude Sonnet 4.6 --- .../2026-03-04-enhance-download-ui-design.md | 192 ++++++++++++++++++ 1 file changed, 192 insertions(+) create mode 100644 docs/plans/2026-03-04-enhance-download-ui-design.md diff --git a/docs/plans/2026-03-04-enhance-download-ui-design.md b/docs/plans/2026-03-04-enhance-download-ui-design.md new file mode 100644 index 0000000..af70256 --- /dev/null +++ b/docs/plans/2026-03-04-enhance-download-ui-design.md @@ -0,0 +1,192 @@ +# Design: Enhanced Download UI Readability + +**Date:** 2026-03-04 +**Status:** Approved + +## Overview + +Enhance the download UI to improve readability by: +1. Displaying project aliases instead of directory names +2. Classifying APKs by environment (dev, sandbox, product, other) +3. Displaying APKs in a list format with commit ID, file size, and creation time +4. Organizing APKs into tabs by environment + +## Requirements + +### Project Aliases +- Store project display name mappings in `lib/project-aliases.json` +- Example: `FT` → `外放构建`, `FT_DEV` → `开发构建` +- Fallback: Display directory name if no alias exists + +### APK Classification +- Categories: `dev`, `sandbox`, `product`, `other` +- APK filename format: `ft_[environment]_[version]_[commit_id].apk` +- Environment suffix is optional; if missing, default to `product` +- Unmatched formats go to `other` tab + +### Display Format +- List view with columns: Commit ID, File Size, Creation Time, Download +- Always display all 4 tabs (dev, product, sandbox, other) +- Commit filter applies globally to all tabs + +## Architecture + +### New Files +- `lib/project-aliases.json` - Project name alias configuration +- `lib/apk-parser.ts` - APK filename parsing utilities + +### Modified Files +- `lib/utils.ts` - Add alias lookup utility +- `app/api/projects/route.ts` - Return projects with aliases +- `app/api/apks/route.ts` - Add environment metadata to response +- `app/download/SearchForm.tsx` - Use project aliases in dropdown +- `app/download/ApkList.tsx` - Replace card grid with tabbed list view + +### Data Flow + +1. **Project Selection:** + - Client loads projects → API reads `project-aliases.json` → returns with display names + - `SearchForm` displays `displayName`, submits `name` to API + +2. **APK Fetching:** + - User selects project/version → client fetches APKs + - API uses `parseApkFilename()` to extract environment + - Returns enriched APKs with `environment` field + +3. **Display:** + - Client receives APKs with `environment` field + - Organizes into tabs (dev, product, sandbox, other) + - Displays in list format + +## Data Structures + +### APK Parser Types +```typescript +export type ApkEnvironment = 'dev' | 'sandbox' | 'product' | 'other'; + +export interface ParsedApkMetadata { + environment: ApkEnvironment; + commit: string | null; + isValid: boolean; +} +``` + +### Project Alias Config +```json +{ + "FT": "外放构建", + "FT_DEV": "开发构建" +} +``` + +### Enriched APK Response +```typescript +{ + name: string; + environment: ApkEnvironment; + commit: string | null; + size: number; + modifiedAt: string; // ISO string + downloadUrl: string; +} +``` + +## Components + +### ApkList (Restructured) +- Replaces grid of `ApkCard` with tabbed list view +- Manages tab state (active tab, filtered APKs) +- Handles commit filter globally +- Delegates list display to `ApkTable` component + +### ApkTable (New) +- Table with columns: Commit ID, File Size, Creation Time, Download +- Styled with hover effects +- Empty state handling per tab + +### SearchForm (Updated) +- Uses `getProjectDisplayName()` for project dropdown +- Maintains existing functionality + +## Error Handling + +### Project Alias Edge Cases +- Missing alias file: Fallback to directory names +- Project not in aliases: Display directory name +- Malformed JSON: Log error, fallback to directory names + +### APK Filename Parsing Edge Cases +- No environment in filename: Default to `product` +- No commit ID: `commit` field is `null` +- Unmatched format: `environment: "other"`, still display +- Invalid characters: Handle gracefully + +### UI Edge Cases +- Empty tab: Display "暂无 APK 文件" +- All tabs empty: Show helpful message +- Loading state: Skeleton or spinner +- API error: Display error message, allow retry + +## APK Filename Parsing Logic + +### Regex Pattern +```typescript +const APK_PATTERN = /^ft_([a-z]+)?_([0-9_]+)_([a-f0-9]{7,})\.apk$/; +// ^^^ ^^^^^^ ^^^^^^^^^ ^^^^^^^^^^^^ +// ft env(opt) version commit id +``` + +### Parsing Rules +1. Try to match standard pattern: `ft_[env]_[version]_[commit].apk` +2. Extract environment if present, otherwise default to `product` +3. If pattern doesn't match, assign `environment: "other"` +4. Extract commit ID from filename +5. Use file system metadata for size and modified time + +## Testing Strategy + +### Unit Tests +- `lib/__tests__/apk-parser.test.ts`: Test filename parsing for all environments +- `lib/__tests__/project-aliases.test.ts`: Test alias lookup logic + +### Integration Tests +- API tests for `/api/projects` with alias data +- API tests for `/api/apks` returning enriched metadata + +### Component Tests +- `ApkTable`: Renders correct columns, handles empty states +- `ApkList`: Tabs work correctly, filters apply globally +- `SearchForm`: Displays project aliases correctly + +### Manual Testing Checklist +- [ ] Projects display with aliases (FT → 外放构建) +- [ ] Projects without aliases show directory names +- [ ] APKs grouped correctly in 4 tabs +- [ ] Product APKs (no env suffix) go to "product" tab +- [ ] Dev/sandbox APKs go to correct tabs +- [ ] Invalid format APKs go to "other" tab +- [ ] Commit filter applies to all tabs +- [ ] List shows Commit ID, File Size, Creation Time +- [ ] Download button works correctly + +## Implementation Approach + +**Selected:** Approach 2 - Shared Utility Functions + Client-side Organization + +**Why:** +- Clean separation of concerns +- Reusable parsing utilities +- Type-safe with TypeScript +- Easier to unit test parsing logic +- Client receives all APKs once, then handles tab organization +- Performance overhead is minimal for this use case + +## Success Criteria + +1. Project aliases display correctly in dropdown +2. APKs are correctly classified by environment +3. All 4 tabs display correctly (dev, product, sandbox, other) +4. List view shows correct columns (Commit ID, File Size, Creation Time) +5. Commit filter works globally across all tabs +6. Edge cases handled gracefully (missing aliases, invalid formats) +7. All tests pass