Skip to content

feat(hiring): hiring approvals page + sidebar entry#4432

Open
ramonmatias19 wants to merge 1 commit intopaperclipai:masterfrom
ramonmatias19:feature/hiring-approvals
Open

feat(hiring): hiring approvals page + sidebar entry#4432
ramonmatias19 wants to merge 1 commit intopaperclipai:masterfrom
ramonmatias19:feature/hiring-approvals

Conversation

@ramonmatias19
Copy link
Copy Markdown

@ramonmatias19 ramonmatias19 commented Apr 24, 2026

⚠️ Depends on: #4431 (i18n bootstrap) — Sidebar.tsx imports useTranslation from react-i18next. Verify/e2e red on this branch until #4431 merges. Expected sequence: #4431 → lockfile refresh bot → rebase this PR → green.

Summary

Split hiring approvals out of the generic Approvals page so pending agent hires get their own review surface with /pending and /all tabs, linked from the sidebar with a pending-count badge.

  • Add ui/src/pages/HiringApprovals.tsx
  • Add /hiring-approvals, /hiring-approvals/pending, /hiring-approvals/all routes (board-scoped + unprefixed redirects)
  • Add UserPlus sidebar item that surfaces pending hire_agent approvals; also migrates the rest of the sidebar labels to i18n.t() in the same change set

Depends on: #4431 (i18n bootstrap)

Test plan

  • Create a hire_agent approval — verify it shows on /hiring-approvals/pending and not /approvals
  • Verify sidebar badge matches pending count
  • Approve / reject from the new page

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 24, 2026

Greptile Summary

