Refactoring of authentification

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
This commit is contained in:
Bryan Frimin
2025-09-08 10:02:52 +02:00
committed by Sacha Al Himdani
parent afa7e4fdd5
commit 0f96b8518f
53 changed files with 7997 additions and 1631 deletions

View File

@@ -17,9 +17,22 @@ import { useFormWithSchema } from "/hooks/useFormWithSchema";
import { Controller } from "react-hook-form";
const inviteMutation = graphql`
mutation InviteUserDialogMutation($input: InviteUserInput!) {
mutation InviteUserDialogMutation(
$input: InviteUserInput!
$connections: [ID!]!
) {
inviteUser(input: $input) {
success
invitationEdge @appendEdge(connections: $connections) {
node {
id
email
fullName
role
expiresAt
acceptedAt
createdAt
}
}
}
}
`;
@@ -30,7 +43,11 @@ const schema = z.object({
createPeople: z.boolean().default(false),
});
export function InviteUserDialog({ children }: PropsWithChildren) {
type Props = PropsWithChildren & {
connectionId?: string;
};
export function InviteUserDialog({ children, connectionId }: Props) {
const { __ } = useTranslate();
const organizationId = useOrganizationId();
const [inviteUser, isInviting] = useMutationWithToasts(inviteMutation, {
@@ -53,6 +70,7 @@ export function InviteUserDialog({ children }: PropsWithChildren) {
fullName: data.fullName,
createPeople: data.createPeople,
},
connections: connectionId ? [connectionId] : ["SettingsPageInvitations_invitations"],
},
onSuccess: () => {
reset();

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<9ed3f33dde5f6a00c742b8db245ba03b>>
* @generated SignedSource<<8efbb638045cb24913b04b4de2033357>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -16,11 +16,22 @@ export type InviteUserInput = {
organizationId: string;
};
export type InviteUserDialogMutation$variables = {
connections: ReadonlyArray<string>;
input: InviteUserInput;
};
export type InviteUserDialogMutation$data = {
readonly inviteUser: {
readonly success: boolean;
readonly invitationEdge: {
readonly node: {
readonly acceptedAt: any | null | undefined;
readonly createdAt: any;
readonly email: string;
readonly expiresAt: any;
readonly fullName: string;
readonly id: string;
readonly role: string;
};
};
};
};
export type InviteUserDialogMutation = {
@@ -29,67 +40,170 @@ export type InviteUserDialogMutation = {
};
const node: ConcreteRequest = (function(){
var v0 = [
var v0 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "connections"
},
v1 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "input"
},
v2 = [
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "input"
"kind": "Variable",
"name": "input",
"variableName": "input"
}
],
v1 = [
{
"alias": null,
"args": [
{
"kind": "Variable",
"name": "input",
"variableName": "input"
}
],
"concreteType": "InviteUserPayload",
"kind": "LinkedField",
"name": "inviteUser",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "success",
"storageKey": null
}
],
"storageKey": null
}
];
v3 = {
"alias": null,
"args": null,
"concreteType": "InvitationEdge",
"kind": "LinkedField",
"name": "invitationEdge",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Invitation",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "email",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "fullName",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "role",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "expiresAt",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "acceptedAt",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "createdAt",
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
};
return {
"fragment": {
"argumentDefinitions": (v0/*: any*/),
"argumentDefinitions": [
(v0/*: any*/),
(v1/*: any*/)
],
"kind": "Fragment",
"metadata": null,
"name": "InviteUserDialogMutation",
"selections": (v1/*: any*/),
"selections": [
{
"alias": null,
"args": (v2/*: any*/),
"concreteType": "InviteUserPayload",
"kind": "LinkedField",
"name": "inviteUser",
"plural": false,
"selections": [
(v3/*: any*/)
],
"storageKey": null
}
],
"type": "Mutation",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": (v0/*: any*/),
"argumentDefinitions": [
(v1/*: any*/),
(v0/*: any*/)
],
"kind": "Operation",
"name": "InviteUserDialogMutation",
"selections": (v1/*: any*/)
"selections": [
{
"alias": null,
"args": (v2/*: any*/),
"concreteType": "InviteUserPayload",
"kind": "LinkedField",
"name": "inviteUser",
"plural": false,
"selections": [
(v3/*: any*/),
{
"alias": null,
"args": null,
"filters": null,
"handle": "appendEdge",
"key": "",
"kind": "LinkedHandle",
"name": "invitationEdge",
"handleArgs": [
{
"kind": "Variable",
"name": "connections",
"variableName": "connections"
}
]
}
],
"storageKey": null
}
]
},
"params": {
"cacheID": "aa667927b5e2cd0019a8457edc286181",
"cacheID": "2f6a83e238f7749e18757ec74e86b64b",
"id": null,
"metadata": {},
"name": "InviteUserDialogMutation",
"operationKind": "mutation",
"text": "mutation InviteUserDialogMutation(\n $input: InviteUserInput!\n) {\n inviteUser(input: $input) {\n success\n }\n}\n"
"text": "mutation InviteUserDialogMutation(\n $input: InviteUserInput!\n) {\n inviteUser(input: $input) {\n invitationEdge {\n node {\n id\n email\n fullName\n role\n expiresAt\n acceptedAt\n createdAt\n }\n }\n }\n}\n"
}
};
})();
(node as any).hash = "de4c5b5208a2ff0953e9d15b844df842";
(node as any).hash = "3981061f31a11e83ad32bed9fabddf64";
export default node;

View File

@@ -10,6 +10,8 @@ export const organizationViewQuery = graphql`
id
name
...SettingsPageFragment
...SettingsPageMembershipsFragment
...SettingsPageInvitationsFragment
}
}
}

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<5a41cd3709282172e4d5a3ca65d07b96>>
* @generated SignedSource<<df47e943d9509dbbe4d7cf9498941171>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -17,7 +17,7 @@ export type OrganizationGraph_ViewQuery$data = {
readonly node: {
readonly id?: string;
readonly name?: string;
readonly " $fragmentSpreads": FragmentRefs<"SettingsPageFragment">;
readonly " $fragmentSpreads": FragmentRefs<"SettingsPageFragment" | "SettingsPageInvitationsFragment" | "SettingsPageMembershipsFragment">;
};
};
export type OrganizationGraph_ViewQuery = {
@@ -58,29 +58,133 @@ v4 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "email",
"name": "__typename",
"storageKey": null
},
v5 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "type",
"name": "email",
"storageKey": null
},
v6 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "type",
"storageKey": null
},
v7 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "createdAt",
"storageKey": null
},
v7 = [
v8 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "updatedAt",
"storageKey": null
},
v9 = [
{
"kind": "Literal",
"name": "first",
"value": 100
"value": 20
},
{
"kind": "Literal",
"name": "orderBy",
"value": {
"direction": "ASC",
"field": "CREATED_AT"
}
}
],
v10 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "totalCount",
"storageKey": null
},
v11 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "fullName",
"storageKey": null
},
v12 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "role",
"storageKey": null
},
v13 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "cursor",
"storageKey": null
},
v14 = {
"alias": null,
"args": null,
"concreteType": "PageInfo",
"kind": "LinkedField",
"name": "pageInfo",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "endCursor",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasNextPage",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasPreviousPage",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "startCursor",
"storageKey": null
}
],
"storageKey": null
},
v15 = {
"kind": "ClientExtension",
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__id",
"storageKey": null
}
]
},
v16 = [
"orderBy"
];
return {
"fragment": {
@@ -106,6 +210,16 @@ return {
"args": null,
"kind": "FragmentSpread",
"name": "SettingsPageFragment"
},
{
"args": null,
"kind": "FragmentSpread",
"name": "SettingsPageMembershipsFragment"
},
{
"args": null,
"kind": "FragmentSpread",
"name": "SettingsPageInvitationsFragment"
}
],
"type": "Organization",
@@ -132,13 +246,7 @@ return {
"name": "node",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
},
(v4/*: any*/),
(v2/*: any*/),
{
"kind": "InlineFragment",
@@ -172,7 +280,7 @@ return {
"name": "websiteUrl",
"storageKey": null
},
(v4/*: any*/),
(v5/*: any*/),
{
"alias": null,
"args": null,
@@ -211,7 +319,7 @@ return {
"name": "dnsRecords",
"plural": true,
"selections": [
(v5/*: any*/),
(v6/*: any*/),
(v3/*: any*/),
{
"alias": null,
@@ -237,14 +345,8 @@ return {
],
"storageKey": null
},
(v6/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "updatedAt",
"storageKey": null
},
(v7/*: any*/),
(v8/*: any*/),
{
"alias": null,
"args": null,
@@ -255,52 +357,17 @@ return {
],
"storageKey": null
},
(v7/*: any*/),
(v8/*: any*/),
{
"alias": null,
"args": (v7/*: any*/),
"concreteType": "UserConnection",
"kind": "LinkedField",
"name": "users",
"plural": false,
"selections": [
"args": [
{
"alias": null,
"args": null,
"concreteType": "UserEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "User",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v2/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "fullName",
"storageKey": null
},
(v4/*: any*/),
(v6/*: any*/)
],
"storageKey": null
}
],
"storageKey": null
"kind": "Literal",
"name": "first",
"value": 100
}
],
"storageKey": "users(first:100)"
},
{
"alias": null,
"args": (v7/*: any*/),
"concreteType": "ConnectorConnection",
"kind": "LinkedField",
"name": "connectors",
@@ -324,8 +391,8 @@ return {
"selections": [
(v2/*: any*/),
(v3/*: any*/),
(v5/*: any*/),
(v6/*: any*/)
(v6/*: any*/),
(v7/*: any*/)
],
"storageKey": null
}
@@ -334,6 +401,130 @@ return {
}
],
"storageKey": "connectors(first:100)"
},
{
"alias": null,
"args": (v9/*: any*/),
"concreteType": "MembershipConnection",
"kind": "LinkedField",
"name": "memberships",
"plural": false,
"selections": [
(v10/*: any*/),
{
"alias": null,
"args": null,
"concreteType": "MembershipEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Membership",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v2/*: any*/),
(v11/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "emailAddress",
"storageKey": null
},
(v12/*: any*/),
(v7/*: any*/),
(v4/*: any*/)
],
"storageKey": null
},
(v13/*: any*/)
],
"storageKey": null
},
(v14/*: any*/),
(v15/*: any*/)
],
"storageKey": "memberships(first:20,orderBy:{\"direction\":\"ASC\",\"field\":\"CREATED_AT\"})"
},
{
"alias": null,
"args": (v9/*: any*/),
"filters": (v16/*: any*/),
"handle": "connection",
"key": "SettingsPageMemberships_memberships",
"kind": "LinkedHandle",
"name": "memberships"
},
{
"alias": null,
"args": (v9/*: any*/),
"concreteType": "InvitationConnection",
"kind": "LinkedField",
"name": "invitations",
"plural": false,
"selections": [
(v10/*: any*/),
{
"alias": null,
"args": null,
"concreteType": "InvitationEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Invitation",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v2/*: any*/),
(v5/*: any*/),
(v11/*: any*/),
(v12/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "expiresAt",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "acceptedAt",
"storageKey": null
},
(v7/*: any*/),
(v4/*: any*/)
],
"storageKey": null
},
(v13/*: any*/)
],
"storageKey": null
},
(v14/*: any*/),
(v15/*: any*/)
],
"storageKey": "invitations(first:20,orderBy:{\"direction\":\"ASC\",\"field\":\"CREATED_AT\"})"
},
{
"alias": null,
"args": (v9/*: any*/),
"filters": (v16/*: any*/),
"handle": "connection",
"key": "SettingsPageInvitations_invitations",
"kind": "LinkedHandle",
"name": "invitations"
}
],
"type": "Organization",
@@ -345,16 +536,16 @@ return {
]
},
"params": {
"cacheID": "8b9e1f3b1e93e1823354e77f10764e54",
"cacheID": "eb300e10b8aec548831c1610ea7bc0ec",
"id": null,
"metadata": {},
"name": "OrganizationGraph_ViewQuery",
"operationKind": "query",
"text": "query OrganizationGraph_ViewQuery(\n $organizationId: ID!\n) {\n node(id: $organizationId) {\n __typename\n ... on Organization {\n id\n name\n ...SettingsPageFragment\n }\n id\n }\n}\n\nfragment SettingsPageFragment on Organization {\n id\n name\n logoUrl\n horizontalLogoUrl\n description\n websiteUrl\n email\n headquarterAddress\n customDomain {\n id\n domain\n sslStatus\n dnsRecords {\n type\n name\n value\n ttl\n purpose\n }\n createdAt\n updatedAt\n sslExpiresAt\n }\n users(first: 100) {\n edges {\n node {\n id\n fullName\n email\n createdAt\n }\n }\n }\n connectors(first: 100) {\n edges {\n node {\n id\n name\n type\n createdAt\n }\n }\n }\n}\n"
"text": "query OrganizationGraph_ViewQuery(\n $organizationId: ID!\n) {\n node(id: $organizationId) {\n __typename\n ... on Organization {\n id\n name\n ...SettingsPageFragment\n ...SettingsPageMembershipsFragment\n ...SettingsPageInvitationsFragment\n }\n id\n }\n}\n\nfragment SettingsPageFragment on Organization {\n id\n name\n logoUrl\n horizontalLogoUrl\n description\n websiteUrl\n email\n headquarterAddress\n customDomain {\n id\n domain\n sslStatus\n dnsRecords {\n type\n name\n value\n ttl\n purpose\n }\n createdAt\n updatedAt\n sslExpiresAt\n }\n createdAt\n updatedAt\n connectors(first: 100) {\n edges {\n node {\n id\n name\n type\n createdAt\n }\n }\n }\n}\n\nfragment SettingsPageInvitationsFragment on Organization {\n invitations(first: 20, orderBy: {direction: ASC, field: CREATED_AT}) {\n totalCount\n edges {\n node {\n id\n email\n fullName\n role\n expiresAt\n acceptedAt\n createdAt\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n\nfragment SettingsPageMembershipsFragment on Organization {\n memberships(first: 20, orderBy: {direction: ASC, field: CREATED_AT}) {\n totalCount\n edges {\n node {\n id\n fullName\n emailAddress\n role\n createdAt\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n"
}
};
})();
(node as any).hash = "196e8c1fc9c2e0b3c76c8b338ed5c7f7";
(node as any).hash = "fda1489f2b80fd3d0b3962574bd7dfe3";
export default node;

View File

@@ -1,5 +1,4 @@
import {
ActionDropdown,
Avatar,
Badge,
Button,
@@ -7,14 +6,21 @@ import {
Dialog,
DialogContent,
DialogFooter,
DropdownItem,
Field,
FileButton,
IconTrashCan,
Label,
PageHeader,
Spinner,
TabBadge,
TabItem,
Tabs,
Tbody,
Td,
Textarea,
Th,
Thead,
Tr,
useConfirm,
useDialogRef,
useToast,
@@ -22,19 +28,28 @@ import {
import { useTranslate } from "@probo/i18n";
import type { PreloadedQuery } from "react-relay";
import type { OrganizationGraph_ViewQuery } from "/hooks/graph/__generated__/OrganizationGraph_ViewQuery.graphql";
import { useFragment, useMutation, usePreloadedQuery } from "react-relay";
import { useFragment, useMutation, usePreloadedQuery, usePaginationFragment } from "react-relay";
import { organizationViewQuery } from "/hooks/graph/OrganizationGraph";
import { graphql } from "relay-runtime";
import { SortableTable, SortableTh } from "/components/SortableTable";
import clsx from "clsx";
import type {
SettingsPageFragment$data,
SettingsPageFragment$key,
} from "./__generated__/SettingsPageFragment.graphql";
import type {
SettingsPageMembershipsFragment$data,
SettingsPageMembershipsFragment$key
} from "./__generated__/SettingsPageMembershipsFragment.graphql";
import type {
SettingsPageInvitationsFragment$data,
SettingsPageInvitationsFragment$key
} from "./__generated__/SettingsPageInvitationsFragment.graphql";
import { useState, type ChangeEventHandler, useEffect } from "react";
import { sprintf } from "@probo/helpers";
import { useFormWithSchema } from "/hooks/useFormWithSchema";
import { z } from "zod";
import type { NodeOf } from "/types";
import clsx from "clsx";
import { useMutationWithToasts } from "/hooks/useMutationWithToasts";
import { useOrganizationId } from "/hooks/useOrganizationId";
import { InviteUserDialog } from "/components/organizations/InviteUserDialog";
@@ -82,16 +97,8 @@ const organizationFragment = graphql`
updatedAt
sslExpiresAt
}
users(first: 100) {
edges {
node {
id
fullName
email
createdAt
}
}
}
createdAt
updatedAt
connectors(first: 100) {
edges {
node {
@@ -105,6 +112,83 @@ const organizationFragment = graphql`
}
`;
const paginatedMembershipsFragment = graphql`
fragment SettingsPageMembershipsFragment on Organization
@refetchable(queryName: "SettingsMembershipsRefetchQuery")
@argumentDefinitions(
first: { type: "Int", defaultValue: 20 }
order: { type: "MembershipOrder", defaultValue: { direction: ASC, field: CREATED_AT } }
after: { type: "CursorKey", defaultValue: null }
before: { type: "CursorKey", defaultValue: null }
last: { type: "Int", defaultValue: null }
) {
memberships(
first: $first
after: $after
last: $last
before: $before
orderBy: $order
) @connection(key: "SettingsPageMemberships_memberships") {
__id
totalCount
edges {
node {
id
fullName
emailAddress
role
createdAt
}
}
}
}
`;
const paginatedInvitationsFragment = graphql`
fragment SettingsPageInvitationsFragment on Organization
@refetchable(queryName: "SettingsInvitationsRefetchQuery")
@argumentDefinitions(
first: { type: "Int", defaultValue: 20 }
order: { type: "InvitationOrder", defaultValue: { direction: ASC, field: CREATED_AT } }
after: { type: "CursorKey", defaultValue: null }
before: { type: "CursorKey", defaultValue: null }
last: { type: "Int", defaultValue: null }
) {
invitations(
first: $first
after: $after
last: $last
before: $before
orderBy: $order
) @connection(key: "SettingsPageInvitations_invitations") {
__id
totalCount
edges {
node {
id
email
fullName
role
expiresAt
acceptedAt
createdAt
}
}
}
}
`;
const deleteInvitationMutation = graphql`
mutation SettingsPage_DeleteInvitationMutation(
$input: DeleteInvitationInput!
$connections: [ID!]!
) {
deleteInvitation(input: $input) {
deletedInvitationId @deleteEdge(connections: $connections)
}
}
`;
const updateOrganizationMutation = graphql`
mutation SettingsPage_UpdateMutation($input: UpdateOrganizationInput!) {
updateOrganization(input: $input) {
@@ -145,6 +229,17 @@ export default function SettingsPage({ queryRef }: Props) {
organizationFragment,
organizationKey
);
const membershipsPagination = usePaginationFragment(
paginatedMembershipsFragment,
organizationKey as SettingsPageMembershipsFragment$key
);
const invitationsPagination = usePaginationFragment(
paginatedInvitationsFragment,
organizationKey as SettingsPageInvitationsFragment$key
);
const [updateOrganization] = useMutation(updateOrganizationMutation);
const [deleteHorizontalLogo, isDeletingHorizontalLogo] = useMutationWithToasts(
deleteHorizontalLogoMutation,
@@ -154,7 +249,27 @@ export default function SettingsPage({ queryRef }: Props) {
}
);
const [deleteOrganization, isDeleting] = useDeleteOrganizationMutation();
const users = organization.users.edges.map((edge) => edge.node);
const memberships = membershipsPagination.data.memberships?.edges.map((edge) => edge.node) || [];
const invitations = invitationsPagination.data.invitations?.edges.map((edge) => edge.node) || [];
const [activeTab, setActiveTab] = useState<"memberships" | "invitations">("memberships");
const refetchMemberships = ({ order }: { order: { direction: string; field: string } }) => {
membershipsPagination.refetch({
order: {
direction: order.direction as "ASC" | "DESC",
field: order.field as "CREATED_AT" | "FULL_NAME" | "EMAIL_ADDRESS" | "ROLE"
}
});
};
const refetchInvitations = ({ order }: { order: { direction: string; field: string } }) => {
invitationsPagination.refetch({
order: {
direction: order.direction as "ASC" | "DESC",
field: order.field as "CREATED_AT" | "EXPIRES_AT" | "FULL_NAME" | "EMAIL" | "ROLE" | "STATUS" | "ACCEPTED_AT"
}
});
};
const { formState, handleSubmit, register, reset } = useFormWithSchema(
organizationSchema,
@@ -454,19 +569,103 @@ export default function SettingsPage({ queryRef }: Props) {
</Card>
</div>
</form>
{/* Integrations */}
<div className="space-y-4">
<div className="space-y-2">
<div className="flex items-center justify-between">
<h2 className="text-base font-medium">{__("Workspace members")}</h2>
<InviteUserDialog>
<InviteUserDialog connectionId={invitationsPagination.data.invitations?.__id}>
<Button variant="secondary">{__("Invite member")}</Button>
</InviteUserDialog>
</div>
<Card className="divide-y divide-border-solid">
{users.map((user) => (
<UserRow key={user.id} user={user} />
))}
<Tabs>
<TabItem
active={activeTab === "memberships"}
onClick={() => setActiveTab("memberships")}
>
{__("Members")}
{(membershipsPagination.data.memberships?.totalCount || 0) > 0 && (
<TabBadge>{membershipsPagination.data.memberships?.totalCount}</TabBadge>
)}
</TabItem>
<TabItem
active={activeTab === "invitations"}
onClick={() => setActiveTab("invitations")}
>
{__("Invitations")}
{(invitationsPagination.data.invitations?.totalCount || 0) > 0 && (
<TabBadge>{invitationsPagination.data.invitations?.totalCount}</TabBadge>
)}
</TabItem>
</Tabs>
<Card>
<div className="px-6 pb-6 pt-6">
{activeTab === "memberships" && (
<SortableTable
{...membershipsPagination}
refetch={refetchMemberships}
>
<Thead>
<Tr>
<SortableTh field="FULL_NAME">{__("Name")}</SortableTh>
<SortableTh field="EMAIL_ADDRESS">{__("Email")}</SortableTh>
<SortableTh field="ROLE">{__("Role")}</SortableTh>
<SortableTh field="CREATED_AT">{__("Joined")}</SortableTh>
<Th></Th>
</Tr>
</Thead>
<Tbody>
{memberships.length === 0 ? (
<Tr>
<Td colSpan={5} className="text-center text-txt-secondary">
{__("No members")}
</Td>
</Tr>
) : (
memberships.map((membership) => (
<MembershipRow key={membership.id} membership={membership} />
))
)}
</Tbody>
</SortableTable>
)}
{activeTab === "invitations" && (
<SortableTable
{...invitationsPagination}
refetch={refetchInvitations}
>
<Thead>
<Tr>
<SortableTh field="FULL_NAME">{__("Name")}</SortableTh>
<SortableTh field="EMAIL">{__("Email")}</SortableTh>
<SortableTh field="ROLE">{__("Role")}</SortableTh>
<SortableTh field="CREATED_AT">{__("Invited")}</SortableTh>
<Th>{__("Status")}</Th>
<SortableTh field="ACCEPTED_AT">{__("Accepted at")}</SortableTh>
<Th></Th>
</Tr>
</Thead>
<Tbody>
{invitations.length === 0 ? (
<Tr>
<Td colSpan={7} className="text-center text-txt-secondary">
{__("No invitations")}
</Td>
</Tr>
) : (
invitations.map((invitation) => (
<InvitationRow
key={invitation.id}
invitation={invitation}
connectionId={invitationsPagination.data.invitations?.__id}
/>
))
)}
</Tbody>
</SortableTable>
)}
</div>
</Card>
</div>
@@ -594,23 +793,107 @@ function Connectors(props: {
);
}
const removeUserMutation = graphql`
mutation SettingsPage_RemoveUserMutation($input: RemoveUserInput!) {
removeUser(input: $input) {
const removeMemberMutation = graphql`
mutation SettingsPage_RemoveMemberMutation($input: RemoveMemberInput!) {
removeMember(input: $input) {
success
}
}
`;
function UserRow(props: { user: NodeOf<SettingsPageFragment$data["users"]> }) {
function InvitationRow(props: {
invitation: NodeOf<SettingsPageInvitationsFragment$data["invitations"]>;
connectionId?: string;
}) {
const { __ } = useTranslate();
const confirm = useConfirm();
const [deleteInvitation, isDeleting] = useMutationWithToasts(
deleteInvitationMutation,
{
successMessage: sprintf(
__("Invitation for %s deleted successfully"),
props.invitation.fullName
),
}
);
const isExpired = new Date() > new Date(props.invitation.expiresAt);
const isAccepted = !!props.invitation.acceptedAt;
const onDelete = () => {
confirm(
() => {
return deleteInvitation({
variables: {
input: {
invitationId: props.invitation.id,
},
connections: props.connectionId ? [props.connectionId] : [],
},
});
},
{
message: sprintf(
__("Are you sure you want to delete the invitation for %s?"),
props.invitation.fullName
),
}
);
};
return (
<Tr className={clsx(isDeleting && "opacity-60 pointer-events-none")}>
<Td>
<div className="font-semibold">{props.invitation.fullName}</div>
</Td>
<Td>{props.invitation.email}</Td>
<Td>
<Badge>{props.invitation.role}</Badge>
</Td>
<Td>{new Date(props.invitation.createdAt).toLocaleDateString()}</Td>
<Td>
{isAccepted ? (
<Badge variant="success">{__("Accepted")}</Badge>
) : isExpired ? (
<Badge variant="danger">{__("Expired")}</Badge>
) : (
<Badge variant="warning">{__("Pending")}</Badge>
)}
</Td>
<Td>
{props.invitation.acceptedAt ? new Date(props.invitation.acceptedAt).toLocaleDateString() : "-"}
</Td>
<Td noLink width={80} className="text-end">
<div
className="flex gap-2 justify-end"
onClick={(e) => e.stopPropagation()}
>
{isDeleting ? (
<Spinner size={16} />
) : (
<Button
variant="danger"
onClick={onDelete}
disabled={isDeleting}
icon={IconTrashCan}
aria-label={__("Delete invitation")}
/>
)}
</div>
</Td>
</Tr>
);
}
function MembershipRow(props: { membership: NodeOf<SettingsPageMembershipsFragment$data["memberships"]> }) {
const { __ } = useTranslate();
const organizationId = useOrganizationId();
const [removeUser, isRemoving] = useMutationWithToasts(removeUserMutation, {
const [removeMember, isRemoving] = useMutationWithToasts(removeMemberMutation, {
successMessage: sprintf(
__("User %s removed successfully"),
props.user.fullName
__("Member %s removed successfully"),
props.membership.fullName
),
errorMessage: sprintf(__("Failed to remove user %s"), props.user.fullName),
errorMessage: sprintf(__("Failed to remove member %s"), props.membership.fullName),
});
const confirm = useConfirm();
const [isRemoved, setIsRemoved] = useState(false);
@@ -622,10 +905,10 @@ function UserRow(props: { user: NodeOf<SettingsPageFragment$data["users"]> }) {
const onRemove = async () => {
confirm(
() => {
return removeUser({
return removeMember({
variables: {
input: {
userId: props.user.id,
memberId: props.membership.id,
organizationId: organizationId,
},
},
@@ -637,42 +920,40 @@ function UserRow(props: { user: NodeOf<SettingsPageFragment$data["users"]> }) {
{
message: sprintf(
__("Are you sure you want to remove %s?"),
props.user.fullName
props.membership.fullName
),
}
);
};
return (
<div
className={clsx(
"flex justify-between items-center py-4 px-4",
isRemoving && "opacity-60 pointer-events-none"
)}
>
<div className="flex items-center gap-4">
<Avatar name={props.user.fullName} size="l" />
<div>
<h3 className="text-base font-semibold">{props.user.fullName}</h3>
<p className="text-sm text-txt-tertiary">{props.user.email}</p>
</div>
</div>
<div className="flex gap-2 items-center">
<Badge>{__("Owner")}</Badge>
{isRemoving ? (
<Spinner size={16} />
) : (
<ActionDropdown>
<DropdownItem
<Tr className={clsx(isRemoving && "opacity-60 pointer-events-none")}>
<Td>
<div className="font-semibold">{props.membership.fullName}</div>
</Td>
<Td>{props.membership.emailAddress}</Td>
<Td>
<Badge>{props.membership.role}</Badge>
</Td>
<Td>{new Date(props.membership.createdAt).toLocaleDateString()}</Td>
<Td noLink width={80} className="text-end">
<div
className="flex gap-2 justify-end"
onClick={(e) => e.stopPropagation()}
>
{isRemoving ? (
<Spinner size={16} />
) : (
<Button
variant="danger"
icon={IconTrashCan}
onClick={onRemove}
>
{__("Remove")}
</DropdownItem>
</ActionDropdown>
)}
</div>
</div>
disabled={isRemoving}
icon={IconTrashCan}
aria-label={__("Remove member")}
/>
)}
</div>
</Td>
</Tr>
);
}

View File

@@ -0,0 +1,368 @@
/**
* @generated SignedSource<<9b6812ed468b85a1d3a8684ed1c3ad6f>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime";
export type InvitationOrderField = "ACCEPTED_AT" | "CREATED_AT" | "EMAIL" | "EXPIRES_AT" | "FULL_NAME" | "ROLE";
export type OrderDirection = "ASC" | "DESC";
export type InvitationOrder = {
direction: OrderDirection;
field: InvitationOrderField;
};
export type SettingsInvitationsRefetchQuery$variables = {
after?: any | null | undefined;
before?: any | null | undefined;
first?: number | null | undefined;
id: string;
last?: number | null | undefined;
order?: InvitationOrder | null | undefined;
};
export type SettingsInvitationsRefetchQuery$data = {
readonly node: {
readonly " $fragmentSpreads": FragmentRefs<"SettingsPageInvitationsFragment">;
};
};
export type SettingsInvitationsRefetchQuery = {
response: SettingsInvitationsRefetchQuery$data;
variables: SettingsInvitationsRefetchQuery$variables;
};
const node: ConcreteRequest = (function(){
var v0 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "after"
},
v1 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "before"
},
v2 = {
"defaultValue": 20,
"kind": "LocalArgument",
"name": "first"
},
v3 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "id"
},
v4 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "last"
},
v5 = {
"defaultValue": {
"direction": "ASC",
"field": "CREATED_AT"
},
"kind": "LocalArgument",
"name": "order"
},
v6 = [
{
"kind": "Variable",
"name": "id",
"variableName": "id"
}
],
v7 = {
"kind": "Variable",
"name": "after",
"variableName": "after"
},
v8 = {
"kind": "Variable",
"name": "before",
"variableName": "before"
},
v9 = {
"kind": "Variable",
"name": "first",
"variableName": "first"
},
v10 = {
"kind": "Variable",
"name": "last",
"variableName": "last"
},
v11 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
},
v12 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
v13 = [
(v7/*: any*/),
(v8/*: any*/),
(v9/*: any*/),
(v10/*: any*/),
{
"kind": "Variable",
"name": "orderBy",
"variableName": "order"
}
];
return {
"fragment": {
"argumentDefinitions": [
(v0/*: any*/),
(v1/*: any*/),
(v2/*: any*/),
(v3/*: any*/),
(v4/*: any*/),
(v5/*: any*/)
],
"kind": "Fragment",
"metadata": null,
"name": "SettingsInvitationsRefetchQuery",
"selections": [
{
"alias": null,
"args": (v6/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
{
"args": [
(v7/*: any*/),
(v8/*: any*/),
(v9/*: any*/),
(v10/*: any*/),
{
"kind": "Variable",
"name": "order",
"variableName": "order"
}
],
"kind": "FragmentSpread",
"name": "SettingsPageInvitationsFragment"
}
],
"storageKey": null
}
],
"type": "Query",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": [
(v0/*: any*/),
(v1/*: any*/),
(v2/*: any*/),
(v4/*: any*/),
(v5/*: any*/),
(v3/*: any*/)
],
"kind": "Operation",
"name": "SettingsInvitationsRefetchQuery",
"selections": [
{
"alias": null,
"args": (v6/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v11/*: any*/),
(v12/*: any*/),
{
"kind": "InlineFragment",
"selections": [
{
"alias": null,
"args": (v13/*: any*/),
"concreteType": "InvitationConnection",
"kind": "LinkedField",
"name": "invitations",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "totalCount",
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "InvitationEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Invitation",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v12/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "email",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "fullName",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "role",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "expiresAt",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "acceptedAt",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "createdAt",
"storageKey": null
},
(v11/*: any*/)
],
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "cursor",
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "PageInfo",
"kind": "LinkedField",
"name": "pageInfo",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "endCursor",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasNextPage",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasPreviousPage",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "startCursor",
"storageKey": null
}
],
"storageKey": null
},
{
"kind": "ClientExtension",
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__id",
"storageKey": null
}
]
}
],
"storageKey": null
},
{
"alias": null,
"args": (v13/*: any*/),
"filters": [
"orderBy"
],
"handle": "connection",
"key": "SettingsPageInvitations_invitations",
"kind": "LinkedHandle",
"name": "invitations"
}
],
"type": "Organization",
"abstractKey": null
}
],
"storageKey": null
}
]
},
"params": {
"cacheID": "d1ad09b7e16875a4fc09c5e8dc7e3b7e",
"id": null,
"metadata": {},
"name": "SettingsInvitationsRefetchQuery",
"operationKind": "query",
"text": "query SettingsInvitationsRefetchQuery(\n $after: CursorKey = null\n $before: CursorKey = null\n $first: Int = 20\n $last: Int = null\n $order: InvitationOrder = {direction: ASC, field: CREATED_AT}\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...SettingsPageInvitationsFragment_16fISc\n id\n }\n}\n\nfragment SettingsPageInvitationsFragment_16fISc on Organization {\n invitations(first: $first, after: $after, last: $last, before: $before, orderBy: $order) {\n totalCount\n edges {\n node {\n id\n email\n fullName\n role\n expiresAt\n acceptedAt\n createdAt\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n"
}
};
})();
(node as any).hash = "d971d93653991efde284ed2b87068698";
export default node;

View File

@@ -0,0 +1,354 @@
/**
* @generated SignedSource<<49986e7498d757f2074e93e6cf4747a5>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime";
export type MembershipOrderField = "CREATED_AT" | "EMAIL_ADDRESS" | "FULL_NAME" | "ROLE";
export type OrderDirection = "ASC" | "DESC";
export type MembershipOrder = {
direction: OrderDirection;
field: MembershipOrderField;
};
export type SettingsMembershipsRefetchQuery$variables = {
after?: any | null | undefined;
before?: any | null | undefined;
first?: number | null | undefined;
id: string;
last?: number | null | undefined;
order?: MembershipOrder | null | undefined;
};
export type SettingsMembershipsRefetchQuery$data = {
readonly node: {
readonly " $fragmentSpreads": FragmentRefs<"SettingsPageMembershipsFragment">;
};
};
export type SettingsMembershipsRefetchQuery = {
response: SettingsMembershipsRefetchQuery$data;
variables: SettingsMembershipsRefetchQuery$variables;
};
const node: ConcreteRequest = (function(){
var v0 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "after"
},
v1 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "before"
},
v2 = {
"defaultValue": 20,
"kind": "LocalArgument",
"name": "first"
},
v3 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "id"
},
v4 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "last"
},
v5 = {
"defaultValue": {
"direction": "ASC",
"field": "CREATED_AT"
},
"kind": "LocalArgument",
"name": "order"
},
v6 = [
{
"kind": "Variable",
"name": "id",
"variableName": "id"
}
],
v7 = {
"kind": "Variable",
"name": "after",
"variableName": "after"
},
v8 = {
"kind": "Variable",
"name": "before",
"variableName": "before"
},
v9 = {
"kind": "Variable",
"name": "first",
"variableName": "first"
},
v10 = {
"kind": "Variable",
"name": "last",
"variableName": "last"
},
v11 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
},
v12 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
v13 = [
(v7/*: any*/),
(v8/*: any*/),
(v9/*: any*/),
(v10/*: any*/),
{
"kind": "Variable",
"name": "orderBy",
"variableName": "order"
}
];
return {
"fragment": {
"argumentDefinitions": [
(v0/*: any*/),
(v1/*: any*/),
(v2/*: any*/),
(v3/*: any*/),
(v4/*: any*/),
(v5/*: any*/)
],
"kind": "Fragment",
"metadata": null,
"name": "SettingsMembershipsRefetchQuery",
"selections": [
{
"alias": null,
"args": (v6/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
{
"args": [
(v7/*: any*/),
(v8/*: any*/),
(v9/*: any*/),
(v10/*: any*/),
{
"kind": "Variable",
"name": "order",
"variableName": "order"
}
],
"kind": "FragmentSpread",
"name": "SettingsPageMembershipsFragment"
}
],
"storageKey": null
}
],
"type": "Query",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": [
(v0/*: any*/),
(v1/*: any*/),
(v2/*: any*/),
(v4/*: any*/),
(v5/*: any*/),
(v3/*: any*/)
],
"kind": "Operation",
"name": "SettingsMembershipsRefetchQuery",
"selections": [
{
"alias": null,
"args": (v6/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v11/*: any*/),
(v12/*: any*/),
{
"kind": "InlineFragment",
"selections": [
{
"alias": null,
"args": (v13/*: any*/),
"concreteType": "MembershipConnection",
"kind": "LinkedField",
"name": "memberships",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "totalCount",
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "MembershipEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Membership",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v12/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "fullName",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "emailAddress",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "role",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "createdAt",
"storageKey": null
},
(v11/*: any*/)
],
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "cursor",
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "PageInfo",
"kind": "LinkedField",
"name": "pageInfo",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "endCursor",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasNextPage",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasPreviousPage",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "startCursor",
"storageKey": null
}
],
"storageKey": null
},
{
"kind": "ClientExtension",
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__id",
"storageKey": null
}
]
}
],
"storageKey": null
},
{
"alias": null,
"args": (v13/*: any*/),
"filters": [
"orderBy"
],
"handle": "connection",
"key": "SettingsPageMemberships_memberships",
"kind": "LinkedHandle",
"name": "memberships"
}
],
"type": "Organization",
"abstractKey": null
}
],
"storageKey": null
}
]
},
"params": {
"cacheID": "57c4ca08006166b58c1fb2407f091704",
"id": null,
"metadata": {},
"name": "SettingsMembershipsRefetchQuery",
"operationKind": "query",
"text": "query SettingsMembershipsRefetchQuery(\n $after: CursorKey = null\n $before: CursorKey = null\n $first: Int = 20\n $last: Int = null\n $order: MembershipOrder = {direction: ASC, field: CREATED_AT}\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...SettingsPageMembershipsFragment_16fISc\n id\n }\n}\n\nfragment SettingsPageMembershipsFragment_16fISc on Organization {\n memberships(first: $first, after: $after, last: $last, before: $before, orderBy: $order) {\n totalCount\n edges {\n node {\n id\n fullName\n emailAddress\n role\n createdAt\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n"
}
};
})();
(node as any).hash = "d28514cdb5181fc1023dc4ea5bddb4f2";
export default node;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<122f3da12674107565d07159872492db>>
* @generated SignedSource<<8477f42a02a102a4ce8540b794ac4289>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -22,6 +22,7 @@ export type SettingsPageFragment$data = {
};
}>;
};
readonly createdAt: any;
readonly customDomain: {
readonly createdAt: any;
readonly dnsRecords: ReadonlyArray<{
@@ -44,16 +45,7 @@ export type SettingsPageFragment$data = {
readonly id: string;
readonly logoUrl: string | null | undefined;
readonly name: string;
readonly users: {
readonly edges: ReadonlyArray<{
readonly node: {
readonly createdAt: any;
readonly email: string;
readonly fullName: string;
readonly id: string;
};
}>;
};
readonly updatedAt: any;
readonly websiteUrl: string | null | undefined;
readonly " $fragmentType": "SettingsPageFragment";
};
@@ -81,30 +73,23 @@ v2 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "email",
"name": "type",
"storageKey": null
},
v3 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "type",
"name": "createdAt",
"storageKey": null
},
v4 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "createdAt",
"name": "updatedAt",
"storageKey": null
},
v5 = [
{
"kind": "Literal",
"name": "first",
"value": 100
}
];
};
return {
"argumentDefinitions": [],
"kind": "Fragment",
@@ -141,7 +126,13 @@ return {
"name": "websiteUrl",
"storageKey": null
},
(v2/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "email",
"storageKey": null
},
{
"alias": null,
"args": null,
@@ -180,7 +171,7 @@ return {
"name": "dnsRecords",
"plural": true,
"selections": [
(v3/*: any*/),
(v2/*: any*/),
(v1/*: any*/),
{
"alias": null,
@@ -206,14 +197,8 @@ return {
],
"storageKey": null
},
(v3/*: any*/),
(v4/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "updatedAt",
"storageKey": null
},
{
"alias": null,
"args": null,
@@ -224,52 +209,17 @@ return {
],
"storageKey": null
},
(v3/*: any*/),
(v4/*: any*/),
{
"alias": null,
"args": (v5/*: any*/),
"concreteType": "UserConnection",
"kind": "LinkedField",
"name": "users",
"plural": false,
"selections": [
"args": [
{
"alias": null,
"args": null,
"concreteType": "UserEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "User",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v0/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "fullName",
"storageKey": null
},
(v2/*: any*/),
(v4/*: any*/)
],
"storageKey": null
}
],
"storageKey": null
"kind": "Literal",
"name": "first",
"value": 100
}
],
"storageKey": "users(first:100)"
},
{
"alias": null,
"args": (v5/*: any*/),
"concreteType": "ConnectorConnection",
"kind": "LinkedField",
"name": "connectors",
@@ -293,8 +243,8 @@ return {
"selections": [
(v0/*: any*/),
(v1/*: any*/),
(v3/*: any*/),
(v4/*: any*/)
(v2/*: any*/),
(v3/*: any*/)
],
"storageKey": null
}
@@ -310,6 +260,6 @@ return {
};
})();
(node as any).hash = "6cea6f88fb0d7b2ae7ef9053b9979898";
(node as any).hash = "b3b152b507befd6b6918a12972e05f14";
export default node;

