mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-11 05:11:49 +01:00
fix(ui): show requester identity in join approvals
This commit is contained in:
1 parent
54b1667c3d
commit
c981115f22
2 files changed
+99
-5
No files matched your search
@@ -5,7 +5,13 @@ import type { ComponentProps } from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import type { Issue } from "@paperclipai/shared";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { FailedRunInboxRow, InboxIssueMetaLeading, InboxIssueTrailingColumns } from "./Inbox";
|
||||
import type { CompanyJoinRequest } from "../api/access";
|
||||
import {
|
||||
FailedRunInboxRow,
|
||||
InboxIssueMetaLeading,
|
||||
InboxIssueTrailingColumns,
|
||||
formatJoinRequestInboxLabel,
|
||||
} from "./Inbox";
|
||||
|
||||
vi.mock("@/lib/router", () => ({
|
||||
Link: ({ children, className, ...props }: ComponentProps<"a">) => (
|
||||
@@ -62,6 +68,44 @@ function createIssue(overrides: Partial<Issue> = {}): Issue {
|
||||
};
|
||||
}
|
||||
|
||||
function createJoinRequest(
|
||||
overrides: Partial<CompanyJoinRequest> = {},
|
||||
): CompanyJoinRequest {
|
||||
return {
|
||||
id: "join-1",
|
||||
inviteId: "invite-1",
|
||||
companyId: "company-1",
|
||||
requestType: "human",
|
||||
status: "pending_approval",
|
||||
requestIp: "127.0.0.1",
|
||||
requestingUserId: "user-1",
|
||||
requestEmailSnapshot: "joiner@example.com",
|
||||
agentName: null,
|
||||
adapterType: null,
|
||||
capabilities: null,
|
||||
agentDefaultsPayload: null,
|
||||
claimSecretExpiresAt: null,
|
||||
claimSecretConsumedAt: null,
|
||||
createdAgentId: null,
|
||||
approvedByUserId: null,
|
||||
approvedAt: null,
|
||||
rejectedByUserId: null,
|
||||
rejectedAt: null,
|
||||
createdAt: new Date("2026-03-11T00:00:00.000Z"),
|
||||
updatedAt: new Date("2026-03-11T00:00:00.000Z"),
|
||||
requesterUser: {
|
||||
id: "user-1",
|
||||
name: "Jordan Example",
|
||||
email: "joiner@example.com",
|
||||
image: null,
|
||||
},
|
||||
approvedByUser: null,
|
||||
rejectedByUser: null,
|
||||
invite: null,
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
describe("FailedRunInboxRow", () => {
|
||||
let container: HTMLDivElement;
|
||||
|
||||
@@ -245,3 +289,23 @@ describe("InboxIssueTrailingColumns", () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("formatJoinRequestInboxLabel", () => {
|
||||
it("shows the human requester's name and email when available", () => {
|
||||
expect(formatJoinRequestInboxLabel(createJoinRequest())).toBe(
|
||||
"Jordan Example (joiner@example.com)",
|
||||
);
|
||||
});
|
||||
|
||||
it("falls back to the email snapshot when the requester profile is missing", () => {
|
||||
expect(
|
||||
formatJoinRequestInboxLabel(
|
||||
createJoinRequest({
|
||||
requesterUser: null,
|
||||
requestEmailSnapshot: "snapshot@example.com",
|
||||
requestingUserId: null,
|
||||
}),
|
||||
),
|
||||
).toBe("snapshot@example.com");
|
||||
});
|
||||
});
|
||||
+34
-4
@@ -197,6 +197,39 @@ function readIssueIdFromRun(run: HeartbeatRun): string | null {
|
||||
return null;
|
||||
}
|
||||
|
||||
function nonEmptyLabel(value: string | null | undefined): string | null {
|
||||
const trimmed = value?.trim();
|
||||
return trimmed ? trimmed : null;
|
||||
}
|
||||
|
||||
export function formatJoinRequestInboxLabel(
|
||||
joinRequest: Pick<
|
||||
JoinRequest,
|
||||
"requestType" | "agentName" | "requestEmailSnapshot" | "requestingUserId"
|
||||
> & {
|
||||
requesterUser?: {
|
||||
name: string | null;
|
||||
email: string | null;
|
||||
} | null;
|
||||
},
|
||||
) {
|
||||
if (joinRequest.requestType !== "human") {
|
||||
return `Agent join request${joinRequest.agentName ? `: ${joinRequest.agentName}` : ""}`;
|
||||
}
|
||||
|
||||
const requesterName = nonEmptyLabel(joinRequest.requesterUser?.name);
|
||||
const requesterEmail =
|
||||
nonEmptyLabel(joinRequest.requesterUser?.email) ??
|
||||
nonEmptyLabel(joinRequest.requestEmailSnapshot);
|
||||
const requesterId = nonEmptyLabel(joinRequest.requestingUserId);
|
||||
|
||||
if (requesterName && requesterEmail) return `${requesterName} (${requesterEmail})`;
|
||||
if (requesterEmail) return requesterEmail;
|
||||
if (requesterName) return requesterName;
|
||||
if (requesterId) return requesterId;
|
||||
return "Human join request";
|
||||
}
|
||||
|
||||
|
||||
type NonIssueUnreadState = "visible" | "fading" | "hidden" | null;
|
||||
|
||||
@@ -523,10 +556,7 @@ function JoinRequestInboxRow({
|
||||
selected?: boolean;
|
||||
className?: string;
|
||||
}) {
|
||||
const label =
|
||||
joinRequest.requestType === "human"
|
||||
? "Human join request"
|
||||
: `Agent join request${joinRequest.agentName ? `: ${joinRequest.agentName}` : ""}`;
|
||||
const label = formatJoinRequestInboxLabel(joinRequest);
|
||||
const showUnreadSlot = unreadState !== null;
|
||||
const showUnreadDot = unreadState === "visible" || unreadState === "fading";
|
||||
|
||||
|
||||
Reference in new issue
Block a user