diff --git a/app/assets/stylesheets/pages/certification/ships/_index.scss b/app/assets/stylesheets/pages/certification/ships/_index.scss index 8b892b8ed..f6cf6ef24 100644 --- a/app/assets/stylesheets/pages/certification/ships/_index.scss +++ b/app/assets/stylesheets/pages/certification/ships/_index.scss @@ -507,6 +507,22 @@ gap: var(--space-xs); } + // Category tag on a queue row (e.g. Hackpad) — a pill, not a status. + &__tag { + display: inline-flex; + align-items: center; + padding: 1px 8px; + border-radius: 999px; + font-size: 0.72rem; + font-weight: 700; + white-space: nowrap; + + &--hackpad { + background: rgba(235, 183, 255, 0.18); + color: var(--color-brand-lilac); + } + } + // Submitter, relative age, and the claim flag all share one meta line under // the project title — keeps the table to three columns with no dead space. &__project-meta { diff --git a/app/controllers/admin/certification/funding_requests_controller.rb b/app/controllers/admin/certification/funding_requests_controller.rb index 441a42dd6..3e781b9a6 100644 --- a/app/controllers/admin/certification/funding_requests_controller.rb +++ b/app/controllers/admin/certification/funding_requests_controller.rb @@ -10,6 +10,7 @@ def index @status = params[:status].presence_in(%w[pending approved returned all]) || "pending" @sort = params[:sort] == "newest" ? "newest" : "oldest" @search = params[:search].to_s.strip + @project_kind = params[:project_kind].presence_in(%w[all hackpad]) || "all" @from = parse_date(params[:from]) @to = parse_date(params[:to]) @@ -19,11 +20,19 @@ def index scope = scope.where("certification_funding_requests.created_at >= ?", @from.beginning_of_day) if @from scope = scope.where("certification_funding_requests.created_at <= ?", @to.end_of_day) if @to scope = apply_search(scope) if @search.present? + scope = scope.where(project_id: hackpad_project_ids) if @project_kind == "hackpad" @pagy, @funding_requests = pagy(:offset, scope.order(created_at: @sort == "newest" ? :desc : :asc), limit: 25) + # Which of the displayed rows are Hackpad projects (one query, so the view + # can flag them without an N+1 of Project#current_mission per row). + @hackpad_project_ids = hackpad_project_ids + .where(project_id: @funding_requests.map(&:project_id)) + .pluck(:project_id) + .to_set + @stats = ::Certification::FundingRequest.dashboard_stats @lb_period = params[:lb].presence_in(%w[daily weekly alltime]) || "daily" @leaderboards = { @@ -77,6 +86,16 @@ def set_funding_request @funding_request = ::Certification::FundingRequest.find(params[:id]) end + # Project ids whose current (active, non-detached) mission is the Hackpad + # mission — i.e. "hackpad projects" (mirrors Project#current_mission, which a + # project has at most one of). Used to filter the funding queue. + def hackpad_project_ids + Project::MissionAttachment.active + .joins(:mission) + .where(missions: { slug: "hackpad" }) + .select(:project_id) + end + # Both fetches below fan out to live HTTP (per Hackatime key / Lookout session) # on every render, including the re-render after a failed verdict submit. The # provider URLs only expire after ~1h, so a short cache keyed by project kills diff --git a/app/views/admin/certification/funding_requests/index.html.erb b/app/views/admin/certification/funding_requests/index.html.erb index 19b9360ef..633547afe 100644 --- a/app/views/admin/certification/funding_requests/index.html.erb +++ b/app/views/admin/certification/funding_requests/index.html.erb @@ -147,6 +147,13 @@ id: "filter-status", class: "ship-queue__select", data: { action: "change->certification--queue#submit" } %> +