View File

@@ -0,0 +1,278 @@
/**
* @generated SignedSource<<4f099d1ee6b4635ca8129eca77d3f7e8>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ReaderFragment } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime";
export type SettingsPageInvitationsFragment$data = {
readonly id: string;
readonly invitations: {
readonly __id: string;
readonly edges: ReadonlyArray<{
readonly node: {
readonly acceptedAt: any | null | undefined;
readonly createdAt: any;
readonly email: string;
readonly expiresAt: any;
readonly fullName: string;
readonly id: string;
readonly role: string;
};
}>;
readonly totalCount: number;
};
readonly " $fragmentType": "SettingsPageInvitationsFragment";
};
export type SettingsPageInvitationsFragment$key = {
readonly " $data"?: SettingsPageInvitationsFragment$data;
readonly " $fragmentSpreads": FragmentRefs<"SettingsPageInvitationsFragment">;
};
import SettingsInvitationsRefetchQuery_graphql from './SettingsInvitationsRefetchQuery.graphql';
const node: ReaderFragment = (function(){
var v0 = [
"invitations"
],
v1 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
};
return {
"argumentDefinitions": [
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "after"
},
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "before"
},
{
"defaultValue": 20,
"kind": "LocalArgument",
"name": "first"
},
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "last"
},
{
"defaultValue": {
"direction": "ASC",
"field": "CREATED_AT"
},
"kind": "LocalArgument",
"name": "order"
}
],
"kind": "Fragment",
"metadata": {
"connection": [
{
"count": null,
"cursor": null,
"direction": "bidirectional",
"path": (v0/*: any*/)
}
],
"refetch": {
"connection": {
"forward": {
"count": "first",
"cursor": "after"
},
"backward": {
"count": "last",
"cursor": "before"
},
"path": (v0/*: any*/)
},
"fragmentPathInResult": [
"node"
],
"operation": SettingsInvitationsRefetchQuery_graphql,
"identifierInfo": {
"identifierField": "id",
"identifierQueryVariableName": "id"
}
}
},
"name": "SettingsPageInvitationsFragment",
"selections": [
{
"alias": "invitations",
"args": [
{
"kind": "Variable",
"name": "orderBy",
"variableName": "order"
}
],
"concreteType": "InvitationConnection",
"kind": "LinkedField",
"name": "__SettingsPageInvitations_invitations_connection",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "totalCount",
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "InvitationEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Invitation",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v1/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "email",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "fullName",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "role",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "expiresAt",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "acceptedAt",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "createdAt",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "cursor",
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "PageInfo",
"kind": "LinkedField",
"name": "pageInfo",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "endCursor",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasNextPage",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasPreviousPage",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "startCursor",
"storageKey": null
}
],
"storageKey": null
},
{
"kind": "ClientExtension",
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__id",
"storageKey": null
}
]
}
],
"storageKey": null
},
(v1/*: any*/)
],
"type": "Organization",
"abstractKey": null
};
})();
(node as any).hash = "d971d93653991efde284ed2b87068698";
export default node;