This PR adds a dedicated /hiring-approvals page that filters hire_agent approvals out of the generic approvals list, wires up new routes in App.tsx, and adds a sidebar entry with a live pending-count badge. The sidebar label migration to i18n.t() is clean.

  • P1 – All UI strings in HiringApprovals.tsx are hardcoded Portuguese ("Contratação", "Pendentes", "Falha ao aprovar", etc.), directly contradicting the i18n migration applied to Sidebar.tsx in the same PR. Every non-Portuguese user will see an untranslated page.
  • P2 – Two unrelated tests/ux/* routes are added to App.tsx alongside the hiring-approvals routes without explanation.
  • The PR description is missing the required Thinking Path, Model Used section, and before/after screenshots required by CONTRIBUTING.md for any UI change.

Confidence Score: 4/5

Not safe to merge until the hardcoded Portuguese strings are replaced with i18n keys.

One P1 finding (Portuguese hardcoded in a new English-first UI page) needs to be fixed before the feature is usable for non-Portuguese users. Routing and sidebar logic are otherwise correct.

ui/src/pages/HiringApprovals.tsx — all user-facing strings need i18n.t() replacements.

Important Files Changed

Filename Overview
ui/src/pages/HiringApprovals.tsx New page for hire_agent approvals — logic is correct but all user-facing strings are hardcoded in Portuguese, and the post-approve redirect targets the generic /approvals route rather than a hiring-scoped one.
ui/src/components/Sidebar.tsx Adds hiring-approvals sidebar entry with pending badge via a 30s-refetch query; also migrates all sidebar labels to i18n.t() — both changes look correct.
ui/src/App.tsx Adds three hiring-approvals routes (redirect + pending + all) and UnprefixedBoardRedirect entries; two unrelated test routes (tests/ux/chat, tests/ux/runs) are also added without explanation.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: ui/src/pages/HiringApprovals.tsx
Line: 30-103

Comment:
**Hardcoded Portuguese strings throughout the page**

`HiringApprovals.tsx` is entirely in Portuguese — breadcrumb ("Contratação"), tab labels ("Pendentes" / "Todos"), empty-state copy, and error messages ("Falha ao aprovar", "Falha ao rejeitar") — while the rest of the app (including the `Sidebar.tsx` changes in this same PR) runs through `i18n.t()`. Any non-Portuguese user will see an untranslated UI, and this directly contradicts the i18n migration this PR is supposed to introduce.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: ui/src/App.tsx
Line: 303-304

Comment:
**Unrelated test routes added in hiring-approvals PR**

Two routes — `tests/ux/chat` and `tests/ux/runs` — are added to the `UnprefixedBoardRedirect` block. They have no connection to the hiring-approvals feature and appear to be unintentional scope creep. If these are needed, they should be in a separate PR.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: ui/src/pages/HiringApprovals.tsx
Line: 50-52

Comment:
**`approveMutation` navigates to `/approvals/${id}` instead of a hiring-approvals route**

After a successful approve action, the user is redirected to `/approvals/${id}?resolved=approved` — the generic approvals detail page. While `ApprovalDetail` may be shared, the breadcrumb trail and back-navigation will land the user outside the `/hiring-approvals` context. Consider whether the detail link and post-approve redirect should use a hiring-approvals-scoped path, or at minimum document this is intentional.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "feat(hiring): hiring approvals page + si..." | Re-trigger Greptile

Comment on lines +30 to +103
}, [setBreadcrumbs]);

const { data, isLoading, error } = useQuery({
queryKey: queryKeys.approvals.list(selectedCompanyId!),
queryFn: () => approvalsApi.list(selectedCompanyId!),
enabled: !!selectedCompanyId,
});

const { data: agents } = useQuery({
queryKey: queryKeys.agents.list(selectedCompanyId!),
queryFn: () => agentsApi.list(selectedCompanyId!),
enabled: !!selectedCompanyId,
});

const approveMutation = useMutation({
mutationFn: (id: string) => approvalsApi.approve(id),
onSuccess: (_approval, id) => {
setActionError(null);
queryClient.invalidateQueries({ queryKey: queryKeys.approvals.list(selectedCompanyId!) });
navigate(`/approvals/${id}?resolved=approved`);
},
onError: (err) => {
setActionError(err instanceof Error ? err.message : "Falha ao aprovar");
},
});

const rejectMutation = useMutation({
mutationFn: (id: string) => approvalsApi.reject(id),
onSuccess: () => {
setActionError(null);
queryClient.invalidateQueries({ queryKey: queryKeys.approvals.list(selectedCompanyId!) });
},
onError: (err) => {
setActionError(err instanceof Error ? err.message : "Falha ao rejeitar");
},
});

const hiringApprovals = (data ?? []).filter((a) => a.type === "hire_agent");

const filtered = hiringApprovals
.filter(
(a) => statusFilter === "all" || a.status === "pending" || a.status === "revision_requested",
)
.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());

const pendingCount = hiringApprovals.filter(
(a) => a.status === "pending" || a.status === "revision_requested",
).length;

if (!selectedCompanyId) {
return <p className="text-sm text-muted-foreground">Selecione uma empresa primeiro.</p>;
}

if (isLoading) {
return <PageSkeleton variant="approvals" />;
}

return (
<div className="space-y-4">
<div className="flex items-center justify-between">
<Tabs value={statusFilter} onValueChange={(v) => navigate(`/hiring-approvals/${v}`)}>
<PageTabBar items={[
{ value: "pending", label: <>Pendentes{pendingCount > 0 && (
<span className={cn(
"ml-1.5 rounded-full px-1.5 py-0.5 text-[10px] font-medium",
"bg-yellow-500/20 text-yellow-500"
)}>
{pendingCount}
</span>
)}</> },
{ value: "all", label: "Todos" },
]} />
</Tabs>
</div>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Hardcoded Portuguese strings throughout the page

HiringApprovals.tsx is entirely in Portuguese — breadcrumb ("Contratação"), tab labels ("Pendentes" / "Todos"), empty-state copy, and error messages ("Falha ao aprovar", "Falha ao rejeitar") — while the rest of the app (including the Sidebar.tsx changes in this same PR) runs through i18n.t(). Any non-Portuguese user will see an untranslated UI, and this directly contradicts the i18n migration this PR is supposed to introduce.

Prompt To Fix With AI
This is a comment left during a code review.
Path: ui/src/pages/HiringApprovals.tsx
Line: 30-103

Comment:
**Hardcoded Portuguese strings throughout the page**

`HiringApprovals.tsx` is entirely in Portuguese — breadcrumb ("Contratação"), tab labels ("Pendentes" / "Todos"), empty-state copy, and error messages ("Falha ao aprovar", "Falha ao rejeitar") — while the rest of the app (including the `Sidebar.tsx` changes in this same PR) runs through `i18n.t()`. Any non-Portuguese user will see an untranslated UI, and this directly contradicts the i18n migration this PR is supposed to introduce.

How can I resolve this? If you propose a fix, please make it concise.

Comment thread ui/src/App.tsx
Comment on lines 303 to +304
<Route path="execution-workspaces/:workspaceId/issues" element={<UnprefixedBoardRedirect />} />
<Route path="hiring-approvals" element={<UnprefixedBoardRedirect />} />
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Unrelated test routes added in hiring-approvals PR

Two routes — tests/ux/chat and tests/ux/runs — are added to the UnprefixedBoardRedirect block. They have no connection to the hiring-approvals feature and appear to be unintentional scope creep. If these are needed, they should be in a separate PR.

Prompt To Fix With AI
This is a comment left during a code review.
Path: ui/src/App.tsx
Line: 303-304

Comment:
**Unrelated test routes added in hiring-approvals PR**

Two routes — `tests/ux/chat` and `tests/ux/runs` — are added to the `UnprefixedBoardRedirect` block. They have no connection to the hiring-approvals feature and appear to be unintentional scope creep. If these are needed, they should be in a separate PR.

How can I resolve this? If you propose a fix, please make it concise.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines +50 to +52
},
onError: (err) => {
setActionError(err instanceof Error ? err.message : "Falha ao aprovar");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 approveMutation navigates to /approvals/${id} instead of a hiring-approvals route

After a successful approve action, the user is redirected to /approvals/${id}?resolved=approved — the generic approvals detail page. While ApprovalDetail may be shared, the breadcrumb trail and back-navigation will land the user outside the /hiring-approvals context. Consider whether the detail link and post-approve redirect should use a hiring-approvals-scoped path, or at minimum document this is intentional.

Prompt To Fix With AI
This is a comment left during a code review.
Path: ui/src/pages/HiringApprovals.tsx
Line: 50-52

Comment:
**`approveMutation` navigates to `/approvals/${id}` instead of a hiring-approvals route**

After a successful approve action, the user is redirected to `/approvals/${id}?resolved=approved` — the generic approvals detail page. While `ApprovalDetail` may be shared, the breadcrumb trail and back-navigation will land the user outside the `/hiring-approvals` context. Consider whether the detail link and post-approve redirect should use a hiring-approvals-scoped path, or at minimum document this is intentional.

How can I resolve this? If you propose a fix, please make it concise.

@ramonmatias19 ramonmatias19 force-pushed the feature/hiring-approvals branch from 4dd1668 to 54e2809 Compare April 24, 2026 20:25
Split hiring approvals out of the generic Approvals page so pending
agent hires get their own review surface with /pending and /all tabs,
linked from the sidebar with a pending-count badge.

- Add ui/src/pages/HiringApprovals.tsx
- Add /hiring-approvals, /hiring-approvals/pending, /hiring-approvals/all
  routes (board-scoped + unprefixed redirects)
- Add UserPlus sidebar item that surfaces pending hire_agent approvals;
  also migrates the rest of the sidebar labels to i18n.t() in the same
  change set
@ramonmatias19 ramonmatias19 force-pushed the feature/hiring-approvals branch from 54e2809 to 1fd5ac8 Compare April 24, 2026 21:08
itsderek23 added a commit to itsderek23/paperclip that referenced this pull request Apr 24, 2026
Three fixes found while running releasebot against PR paperclipai#4432:

- ensureShaReachable now falls back to fetching the SHA directly from
  origin when it's not in pull/<n>/head. This covers the case where
  origin/master has advanced past the PR base since the last local fetch.
- Summary prompt now receives a structured Facts block with exact
  per-side pass/fail counts and visual-review verdict counts, with an
  explicit instruction not to invert them. Fixes a hallucination where
  the summary claimed "Playwright failed on the after side" when the
  after side had zero failures.
- --skip-install now preflights cli/node_modules/tsx/dist/cli.mjs in
  both worktrees and exits early with a clear message, instead of
  failing mid-boot with MODULE_NOT_FOUND.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant