Fix dropdown menu duplicates and reorder items
- Fix CSS breakpoints to sync header tabs with dropdown menu visibility - Add missing apps (docs, sheet, slides, social) to hide/show logic - Remove incorrect paper breakpoint (not in header tabs) - Reorder dropdown: dynamic items first (header tab apps), then static items - Move People after dynamic items (after social) - Remove duplicate Social entry from dropdown menu - All 26 suite app folders have menu entries (no orphans)
This commit is contained in:
parent
a0817363c4
commit
03ced8e327
5 changed files with 49 additions and 177 deletions
49
PROMPT.md
49
PROMPT.md
|
|
@ -219,9 +219,9 @@ match x {
|
||||||
```
|
```
|
||||||
gb/
|
gb/
|
||||||
├── botapp/ # Desktop app (Tauri)
|
├── botapp/ # Desktop app (Tauri)
|
||||||
├── botserver/ # Main server (Axum API)
|
├── botserver/ # Main server (Axum API) - port 8088
|
||||||
├── botlib/ # Shared library
|
├── botlib/ # Shared library
|
||||||
├── botui/ # Web UI
|
├── botui/ # Web UI server - port 3000
|
||||||
├── botbook/ # Documentation
|
├── botbook/ # Documentation
|
||||||
├── bottest/ # Integration tests
|
├── bottest/ # Integration tests
|
||||||
└── PROMPT.md # THIS FILE
|
└── PROMPT.md # THIS FILE
|
||||||
|
|
@ -229,6 +229,51 @@ gb/
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 🖥️ UI Architecture (botui + botserver)
|
||||||
|
|
||||||
|
### Two Servers During Development
|
||||||
|
|
||||||
|
| Server | Port | Purpose |
|
||||||
|
|--------|------|---------|
|
||||||
|
| **botui** | 3000 | Serves UI files + proxies API to botserver |
|
||||||
|
| **botserver** | 8088 | Backend API + embedded UI fallback |
|
||||||
|
|
||||||
|
### How It Works
|
||||||
|
|
||||||
|
```
|
||||||
|
Browser → localhost:3000 → botui (serves HTML/CSS/JS)
|
||||||
|
→ /api/* proxied to botserver:8088
|
||||||
|
→ /suite/* served from botui/ui/suite/
|
||||||
|
```
|
||||||
|
|
||||||
|
### Adding New Suite Apps
|
||||||
|
|
||||||
|
When adding a new app (e.g., `video`, `learn`):
|
||||||
|
|
||||||
|
1. Create folder: `botui/ui/suite/<appname>/`
|
||||||
|
2. Add to `SUITE_DIRS` in `botui/src/ui_server/mod.rs`:
|
||||||
|
```rust
|
||||||
|
const SUITE_DIRS: &[&str] = &[
|
||||||
|
"chat", "mail", "calendar", ...,
|
||||||
|
"video", // ← add new app here
|
||||||
|
"learn",
|
||||||
|
];
|
||||||
|
```
|
||||||
|
3. Rebuild botui: `cargo build -p botui`
|
||||||
|
4. Add menu entry in `botui/ui/suite/index.html`
|
||||||
|
|
||||||
|
### Hot Reload
|
||||||
|
|
||||||
|
- **UI files (HTML/CSS/JS)**: Edit & refresh browser (no restart)
|
||||||
|
- **botui Rust code**: Rebuild + restart botui
|
||||||
|
- **botserver Rust code**: Rebuild + restart botserver
|
||||||
|
|
||||||
|
### Production (Single Binary)
|
||||||
|
|
||||||
|
When `botui/ui/suite/` folder not found, botserver uses **embedded UI** compiled into binary via `rust-embed`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## 🚀 OFFLINE ERROR FIXING WORKFLOW
|
## 🚀 OFFLINE ERROR FIXING WORKFLOW
|
||||||
|
|
||||||
### Step 1: Analyze Error List
|
### Step 1: Analyze Error List
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit a8444f0d2400f60d966341c59a7a3df4577c69d2
|
Subproject commit 1b0a5cbec7f4a0e8576757f36d04a89c80f9406a
|
||||||
2
botui
2
botui
|
|
@ -1 +1 @@
|
||||||
Subproject commit cb33a75d39f2cf53de952622f72e8e6ef4ea0690
|
Subproject commit 80c91f63046dd5d11e2874bb355ec2d967a70b55
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
{
|
|
||||||
"base_url": "http://localhost:8300",
|
|
||||||
"default_org": {
|
|
||||||
"id": "353226116074307598",
|
|
||||||
"name": "default",
|
|
||||||
"domain": "default.localhost"
|
|
||||||
},
|
|
||||||
"default_user": {
|
|
||||||
"id": "admin",
|
|
||||||
"username": "admin",
|
|
||||||
"email": "admin@localhost",
|
|
||||||
"password": "",
|
|
||||||
"first_name": "Admin",
|
|
||||||
"last_name": "User"
|
|
||||||
},
|
|
||||||
"admin_token": "XzjmsXoVy7mDKK8gyWtJNp3w3enVW3EKGPdfLbz0nX9vMsDpg27UtAROOcKMXsoc0fDwv98",
|
|
||||||
"project_id": "",
|
|
||||||
"client_id": "353226118456737806",
|
|
||||||
"client_secret": "5uH0r2elIQ3xji4N4aTOARZjEDDUWC0cfIybGaFkvhwlA6gvygMHOdmodVg4K6PJ"
|
|
||||||
}
|
|
||||||
|
|
@ -1,153 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
LOCALES_DIR="${1:-locales}"
|
|
||||||
BASE_LOCALE="${2:-en}"
|
|
||||||
|
|
||||||
RED='\033[0;31m'
|
|
||||||
GREEN='\033[0;32m'
|
|
||||||
YELLOW='\033[1;33m'
|
|
||||||
NC='\033[0m'
|
|
||||||
|
|
||||||
if [ ! -d "$LOCALES_DIR" ]; then
|
|
||||||
echo -e "${RED}Error: Locales directory not found: $LOCALES_DIR${NC}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! -d "$LOCALES_DIR/$BASE_LOCALE" ]; then
|
|
||||||
echo -e "${RED}Error: Base locale not found: $LOCALES_DIR/$BASE_LOCALE${NC}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
extract_keys() {
|
|
||||||
local file="$1"
|
|
||||||
grep -E '^[a-z][a-z0-9-]*\s*=' "$file" 2>/dev/null | cut -d'=' -f1 | tr -d ' ' | sort -u
|
|
||||||
}
|
|
||||||
|
|
||||||
count_keys() {
|
|
||||||
local dir="$1"
|
|
||||||
local count=0
|
|
||||||
for file in "$dir"/*.ftl; do
|
|
||||||
if [ -f "$file" ]; then
|
|
||||||
local file_count
|
|
||||||
file_count=$(extract_keys "$file" | wc -l)
|
|
||||||
count=$((count + file_count))
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
echo "$count"
|
|
||||||
}
|
|
||||||
|
|
||||||
echo "========================================"
|
|
||||||
echo " General Bots i18n Coverage Report"
|
|
||||||
echo "========================================"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
base_count=$(count_keys "$LOCALES_DIR/$BASE_LOCALE")
|
|
||||||
echo -e "Base locale: ${GREEN}$BASE_LOCALE${NC} ($base_count keys)"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
declare -A all_base_keys
|
|
||||||
for file in "$LOCALES_DIR/$BASE_LOCALE"/*.ftl; do
|
|
||||||
if [ -f "$file" ]; then
|
|
||||||
filename=$(basename "$file")
|
|
||||||
while IFS= read -r key; do
|
|
||||||
all_base_keys["$filename:$key"]=1
|
|
||||||
done < <(extract_keys "$file")
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
total_missing=0
|
|
||||||
total_extra=0
|
|
||||||
|
|
||||||
for locale_dir in "$LOCALES_DIR"/*/; do
|
|
||||||
locale=$(basename "$locale_dir")
|
|
||||||
|
|
||||||
if [ "$locale" = "$BASE_LOCALE" ]; then
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
locale_count=$(count_keys "$locale_dir")
|
|
||||||
|
|
||||||
if [ "$base_count" -gt 0 ]; then
|
|
||||||
coverage=$((locale_count * 100 / base_count))
|
|
||||||
else
|
|
||||||
coverage=0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$coverage" -ge 90 ]; then
|
|
||||||
color=$GREEN
|
|
||||||
elif [ "$coverage" -ge 50 ]; then
|
|
||||||
color=$YELLOW
|
|
||||||
else
|
|
||||||
color=$RED
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo -e "Locale: ${color}$locale${NC} - $locale_count/$base_count keys (${coverage}%)"
|
|
||||||
|
|
||||||
missing_keys=()
|
|
||||||
extra_keys=()
|
|
||||||
|
|
||||||
for file in "$LOCALES_DIR/$BASE_LOCALE"/*.ftl; do
|
|
||||||
if [ -f "$file" ]; then
|
|
||||||
filename=$(basename "$file")
|
|
||||||
target_file="$locale_dir/$filename"
|
|
||||||
|
|
||||||
if [ ! -f "$target_file" ]; then
|
|
||||||
while IFS= read -r key; do
|
|
||||||
missing_keys+=("$filename: $key")
|
|
||||||
done < <(extract_keys "$file")
|
|
||||||
else
|
|
||||||
while IFS= read -r key; do
|
|
||||||
if ! grep -q "^$key\s*=" "$target_file" 2>/dev/null; then
|
|
||||||
missing_keys+=("$filename: $key")
|
|
||||||
fi
|
|
||||||
done < <(extract_keys "$file")
|
|
||||||
|
|
||||||
while IFS= read -r key; do
|
|
||||||
if ! grep -q "^$key\s*=" "$file" 2>/dev/null; then
|
|
||||||
extra_keys+=("$filename: $key")
|
|
||||||
fi
|
|
||||||
done < <(extract_keys "$target_file")
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ ${#missing_keys[@]} -gt 0 ]; then
|
|
||||||
echo -e " ${RED}Missing keys (${#missing_keys[@]}):${NC}"
|
|
||||||
for key in "${missing_keys[@]:0:10}"; do
|
|
||||||
echo " - $key"
|
|
||||||
done
|
|
||||||
if [ ${#missing_keys[@]} -gt 10 ]; then
|
|
||||||
echo " ... and $((${#missing_keys[@]} - 10)) more"
|
|
||||||
fi
|
|
||||||
total_missing=$((total_missing + ${#missing_keys[@]}))
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ${#extra_keys[@]} -gt 0 ]; then
|
|
||||||
echo -e " ${YELLOW}Extra keys (${#extra_keys[@]}):${NC}"
|
|
||||||
for key in "${extra_keys[@]:0:5}"; do
|
|
||||||
echo " - $key"
|
|
||||||
done
|
|
||||||
if [ ${#extra_keys[@]} -gt 5 ]; then
|
|
||||||
echo " ... and $((${#extra_keys[@]} - 5)) more"
|
|
||||||
fi
|
|
||||||
total_extra=$((total_extra + ${#extra_keys[@]}))
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
done
|
|
||||||
|
|
||||||
echo "========================================"
|
|
||||||
echo " Summary"
|
|
||||||
echo "========================================"
|
|
||||||
echo "Base keys: $base_count"
|
|
||||||
echo -e "Total missing: ${RED}$total_missing${NC}"
|
|
||||||
echo -e "Total extra: ${YELLOW}$total_extra${NC}"
|
|
||||||
|
|
||||||
if [ "$total_missing" -eq 0 ] && [ "$total_extra" -eq 0 ]; then
|
|
||||||
echo -e "${GREEN}All translations are complete!${NC}"
|
|
||||||
exit 0
|
|
||||||
else
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
Loading…
Add table
Reference in a new issue