mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-10-04 02:04:06 +00:00
feat(ui): invite a teammate from the AWS connect step (#12917)
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { toSentInvitation } from "./invitation.adapter";
|
||||
|
||||
const created = {
|
||||
data: {
|
||||
id: "inv-1",
|
||||
type: "invitations",
|
||||
attributes: {
|
||||
email: "teammate@company.com",
|
||||
token: "abc123DEF45678",
|
||||
state: "pending",
|
||||
expires_at: "2026-10-07T10:00:00Z",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
describe("toSentInvitation", () => {
|
||||
it("reads the id, email and token of a created invitation", () => {
|
||||
expect(toSentInvitation(created)).toEqual({
|
||||
id: "inv-1",
|
||||
email: "teammate@company.com",
|
||||
token: "abc123DEF45678",
|
||||
});
|
||||
});
|
||||
|
||||
it("returns null when the action resolved without a value", () => {
|
||||
// A 5xx makes `sendInvite` resolve undefined.
|
||||
expect(toSentInvitation(undefined)).toBeNull();
|
||||
});
|
||||
|
||||
it("returns null on a rejection, with or without an errors array", () => {
|
||||
expect(
|
||||
toSentInvitation({ errors: [{ detail: "Invalid email" }] }),
|
||||
).toBeNull();
|
||||
expect(toSentInvitation({ error: "Something went wrong" })).toBeNull();
|
||||
});
|
||||
|
||||
it("returns null when the record is missing any of the fields the link needs", () => {
|
||||
expect(
|
||||
toSentInvitation({
|
||||
data: { id: "inv-1", attributes: { email: "a@b.com" } },
|
||||
}),
|
||||
).toBeNull();
|
||||
expect(
|
||||
toSentInvitation({
|
||||
data: { id: "inv-1", attributes: { token: "abc123DEF45678" } },
|
||||
}),
|
||||
).toBeNull();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,25 @@
|
||||
import type { SentInvitation } from "@/types/onboarding-invite";
|
||||
|
||||
const readString = (value: unknown): string | null =>
|
||||
typeof value === "string" && value.length > 0 ? value : null;
|
||||
|
||||
/**
|
||||
* The created record out of `sendInvite`'s JSON:API response. Null for every
|
||||
* failure shape: `undefined` (a 5xx makes the action resolve without a value),
|
||||
* `{ errors }`, a bare `{ error }`, or a record missing what the link needs.
|
||||
*/
|
||||
export function toSentInvitation(response: unknown): SentInvitation | null {
|
||||
if (!response || typeof response !== "object") return null;
|
||||
const { data } = response as { data?: unknown };
|
||||
if (!data || typeof data !== "object") return null;
|
||||
const { id, attributes } = data as { id?: unknown; attributes?: unknown };
|
||||
const fields =
|
||||
attributes && typeof attributes === "object"
|
||||
? (attributes as Record<string, unknown>)
|
||||
: {};
|
||||
const invitationId = readString(id);
|
||||
const email = readString(fields.email);
|
||||
const token = readString(fields.token);
|
||||
if (!invitationId || !email || !token) return null;
|
||||
return { id: invitationId, email, token };
|
||||
}
|
||||
@@ -5,11 +5,9 @@ import type { InvitationRoleOption } from "@/types/onboarding-invite";
|
||||
|
||||
const ROLES_PAGE_SIZE = 50;
|
||||
|
||||
// Roles the onboarding invite step can offer; empty when the read fails so
|
||||
// the step can fall back to skipping rather than blocking the checkpoint.
|
||||
export const getOnboardingInviteRoles = async (): Promise<
|
||||
InvitationRoleOption[]
|
||||
> => {
|
||||
// Roles an invitation can grant; empty when the read fails so a caller can
|
||||
// fall back (skip, disable) rather than block.
|
||||
export const getInvitationRoles = async (): Promise<InvitationRoleOption[]> => {
|
||||
const rolesData = await getRoles({ pageSize: ROLES_PAGE_SIZE });
|
||||
const roles: unknown = rolesData?.data;
|
||||
if (!Array.isArray(roles)) return [];
|
||||
Reference in New Issue
Block a user