View File

@@ -0,0 +1,262 @@
/**
* @generated SignedSource<<778a6585d3f3d9b346273c20319ce96d>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ReaderFragment } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime";
export type SettingsPageMembershipsFragment$data = {
readonly id: string;
readonly memberships: {
readonly __id: string;
readonly edges: ReadonlyArray<{
readonly node: {
readonly createdAt: any;
readonly emailAddress: string;
readonly fullName: string;
readonly id: string;
readonly role: string;
};
}>;
readonly totalCount: number;
};
readonly " $fragmentType": "SettingsPageMembershipsFragment";
};
export type SettingsPageMembershipsFragment$key = {
readonly " $data"?: SettingsPageMembershipsFragment$data;
readonly " $fragmentSpreads": FragmentRefs<"SettingsPageMembershipsFragment">;
};
import SettingsMembershipsRefetchQuery_graphql from './SettingsMembershipsRefetchQuery.graphql';
const node: ReaderFragment = (function(){
var v0 = [
"memberships"
],
v1 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
};
return {
"argumentDefinitions": [
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "after"
},
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "before"
},
{
"defaultValue": 20,
"kind": "LocalArgument",
"name": "first"
},
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "last"
},
{
"defaultValue": {
"direction": "ASC",
"field": "CREATED_AT"
},
"kind": "LocalArgument",
"name": "order"
}
],
"kind": "Fragment",
"metadata": {
"connection": [
{
"count": null,
"cursor": null,
"direction": "bidirectional",
"path": (v0/*: any*/)
}
],
"refetch": {
"connection": {
"forward": {
"count": "first",
"cursor": "after"
},
"backward": {
"count": "last",
"cursor": "before"
},
"path": (v0/*: any*/)
},
"fragmentPathInResult": [
"node"
],
"operation": SettingsMembershipsRefetchQuery_graphql,
"identifierInfo": {
"identifierField": "id",
"identifierQueryVariableName": "id"
}
}
},
"name": "SettingsPageMembershipsFragment",
"selections": [
{
"alias": "memberships",
"args": [
{
"kind": "Variable",
"name": "orderBy",
"variableName": "order"
}
],
"concreteType": "MembershipConnection",
"kind": "LinkedField",
"name": "__SettingsPageMemberships_memberships_connection",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "totalCount",
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "MembershipEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Membership",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v1/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "fullName",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "emailAddress",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "role",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "createdAt",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "cursor",
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "PageInfo",
"kind": "LinkedField",
"name": "pageInfo",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "endCursor",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasNextPage",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasPreviousPage",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "startCursor",
"storageKey": null
}
],
"storageKey": null
},
{
"kind": "ClientExtension",
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__id",
"storageKey": null
}
]
}
],
"storageKey": null
},
(v1/*: any*/)
],
"type": "Organization",
"abstractKey": null
};
})();
(node as any).hash = "d28514cdb5181fc1023dc4ea5bddb4f2";
export default node;

