-
Notifications
You must be signed in to change notification settings - Fork 1
feat(web): reposition UI as viewer + light CRUD #8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
311dc42
537ace4
c2cfb86
cdda5eb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -89,6 +89,7 @@ pub fn build_router(state: AppState) -> axum::Router { | |
| // ── New RESTful endpoints ────────────────────────────── | ||
| .route("/api/v1/epics/{id}/plan", post(handlers::set_epic_plan_handler)) | ||
| .route("/api/v1/epics/{id}/work", post(handlers::start_epic_work_handler)) | ||
| .route("/api/v1/tasks/{id}", get(handlers::get_task_handler)) | ||
| .route("/api/v1/tasks/{id}/start", post(handlers::start_task_rest_handler)) | ||
| .route("/api/v1/tasks/{id}/done", post(handlers::done_task_rest_handler)) | ||
| .route("/api/v1/tasks/{id}/block", post(handlers::block_task_rest_handler)) | ||
|
Comment on lines
89
to
95
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,83 @@ | ||
| import { Search, X } from "lucide-react"; | ||
|
|
||
| export interface EpicFiltersValue { | ||
| search: string; | ||
| status: string; | ||
| } | ||
|
|
||
| export const DEFAULT_EPIC_FILTERS: EpicFiltersValue = { | ||
| search: "", | ||
| status: "all", | ||
| }; | ||
|
|
||
| interface EpicFiltersProps { | ||
| value: EpicFiltersValue; | ||
| onChange: (next: EpicFiltersValue) => void; | ||
| statusOptions: string[]; | ||
| filteredCount: number; | ||
| totalCount: number; | ||
| } | ||
|
|
||
| export default function EpicFilters({ | ||
| value, | ||
| onChange, | ||
| statusOptions, | ||
| filteredCount, | ||
| totalCount, | ||
| }: EpicFiltersProps) { | ||
| const active = value.search.trim() !== "" || value.status !== "all"; | ||
|
|
||
| return ( | ||
| <div className="flex flex-col sm:flex-row sm:items-center gap-3 mb-3"> | ||
| <div className="relative flex-1 min-w-0"> | ||
| <Search | ||
| size={14} | ||
| className="absolute left-2.5 top-1/2 -translate-y-1/2 text-text-muted pointer-events-none" | ||
| /> | ||
| <input | ||
| type="text" | ||
| value={value.search} | ||
| onChange={(e) => onChange({ ...value, search: e.target.value })} | ||
| placeholder="Search epics by id or title…" | ||
| className="w-full pl-8 pr-8 py-2 rounded-md text-sm bg-bg-secondary border border-border text-text-primary placeholder:text-text-muted focus:outline-none focus:border-accent transition-colors" | ||
| /> | ||
| {value.search && ( | ||
| <button | ||
| onClick={() => onChange({ ...value, search: "" })} | ||
| className="absolute right-2 top-1/2 -translate-y-1/2 text-text-muted hover:text-text-primary transition-colors" | ||
| aria-label="Clear search" | ||
| > | ||
| <X size={14} /> | ||
| </button> | ||
| )} | ||
| </div> | ||
|
|
||
| <select | ||
| value={value.status} | ||
| onChange={(e) => onChange({ ...value, status: e.target.value })} | ||
| className="px-3 py-2 rounded-md text-sm bg-bg-secondary border border-border text-text-primary focus:outline-none focus:border-accent transition-colors" | ||
| > | ||
| <option value="all">All statuses</option> | ||
| {statusOptions.map((s) => ( | ||
| <option key={s} value={s}> | ||
| {s.replace("_", " ")} | ||
| </option> | ||
| ))} | ||
| </select> | ||
|
|
||
| {active && ( | ||
| <div className="flex items-center gap-2 text-xs text-text-muted"> | ||
| <span className="font-mono whitespace-nowrap"> | ||
| {filteredCount} / {totalCount} | ||
| </span> | ||
| <button | ||
| onClick={() => onChange(DEFAULT_EPIC_FILTERS)} | ||
| className="text-accent hover:text-accent-hover transition-colors whitespace-nowrap" | ||
| > | ||
| Clear filters | ||
| </button> | ||
| </div> | ||
| )} | ||
| </div> | ||
| ); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The markdown table in this section uses double leading pipes (
||) on each row, which renders as an extra empty column (or breaks table rendering depending on the renderer). Use single leading/ending pipes (|) for standard GitHub-flavored markdown tables.