Skip to content

Commit 365f0b9

Browse files
feat: mock newm-admin dashboard view
1 parent c38e392 commit 365f0b9

15 files changed

Lines changed: 832 additions & 103 deletions

File tree

.agent/task/admin/newm-admin.md

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
# NEWM Admin Desktop Application
2+
3+
## Overview
4+
5+
NEWM Admin is a desktop application for internal administrators to manage the NEWM platform. Built with Rust and GPUI (GPU-accelerated UI framework from Zed), it provides a performant, native interface for admin operations.
6+
7+
**Tech Stack:**
8+
- **Language:** Rust (2024 edition)
9+
- **UI Framework:** GPUI + gpui-component
10+
- **HTTP Client:** reqwest with async-compat bridge
11+
- **Target Platform:** Desktop (Linux, macOS, Windows)
12+
13+
---
14+
15+
## Current Features
16+
17+
### ✅ Authentication
18+
19+
**Status:** Completed (2026-01-07)
20+
21+
| Feature | Description |
22+
|---------|-------------|
23+
| Admin Login | Email/password authentication against Garage/Studio APIs |
24+
| Environment Selection | Toggle between Garage (dev) and Studio (prod) environments |
25+
| JWT Validation | Verifies `admin: true` claim in JWT before allowing access |
26+
| Password Visibility Toggle | Eye icon to show/hide password input |
27+
28+
**Files:**
29+
- [auth.rs](file:///home/westbam/Development/newm-server/newm-admin/src/auth.rs) — HTTP authentication client
30+
- [jwt.rs](file:///home/westbam/Development/newm-server/newm-admin/src/jwt.rs) — JWT claims parsing
31+
- [login.rs](file:///home/westbam/Development/newm-server/newm-admin/src/views/login.rs) — Login view UI
32+
33+
---
34+
35+
### ✅ Admin Dashboard
36+
37+
**Status:** Completed (2026-01-07)
38+
39+
| Feature | Description |
40+
|---------|-------------|
41+
| Sidebar Navigation | 200px fixed sidebar with menu items |
42+
| View State Management | Switches from Login → Dashboard on success |
43+
| Menu Items | Earnings (pie chart icon), Refunds (undo icon) |
44+
| Dynamic Work Area | Content changes based on selected menu |
45+
| Mock Statistics Cards | Placeholder cards showing sample data |
46+
47+
**Files:**
48+
- [app.rs](file:///home/westbam/Development/newm-server/newm-admin/src/app.rs) — App state and view switching
49+
- [dashboard.rs](file:///home/westbam/Development/newm-server/newm-admin/src/views/dashboard.rs) — Dashboard view
50+
- [colors.rs](file:///home/westbam/Development/newm-server/newm-admin/src/colors.rs) — Shared color palette
51+
52+
---
53+
54+
## Planned Features
55+
56+
### 🔲 Earnings Management
57+
58+
**Priority:** High
59+
60+
| Requirement | Status |
61+
|-------------|--------|
62+
| List all earnings with pagination | ⬜ Not started |
63+
| Filter by artist, song, date range | ⬜ Not started |
64+
| View earnings details | ⬜ Not started |
65+
| Export earnings data | ⬜ Not started |
66+
67+
### 🔲 Refunds Processing
68+
69+
**Priority:** High
70+
71+
| Requirement | Status |
72+
|-------------|--------|
73+
| List refund requests | ⬜ Not started |
74+
| Approve/reject refunds | ⬜ Not started |
75+
| View refund history | ⬜ Not started |
76+
| Audit trail for refund actions | ⬜ Not started |
77+
78+
### 🔲 Token Refresh
79+
80+
**Priority:** Medium
81+
82+
| Requirement | Status |
83+
|-------------|--------|
84+
| Automatic token refresh before expiry | ⬜ Not started |
85+
| Token storage (secure) | ⬜ Not started |
86+
| Session timeout handling | ⬜ Not started |
87+
88+
---
89+
90+
## Project Structure
91+
92+
```
93+
newm-admin/
94+
├── src/
95+
│ ├── main.rs # Entry point, window setup
96+
│ ├── app.rs # App state, view coordinator
97+
│ ├── auth.rs # Authentication client
98+
│ ├── jwt.rs # JWT parsing utilities
99+
│ ├── colors.rs # Shared color palette
100+
│ └── views/
101+
│ ├── mod.rs # View module exports
102+
│ ├── login.rs # Login view
103+
│ └── dashboard.rs # Dashboard view
104+
├── Cargo.toml # Dependencies
105+
├── DESIGN_GUIDE.md # UI styling reference
106+
└── README.md # Setup instructions
107+
```
108+
109+
---
110+
111+
## Design System
112+
113+
The application follows NEWM Studio's visual language:
114+
115+
| Element | Specification |
116+
|---------|---------------|
117+
| Background | `#000000` (primary), `#1a1a1a` (surface) |
118+
| Sidebar | 200px fixed width |
119+
| Primary Button | Purple-to-pink gradient (`#C341F0``#F53C69`) |
120+
| Text | White (`#ffffff`), secondary gray (`#a1a1aa`) |
121+
| Icons | From gpui-component-assets |
122+
123+
See [DESIGN_GUIDE.md](file:///home/westbam/Development/newm-server/newm-admin/DESIGN_GUIDE.md) for full specifications.
124+
125+
---
126+
127+
## Development Commands
128+
129+
```bash
130+
# Build
131+
cd newm-admin && cargo build
132+
133+
# Run (development)
134+
cd newm-admin && cargo run
135+
136+
# Format code
137+
cd newm-admin && cargo fmt
138+
139+
# Lint
140+
cd newm-admin && cargo clippy
141+
```
142+
143+
---
144+
145+
## Backend API Dependencies
146+
147+
The admin app communicates with the NEWM backend:
148+
149+
| Endpoint | Purpose |
150+
|----------|---------|
151+
| `POST /v1/auth/login` | Admin authentication |
152+
| `GET /v1/auth/refresh` | Token refresh |
153+
| `GET /v1/earnings/*` | Earnings data (planned) |
154+
| `POST /v1/refunds/*` | Refund operations (planned) |
155+
156+
---
157+
158+
## Change Log
159+
160+
| Date | Feature | Description |
161+
|------|---------|-------------|
162+
| 2026-01-07 | Dashboard | Added sidebar nav with Earnings/Refunds, work area panels |
163+
| 2026-01-07 | Auth | JWT admin validation, login view with environment selector |
164+
| 2026-01-06 | Init | Project setup with GPUI, basic login UI |
165+
166+
---
167+
168+
**Status:** 🚧 In Progress
169+
**Last Updated:** 2026-01-07

.agent/task/readme.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ Any unresolved decisions.
106106
107107
| Domain | Plan | Status | Date |
108108
|--------|------|--------|------|
109-
| *No plans yet* ||| |
109+
| admin | [newm-admin.md](admin/newm-admin.md) — NEWM Admin Desktop App | 🚧 In Progress | 2026-01-07 |
110110

111111
---
112112

.agent/workflows/admin.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,3 +191,19 @@ gpui_component::init(cx);
191191
```bash
192192
sudo apt install libxkbcommon-dev libwayland-dev
193193
```
194+
195+
---
196+
197+
## Visual Verification
198+
199+
This is a **desktop application**, not a web app. You cannot use browser tools to verify UI changes.
200+
201+
When visual verification of UI changes is needed:
202+
203+
1. **Run the application** using `cargo run`
204+
2. **Ask the user to take a screenshot** of the relevant window/view
205+
3. **Request the user provide the screenshot** so you can verify the UI appears correctly
206+
4. Document what specific UI elements should be visible in the screenshot
207+
208+
Example prompt to user:
209+
> "Please run the application and take a screenshot of [specific view]. I need to verify that [specific UI element] appears correctly. Attach the screenshot to your reply."

.github/workflows/newm-admin.yml

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
# Based on https://github.com/actions-rs/meta/blob/master/recipes/quickstart.md
2+
3+
on:
4+
push:
5+
paths:
6+
- 'newm-admin/**'
7+
8+
name: Validate
9+
10+
jobs:
11+
build:
12+
name: Build
13+
strategy:
14+
fail-fast: false
15+
matrix:
16+
job:
17+
- { os: ubuntu-22.04, label: ubuntu22, target: x86_64-unknown-linux-gnu }
18+
- { os: ubuntu-22.04, label: ubuntu22, target: x86_64-unknown-linux-musl, use-cross: true }
19+
- { os: macos-latest, label: macos, target: aarch64-apple-darwin }
20+
- { os: windows-latest, label: windows, target: x86_64-pc-windows-msvc }
21+
rust: [ nightly ]
22+
23+
runs-on: ${{ matrix.job.os }}
24+
25+
defaults:
26+
run:
27+
working-directory: newm-admin
28+
29+
steps:
30+
- name: Checkout sources
31+
uses: actions/checkout@v2
32+
33+
- name: Install nightly toolchain
34+
uses: dtolnay/rust-toolchain@stable
35+
with:
36+
toolchain: nightly
37+
components: rustfmt, clippy
38+
39+
- name: Install cross
40+
if: ${{ matrix.job.use-cross }}
41+
run: cargo install cross
42+
43+
- name: Run cargo check
44+
if: ${{ matrix.job.target == 'x86_64-unknown-linux-gnu' }}
45+
run: cargo check
46+
47+
- name: Run cargo fmt
48+
if: ${{ matrix.job.target == 'x86_64-unknown-linux-gnu' }}
49+
run: cargo fmt --all -- --check
50+
51+
- name: Run cargo clippy (cross)
52+
if: ${{ matrix.job.use-cross }}
53+
run: cross clippy --release --target ${{ matrix.job.target }} -- -D warnings
54+
55+
- name: Run cargo clippy
56+
if: ${{ !matrix.job.use-cross }}
57+
run: cargo clippy --release --target ${{ matrix.job.target }} -- -D warnings
58+
59+
- name: Run cargo test (cross)
60+
if: ${{ matrix.job.use-cross }}
61+
run: cross test --release --target ${{ matrix.job.target }}
62+
63+
- name: Run cargo test
64+
if: ${{ !matrix.job.use-cross }}
65+
run: cargo test --release --target ${{ matrix.job.target }}
66+
67+
- name: Build Release (cross)
68+
if: ${{ matrix.job.use-cross }}
69+
run: cross build --release --target ${{ matrix.job.target }} --locked
70+
71+
- name: Build Release
72+
if: ${{ !matrix.job.use-cross }}
73+
run: cargo build --release --target ${{ matrix.job.target }} --locked
74+
75+
- name: Package
76+
id: package
77+
shell: bash
78+
run: |
79+
PROJECT_NAME=$(sed -n 's/^name = "\(.*\)"/\1/p' Cargo.toml)
80+
PROJECT_VERSION=$(sed -n 's/^version = "\(.*\)"/\1/p' Cargo.toml | head -n1)
81+
if [[ "${{ matrix.job.target }}" == *-pc-windows-* ]]; then
82+
PKG_SUFFIX=".zip"
83+
else
84+
PKG_SUFFIX=".tar.gz"
85+
fi
86+
PKG_NAME=${PROJECT_NAME}-${PROJECT_VERSION}-${{ matrix.job.label }}-${{ matrix.job.target }}${PKG_SUFFIX}
87+
88+
if [[ "${{ matrix.job.target }}" == *-pc-windows-* ]]; then
89+
7z -y a "${PKG_NAME}" ./target/${{matrix.job.target}}/release/newm-admin.exe | tail -2
90+
else
91+
tar -C target/${{matrix.job.target}}/release -czf "${PKG_NAME}" newm-admin
92+
fi
93+
94+
echo ::set-output name=PKG_NAME::${PKG_NAME}
95+
echo ::set-output name=PKG_PATH::${PKG_NAME}
96+
97+
- name: Upload Artifacts
98+
uses: actions/upload-artifact@v4
99+
with:
100+
name: ${{ steps.package.outputs.PKG_NAME }}
101+
path: ${{ steps.package.outputs.PKG_PATH }}
102+
103+
- name: Release
104+
uses: softprops/action-gh-release@v1
105+
if: startsWith(github.ref, 'refs/tags/v')
106+
with:
107+
prerelease: "${{ contains(github.ref, 'alpha') || contains(github.ref, 'beta') || contains(github.ref, 'rc') }}"
108+
files: ${{ steps.package.outputs.PKG_PATH }}
109+
env:
110+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

newm-admin/Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

newm-admin/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,6 @@ tracing-subscriber = { version = "0.3", features = ["env-filter"] }
2525

2626
# Error Handling
2727
anyhow = "1"
28+
29+
# JWT Parsing
30+
base64 = "0.22"

newm-admin/src/NEWM_Logo.png

727 KB
Loading

newm-admin/src/app.rs

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,55 @@
11
use gpui::*;
22

3+
use crate::views::dashboard::DashboardView;
34
use crate::views::login::LoginView;
45

6+
/// Current view state of the application
7+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
8+
pub enum AppView {
9+
#[default]
10+
Login,
11+
Dashboard,
12+
}
13+
514
pub struct AdminApp {
15+
current_view: AppView,
616
login_view: Entity<LoginView>,
17+
dashboard_view: Entity<DashboardView>,
718
}
819

920
impl AdminApp {
1021
pub fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {
1122
let login_view = cx.new(|cx| LoginView::new(window, cx));
12-
Self { login_view }
23+
let dashboard_view = cx.new(|cx| DashboardView::new(window, cx));
24+
25+
// Subscribe to login success events
26+
cx.subscribe(
27+
&login_view,
28+
|this, _login, _event: &LoginSuccessEvent, cx| {
29+
this.current_view = AppView::Dashboard;
30+
cx.notify();
31+
},
32+
)
33+
.detach();
34+
35+
Self {
36+
current_view: AppView::default(),
37+
login_view,
38+
dashboard_view,
39+
}
1340
}
1441
}
1542

1643
impl Render for AdminApp {
1744
fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
18-
div().size_full().child(self.login_view.clone())
45+
div().size_full().child(match self.current_view {
46+
AppView::Login => self.login_view.clone().into_any_element(),
47+
AppView::Dashboard => self.dashboard_view.clone().into_any_element(),
48+
})
1949
}
2050
}
51+
52+
/// Event emitted when login succeeds
53+
pub struct LoginSuccessEvent;
54+
55+
impl EventEmitter<LoginSuccessEvent> for LoginView {}

0 commit comments

Comments
 (0)