View File

@@ -0,0 +1,132 @@
/**
* @generated SignedSource<<f058193b755f9fed3efe4910aae9a7e3>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
export type DeleteInvitationInput = {
invitationId: string;
};
export type SettingsPage_DeleteInvitationMutation$variables = {
connections: ReadonlyArray<string>;
input: DeleteInvitationInput;
};
export type SettingsPage_DeleteInvitationMutation$data = {
readonly deleteInvitation: {
readonly deletedInvitationId: string;
};
};
export type SettingsPage_DeleteInvitationMutation = {
response: SettingsPage_DeleteInvitationMutation$data;
variables: SettingsPage_DeleteInvitationMutation$variables;
};
const node: ConcreteRequest = (function(){
var v0 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "connections"
},
v1 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "input"
},
v2 = [
{
"kind": "Variable",
"name": "input",
"variableName": "input"
}
],
v3 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "deletedInvitationId",
"storageKey": null
};
return {
"fragment": {
"argumentDefinitions": [
(v0/*: any*/),
(v1/*: any*/)
],
"kind": "Fragment",
"metadata": null,
"name": "SettingsPage_DeleteInvitationMutation",
"selections": [
{
"alias": null,
"args": (v2/*: any*/),
"concreteType": "DeleteInvitationPayload",
"kind": "LinkedField",
"name": "deleteInvitation",
"plural": false,
"selections": [
(v3/*: any*/)
],
"storageKey": null
}
],
"type": "Mutation",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": [
(v1/*: any*/),
(v0/*: any*/)
],
"kind": "Operation",
"name": "SettingsPage_DeleteInvitationMutation",
"selections": [
{
"alias": null,
"args": (v2/*: any*/),
"concreteType": "DeleteInvitationPayload",
"kind": "LinkedField",
"name": "deleteInvitation",
"plural": false,
"selections": [
(v3/*: any*/),
{
"alias": null,
"args": null,
"filters": null,
"handle": "deleteEdge",
"key": "",
"kind": "ScalarHandle",
"name": "deletedInvitationId",
"handleArgs": [
{
"kind": "Variable",
"name": "connections",
"variableName": "connections"
}
]
}
],
"storageKey": null
}
]
},
"params": {
"cacheID": "1c362c5db7a985d7548166b2b1eb42c9",
"id": null,
"metadata": {},
"name": "SettingsPage_DeleteInvitationMutation",
"operationKind": "mutation",
"text": "mutation SettingsPage_DeleteInvitationMutation(\n $input: DeleteInvitationInput!\n) {\n deleteInvitation(input: $input) {\n deletedInvitationId\n }\n}\n"
}
};
})();
(node as any).hash = "3c484508ba04b5a75eca62fa6afeb16d";
export default node;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<e5fd0bf99e25c4f410c6c53f4025ed15>>
* @generated SignedSource<<994eb713978ecef3329fd9873e4c744c>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -9,21 +9,21 @@
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
export type RemoveUserInput = {
export type RemoveMemberInput = {
memberId: string;
organizationId: string;
userId: string;
};
export type SettingsPage_RemoveUserMutation$variables = {
input: RemoveUserInput;
export type SettingsPage_RemoveMemberMutation$variables = {
input: RemoveMemberInput;
};
export type SettingsPage_RemoveUserMutation$data = {
readonly removeUser: {
export type SettingsPage_RemoveMemberMutation$data = {
readonly removeMember: {
readonly success: boolean;
};
};
export type SettingsPage_RemoveUserMutation = {
response: SettingsPage_RemoveUserMutation$data;
variables: SettingsPage_RemoveUserMutation$variables;
export type SettingsPage_RemoveMemberMutation = {
response: SettingsPage_RemoveMemberMutation$data;
variables: SettingsPage_RemoveMemberMutation$variables;
};
const node: ConcreteRequest = (function(){
@@ -44,9 +44,9 @@ v1 = [
"variableName": "input"
}
],
"concreteType": "RemoveUserPayload",
"concreteType": "RemoveMemberPayload",
"kind": "LinkedField",
"name": "removeUser",
"name": "removeMember",
"plural": false,
"selections": [
{
@@ -65,7 +65,7 @@ return {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "SettingsPage_RemoveUserMutation",
"name": "SettingsPage_RemoveMemberMutation",
"selections": (v1/*: any*/),
"type": "Mutation",
"abstractKey": null
@@ -74,20 +74,20 @@ return {
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "SettingsPage_RemoveUserMutation",
"name": "SettingsPage_RemoveMemberMutation",
"selections": (v1/*: any*/)
},
"params": {
"cacheID": "a397335d917a93baf77ceba83c735326",
"cacheID": "97e29046871ce8aab01abf98a62236fc",
"id": null,
"metadata": {},
"name": "SettingsPage_RemoveUserMutation",
"name": "SettingsPage_RemoveMemberMutation",
"operationKind": "mutation",
"text": "mutation SettingsPage_RemoveUserMutation(\n $input: RemoveUserInput!\n) {\n removeUser(input: $input) {\n success\n }\n}\n"
"text": "mutation SettingsPage_RemoveMemberMutation(\n $input: RemoveMemberInput!\n) {\n removeMember(input: $input) {\n success\n }\n}\n"
}
};
})();
(node as any).hash = "ba5bf0e182d15f4805080f63d1604d91";
(node as any).hash = "f61071a0fb6f6554e56e79b6b04bc135";
export default node;