Order organization by name
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
@@ -30,36 +30,60 @@ import {
|
||||
DropdownItem,
|
||||
IconChevronGrabberVertical,
|
||||
IconPlusLarge,
|
||||
IconChevronDown,
|
||||
Avatar,
|
||||
} from "@probo/ui";
|
||||
import { useTranslate } from "@probo/i18n";
|
||||
import { graphql } from "relay-runtime";
|
||||
import { useLazyLoadQuery } from "react-relay";
|
||||
import { useLazyLoadQuery, usePaginationFragment } from "react-relay";
|
||||
import type { MainLayoutQuery as MainLayoutQueryType } from "./__generated__/MainLayoutQuery.graphql";
|
||||
import { Suspense } from "react";
|
||||
import type { MainLayout_OrganizationSelector_viewer$key } from "./__generated__/MainLayout_OrganizationSelector_viewer.graphql";
|
||||
import { Suspense, useState } from "react";
|
||||
import { useToast } from "@probo/ui";
|
||||
import { ErrorBoundary } from "react-error-boundary";
|
||||
import { PageError } from "/components/PageError";
|
||||
import { buildEndpoint } from "/providers/RelayProviders";
|
||||
|
||||
const MainLayoutQuery = graphql`
|
||||
query MainLayoutQuery {
|
||||
query MainLayoutQuery($organizationId: ID!) {
|
||||
viewer {
|
||||
id
|
||||
user {
|
||||
fullName
|
||||
email
|
||||
}
|
||||
organizations(first: 25) @connection(key: "MainLayout_organizations") {
|
||||
__id
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
name
|
||||
logoUrl
|
||||
}
|
||||
...MainLayout_OrganizationSelector_viewer
|
||||
}
|
||||
organization: node(id: $organizationId) {
|
||||
... on Organization {
|
||||
id
|
||||
name
|
||||
logoUrl
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const OrganizationSelectorFragment = graphql`
|
||||
fragment MainLayout_OrganizationSelector_viewer on Viewer
|
||||
@refetchable(queryName: "MainLayoutOrganizationSelectorPaginationQuery")
|
||||
@argumentDefinitions(
|
||||
first: { type: "Int", defaultValue: 25 }
|
||||
after: { type: "CursorKey" }
|
||||
) {
|
||||
organizations(first: $first, after: $after, orderBy: {field: NAME, direction: ASC})
|
||||
@connection(key: "MainLayout_OrganizationSelector_organizations") {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
name
|
||||
logoUrl
|
||||
}
|
||||
}
|
||||
pageInfo {
|
||||
hasNextPage
|
||||
endCursor
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
@@ -83,11 +107,11 @@ export function MainLayout() {
|
||||
<>
|
||||
<div className="mr-auto">
|
||||
<Suspense fallback={<Skeleton className="w-20 h-8" />}>
|
||||
<OrganizationSelector organizationId={organizationId} />
|
||||
<OrganizationSelectorWrapper organizationId={organizationId} />
|
||||
</Suspense>
|
||||
</div>
|
||||
<Suspense fallback={<Skeleton className="w-32 h-8" />}>
|
||||
<UserDropdown />
|
||||
<UserDropdown organizationId={organizationId} />
|
||||
</Suspense>
|
||||
</>
|
||||
}
|
||||
@@ -188,10 +212,10 @@ export function MainLayout() {
|
||||
);
|
||||
}
|
||||
|
||||
function UserDropdown() {
|
||||
function UserDropdown({ organizationId }: { organizationId: string }) {
|
||||
const { __ } = useTranslate();
|
||||
const { toast } = useToast();
|
||||
const user = useLazyLoadQuery<MainLayoutQueryType>(MainLayoutQuery, {}).viewer
|
||||
const user = useLazyLoadQuery<MainLayoutQueryType>(MainLayoutQuery, { organizationId }).viewer
|
||||
.user;
|
||||
|
||||
const handleLogout: React.MouseEventHandler<HTMLAnchorElement> = async (
|
||||
@@ -242,16 +266,40 @@ function UserDropdown() {
|
||||
);
|
||||
}
|
||||
|
||||
function OrganizationSelector({ organizationId }: { organizationId: string }) {
|
||||
const organizations = useLazyLoadQuery<MainLayoutQueryType>(
|
||||
MainLayoutQuery,
|
||||
{}
|
||||
).viewer.organizations.edges.map((edge) => edge.node);
|
||||
const currentOrganization = organizations.find(
|
||||
(organization) => organization.id === organizationId
|
||||
);
|
||||
function OrganizationSelectorWrapper({ organizationId }: { organizationId: string }) {
|
||||
const data = useLazyLoadQuery<MainLayoutQueryType>(MainLayoutQuery, { organizationId });
|
||||
return <OrganizationSelector viewer={data.viewer} currentOrganization={data.organization} />;
|
||||
}
|
||||
|
||||
function OrganizationSelector({
|
||||
viewer,
|
||||
currentOrganization
|
||||
}: {
|
||||
viewer: MainLayout_OrganizationSelector_viewer$key;
|
||||
currentOrganization: MainLayoutQueryType["response"]["organization"];
|
||||
}) {
|
||||
const [isLoadingMore, setIsLoadingMore] = useState(false);
|
||||
const { __ } = useTranslate();
|
||||
|
||||
const { data, loadNext, hasNext } = usePaginationFragment(
|
||||
OrganizationSelectorFragment,
|
||||
viewer
|
||||
);
|
||||
|
||||
const organizations = data.organizations.edges.map((edge) => edge.node);
|
||||
|
||||
const handleLoadMore = (e?: React.MouseEvent) => {
|
||||
e?.preventDefault();
|
||||
e?.stopPropagation();
|
||||
|
||||
if (hasNext && !isLoadingMore) {
|
||||
setIsLoadingMore(true);
|
||||
loadNext(25, {
|
||||
onComplete: () => setIsLoadingMore(false),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Dropdown
|
||||
toggle={
|
||||
@@ -260,22 +308,40 @@ function OrganizationSelector({ organizationId }: { organizationId: string }) {
|
||||
variant="tertiary"
|
||||
iconAfter={IconChevronGrabberVertical}
|
||||
>
|
||||
{currentOrganization?.name}
|
||||
{currentOrganization?.name || ""}
|
||||
</Button>
|
||||
}
|
||||
>
|
||||
{organizations.map((organization) => (
|
||||
<DropdownItem
|
||||
asChild
|
||||
key={organization.id}
|
||||
icon={IconCircleQuestionmark}
|
||||
>
|
||||
<Link to={`/organizations/${organization.id}`}>
|
||||
<Avatar src={organization.logoUrl} name={organization.name} />
|
||||
{organization.name}
|
||||
</Link>
|
||||
</DropdownItem>
|
||||
))}
|
||||
<div className="max-h-150 overflow-y-auto scrollbar-thin scrollbar-thumb-gray-300 scrollbar-track-transparent hover:scrollbar-thumb-gray-400">
|
||||
{organizations.map((organization) => (
|
||||
<DropdownItem
|
||||
asChild
|
||||
key={organization.id}
|
||||
>
|
||||
<Link to={`/organizations/${organization.id}`}>
|
||||
<Avatar src={organization.logoUrl} name={organization.name} />
|
||||
{organization.name}
|
||||
</Link>
|
||||
</DropdownItem>
|
||||
))}
|
||||
{hasNext && (
|
||||
<div className="px-3 py-1 flex justify-center">
|
||||
<Button
|
||||
variant="tertiary"
|
||||
onClick={handleLoadMore}
|
||||
onMouseDown={(e: React.MouseEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}}
|
||||
className="mx-auto"
|
||||
icon={IconChevronDown}
|
||||
disabled={isLoadingMore}
|
||||
>
|
||||
{isLoadingMore ? __("Loading...") : __("Show More")}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<DropdownSeparator />
|
||||
<DropdownItem asChild icon={IconPlusLarge}>
|
||||
<Link to="/organizations/new">
|
||||
|
||||
230
apps/console/src/layouts/__generated__/MainLayoutOrganizationSelectorPaginationQuery.graphql.ts
generated
Normal file
230
apps/console/src/layouts/__generated__/MainLayoutOrganizationSelectorPaginationQuery.graphql.ts
generated
Normal file
@@ -0,0 +1,230 @@
|
||||
/**
|
||||
* @generated SignedSource<<92c96c7b8a58554e9fb99b86489e13d4>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
|
||||
import { ConcreteRequest } from 'relay-runtime';
|
||||
import { FragmentRefs } from "relay-runtime";
|
||||
export type MainLayoutOrganizationSelectorPaginationQuery$variables = {
|
||||
after?: any | null | undefined;
|
||||
first?: number | null | undefined;
|
||||
};
|
||||
export type MainLayoutOrganizationSelectorPaginationQuery$data = {
|
||||
readonly viewer: {
|
||||
readonly " $fragmentSpreads": FragmentRefs<"MainLayout_OrganizationSelector_viewer">;
|
||||
};
|
||||
};
|
||||
export type MainLayoutOrganizationSelectorPaginationQuery = {
|
||||
response: MainLayoutOrganizationSelectorPaginationQuery$data;
|
||||
variables: MainLayoutOrganizationSelectorPaginationQuery$variables;
|
||||
};
|
||||
|
||||
const node: ConcreteRequest = (function(){
|
||||
var v0 = [
|
||||
{
|
||||
"defaultValue": null,
|
||||
"kind": "LocalArgument",
|
||||
"name": "after"
|
||||
},
|
||||
{
|
||||
"defaultValue": 25,
|
||||
"kind": "LocalArgument",
|
||||
"name": "first"
|
||||
}
|
||||
],
|
||||
v1 = {
|
||||
"kind": "Variable",
|
||||
"name": "after",
|
||||
"variableName": "after"
|
||||
},
|
||||
v2 = {
|
||||
"kind": "Variable",
|
||||
"name": "first",
|
||||
"variableName": "first"
|
||||
},
|
||||
v3 = [
|
||||
(v1/*: any*/),
|
||||
(v2/*: any*/),
|
||||
{
|
||||
"kind": "Literal",
|
||||
"name": "orderBy",
|
||||
"value": {
|
||||
"direction": "ASC",
|
||||
"field": "NAME"
|
||||
}
|
||||
}
|
||||
],
|
||||
v4 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "id",
|
||||
"storageKey": null
|
||||
};
|
||||
return {
|
||||
"fragment": {
|
||||
"argumentDefinitions": (v0/*: any*/),
|
||||
"kind": "Fragment",
|
||||
"metadata": null,
|
||||
"name": "MainLayoutOrganizationSelectorPaginationQuery",
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "Viewer",
|
||||
"kind": "LinkedField",
|
||||
"name": "viewer",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
{
|
||||
"args": [
|
||||
(v1/*: any*/),
|
||||
(v2/*: any*/)
|
||||
],
|
||||
"kind": "FragmentSpread",
|
||||
"name": "MainLayout_OrganizationSelector_viewer"
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"type": "Query",
|
||||
"abstractKey": null
|
||||
},
|
||||
"kind": "Request",
|
||||
"operation": {
|
||||
"argumentDefinitions": (v0/*: any*/),
|
||||
"kind": "Operation",
|
||||
"name": "MainLayoutOrganizationSelectorPaginationQuery",
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "Viewer",
|
||||
"kind": "LinkedField",
|
||||
"name": "viewer",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v3/*: any*/),
|
||||
"concreteType": "OrganizationConnection",
|
||||
"kind": "LinkedField",
|
||||
"name": "organizations",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "OrganizationEdge",
|
||||
"kind": "LinkedField",
|
||||
"name": "edges",
|
||||
"plural": true,
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "Organization",
|
||||
"kind": "LinkedField",
|
||||
"name": "node",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v4/*: any*/),
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "name",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "logoUrl",
|
||||
"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": "hasNextPage",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "endCursor",
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v3/*: any*/),
|
||||
"filters": [
|
||||
"orderBy"
|
||||
],
|
||||
"handle": "connection",
|
||||
"key": "MainLayout_OrganizationSelector_organizations",
|
||||
"kind": "LinkedHandle",
|
||||
"name": "organizations"
|
||||
},
|
||||
(v4/*: any*/)
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"params": {
|
||||
"cacheID": "57fa65c9d5f23210b606fbf0b2005fb8",
|
||||
"id": null,
|
||||
"metadata": {},
|
||||
"name": "MainLayoutOrganizationSelectorPaginationQuery",
|
||||
"operationKind": "query",
|
||||
"text": "query MainLayoutOrganizationSelectorPaginationQuery(\n $after: CursorKey\n $first: Int = 25\n) {\n viewer {\n ...MainLayout_OrganizationSelector_viewer_2HEEH6\n id\n }\n}\n\nfragment MainLayout_OrganizationSelector_viewer_2HEEH6 on Viewer {\n organizations(first: $first, after: $after, orderBy: {field: NAME, direction: ASC}) {\n edges {\n node {\n id\n name\n logoUrl\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n"
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
(node as any).hash = "0dc2841aeeb6ba5291cb45d8644ec4af";
|
||||
|
||||
export default node;
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @generated SignedSource<<d411922830ba632f8c48c98caa435a22>>
|
||||
* @generated SignedSource<<0719379cc0124f36eb1810ad24b2ae5a>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
@@ -9,24 +9,23 @@
|
||||
// @ts-nocheck
|
||||
|
||||
import { ConcreteRequest } from 'relay-runtime';
|
||||
export type MainLayoutQuery$variables = Record<PropertyKey, never>;
|
||||
import { FragmentRefs } from "relay-runtime";
|
||||
export type MainLayoutQuery$variables = {
|
||||
organizationId: string;
|
||||
};
|
||||
export type MainLayoutQuery$data = {
|
||||
readonly organization: {
|
||||
readonly id?: string;
|
||||
readonly logoUrl?: string | null | undefined;
|
||||
readonly name?: string;
|
||||
};
|
||||
readonly viewer: {
|
||||
readonly id: string;
|
||||
readonly organizations: {
|
||||
readonly __id: string;
|
||||
readonly edges: ReadonlyArray<{
|
||||
readonly node: {
|
||||
readonly id: string;
|
||||
readonly logoUrl: string | null | undefined;
|
||||
readonly name: string;
|
||||
};
|
||||
}>;
|
||||
};
|
||||
readonly user: {
|
||||
readonly email: string;
|
||||
readonly fullName: string;
|
||||
};
|
||||
readonly " $fragmentSpreads": FragmentRefs<"MainLayout_OrganizationSelector_viewer">;
|
||||
};
|
||||
};
|
||||
export type MainLayoutQuery = {
|
||||
@@ -35,127 +34,80 @@ export type MainLayoutQuery = {
|
||||
};
|
||||
|
||||
const node: ConcreteRequest = (function(){
|
||||
var v0 = {
|
||||
var v0 = [
|
||||
{
|
||||
"defaultValue": null,
|
||||
"kind": "LocalArgument",
|
||||
"name": "organizationId"
|
||||
}
|
||||
],
|
||||
v1 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "id",
|
||||
"storageKey": null
|
||||
},
|
||||
v1 = {
|
||||
v2 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "fullName",
|
||||
"storageKey": null
|
||||
},
|
||||
v2 = {
|
||||
v3 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "email",
|
||||
"storageKey": null
|
||||
},
|
||||
v3 = [
|
||||
v4 = [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "OrganizationEdge",
|
||||
"kind": "LinkedField",
|
||||
"name": "edges",
|
||||
"plural": true,
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "Organization",
|
||||
"kind": "LinkedField",
|
||||
"name": "node",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v0/*: any*/),
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "name",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "logoUrl",
|
||||
"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
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"kind": "ClientExtension",
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "__id",
|
||||
"storageKey": null
|
||||
}
|
||||
]
|
||||
"kind": "Variable",
|
||||
"name": "id",
|
||||
"variableName": "organizationId"
|
||||
}
|
||||
],
|
||||
v4 = [
|
||||
v5 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "name",
|
||||
"storageKey": null
|
||||
},
|
||||
v6 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "logoUrl",
|
||||
"storageKey": null
|
||||
},
|
||||
v7 = [
|
||||
{
|
||||
"kind": "Literal",
|
||||
"name": "first",
|
||||
"value": 25
|
||||
},
|
||||
{
|
||||
"kind": "Literal",
|
||||
"name": "orderBy",
|
||||
"value": {
|
||||
"direction": "ASC",
|
||||
"field": "NAME"
|
||||
}
|
||||
}
|
||||
];
|
||||
],
|
||||
v8 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "__typename",
|
||||
"storageKey": null
|
||||
};
|
||||
return {
|
||||
"fragment": {
|
||||
"argumentDefinitions": [],
|
||||
"argumentDefinitions": (v0/*: any*/),
|
||||
"kind": "Fragment",
|
||||
"metadata": null,
|
||||
"name": "MainLayoutQuery",
|
||||
@@ -168,7 +120,7 @@ return {
|
||||
"name": "viewer",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v0/*: any*/),
|
||||
(v1/*: any*/),
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
@@ -177,20 +129,36 @@ return {
|
||||
"name": "user",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v1/*: any*/),
|
||||
(v2/*: any*/)
|
||||
(v2/*: any*/),
|
||||
(v3/*: any*/)
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": "organizations",
|
||||
"args": null,
|
||||
"concreteType": "OrganizationConnection",
|
||||
"kind": "LinkedField",
|
||||
"name": "__MainLayout_organizations_connection",
|
||||
"plural": false,
|
||||
"selections": (v3/*: any*/),
|
||||
"storageKey": null
|
||||
"kind": "FragmentSpread",
|
||||
"name": "MainLayout_OrganizationSelector_viewer"
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": "organization",
|
||||
"args": (v4/*: any*/),
|
||||
"concreteType": null,
|
||||
"kind": "LinkedField",
|
||||
"name": "node",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
{
|
||||
"kind": "InlineFragment",
|
||||
"selections": [
|
||||
(v1/*: any*/),
|
||||
(v5/*: any*/),
|
||||
(v6/*: any*/)
|
||||
],
|
||||
"type": "Organization",
|
||||
"abstractKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
@@ -201,7 +169,7 @@ return {
|
||||
},
|
||||
"kind": "Request",
|
||||
"operation": {
|
||||
"argumentDefinitions": [],
|
||||
"argumentDefinitions": (v0/*: any*/),
|
||||
"kind": "Operation",
|
||||
"name": "MainLayoutQuery",
|
||||
"selections": [
|
||||
@@ -213,7 +181,7 @@ return {
|
||||
"name": "viewer",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v0/*: any*/),
|
||||
(v1/*: any*/),
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
@@ -222,59 +190,130 @@ return {
|
||||
"name": "user",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v1/*: any*/),
|
||||
(v2/*: any*/),
|
||||
(v0/*: any*/)
|
||||
(v3/*: any*/),
|
||||
(v1/*: any*/)
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v4/*: any*/),
|
||||
"args": (v7/*: any*/),
|
||||
"concreteType": "OrganizationConnection",
|
||||
"kind": "LinkedField",
|
||||
"name": "organizations",
|
||||
"plural": false,
|
||||
"selections": (v3/*: any*/),
|
||||
"storageKey": "organizations(first:25)"
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "OrganizationEdge",
|
||||
"kind": "LinkedField",
|
||||
"name": "edges",
|
||||
"plural": true,
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "Organization",
|
||||
"kind": "LinkedField",
|
||||
"name": "node",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v1/*: any*/),
|
||||
(v5/*: any*/),
|
||||
(v6/*: any*/),
|
||||
(v8/*: 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": "hasNextPage",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "endCursor",
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": "organizations(first:25,orderBy:{\"direction\":\"ASC\",\"field\":\"NAME\"})"
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v4/*: any*/),
|
||||
"filters": null,
|
||||
"args": (v7/*: any*/),
|
||||
"filters": [
|
||||
"orderBy"
|
||||
],
|
||||
"handle": "connection",
|
||||
"key": "MainLayout_organizations",
|
||||
"key": "MainLayout_OrganizationSelector_organizations",
|
||||
"kind": "LinkedHandle",
|
||||
"name": "organizations"
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": "organization",
|
||||
"args": (v4/*: any*/),
|
||||
"concreteType": null,
|
||||
"kind": "LinkedField",
|
||||
"name": "node",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v8/*: any*/),
|
||||
(v1/*: any*/),
|
||||
{
|
||||
"kind": "InlineFragment",
|
||||
"selections": [
|
||||
(v5/*: any*/),
|
||||
(v6/*: any*/)
|
||||
],
|
||||
"type": "Organization",
|
||||
"abstractKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"params": {
|
||||
"cacheID": "9ab80df970b8fa7c4eabff75a6730ec5",
|
||||
"cacheID": "6287440397ef427d84f8734b0953784c",
|
||||
"id": null,
|
||||
"metadata": {
|
||||
"connection": [
|
||||
{
|
||||
"count": null,
|
||||
"cursor": null,
|
||||
"direction": "forward",
|
||||
"path": [
|
||||
"viewer",
|
||||
"organizations"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"name": "MainLayoutQuery",
|
||||
"operationKind": "query",
|
||||
"text": "query MainLayoutQuery {\n viewer {\n id\n user {\n fullName\n email\n id\n }\n organizations(first: 25) {\n edges {\n node {\n id\n name\n logoUrl\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n}\n"
|
||||
"text": "query MainLayoutQuery(\n $organizationId: ID!\n) {\n viewer {\n id\n user {\n fullName\n email\n id\n }\n ...MainLayout_OrganizationSelector_viewer\n }\n organization: node(id: $organizationId) {\n __typename\n ... on Organization {\n id\n name\n logoUrl\n }\n id\n }\n}\n\nfragment MainLayout_OrganizationSelector_viewer on Viewer {\n organizations(first: 25, orderBy: {field: NAME, direction: ASC}) {\n edges {\n node {\n id\n name\n logoUrl\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n"
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
(node as any).hash = "fc37d1b70f1a239abb4c959d47ee28fd";
|
||||
(node as any).hash = "aaaca58a896839aa85ce7c2fcf75de39";
|
||||
|
||||
export default node;
|
||||
|
||||
190
apps/console/src/layouts/__generated__/MainLayout_OrganizationSelector_viewer.graphql.ts
generated
Normal file
190
apps/console/src/layouts/__generated__/MainLayout_OrganizationSelector_viewer.graphql.ts
generated
Normal file
@@ -0,0 +1,190 @@
|
||||
/**
|
||||
* @generated SignedSource<<2eda1054dbabd2bb5e45d8db5c7a01fc>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
|
||||
import { ReaderFragment } from 'relay-runtime';
|
||||
import { FragmentRefs } from "relay-runtime";
|
||||
export type MainLayout_OrganizationSelector_viewer$data = {
|
||||
readonly organizations: {
|
||||
readonly edges: ReadonlyArray<{
|
||||
readonly node: {
|
||||
readonly id: string;
|
||||
readonly logoUrl: string | null | undefined;
|
||||
readonly name: string;
|
||||
};
|
||||
}>;
|
||||
readonly pageInfo: {
|
||||
readonly endCursor: any | null | undefined;
|
||||
readonly hasNextPage: boolean;
|
||||
};
|
||||
};
|
||||
readonly " $fragmentType": "MainLayout_OrganizationSelector_viewer";
|
||||
};
|
||||
export type MainLayout_OrganizationSelector_viewer$key = {
|
||||
readonly " $data"?: MainLayout_OrganizationSelector_viewer$data;
|
||||
readonly " $fragmentSpreads": FragmentRefs<"MainLayout_OrganizationSelector_viewer">;
|
||||
};
|
||||
|
||||
import MainLayoutOrganizationSelectorPaginationQuery_graphql from './MainLayoutOrganizationSelectorPaginationQuery.graphql';
|
||||
|
||||
const node: ReaderFragment = (function(){
|
||||
var v0 = [
|
||||
"organizations"
|
||||
];
|
||||
return {
|
||||
"argumentDefinitions": [
|
||||
{
|
||||
"defaultValue": null,
|
||||
"kind": "LocalArgument",
|
||||
"name": "after"
|
||||
},
|
||||
{
|
||||
"defaultValue": 25,
|
||||
"kind": "LocalArgument",
|
||||
"name": "first"
|
||||
}
|
||||
],
|
||||
"kind": "Fragment",
|
||||
"metadata": {
|
||||
"connection": [
|
||||
{
|
||||
"count": "first",
|
||||
"cursor": "after",
|
||||
"direction": "forward",
|
||||
"path": (v0/*: any*/)
|
||||
}
|
||||
],
|
||||
"refetch": {
|
||||
"connection": {
|
||||
"forward": {
|
||||
"count": "first",
|
||||
"cursor": "after"
|
||||
},
|
||||
"backward": null,
|
||||
"path": (v0/*: any*/)
|
||||
},
|
||||
"fragmentPathInResult": [
|
||||
"viewer"
|
||||
],
|
||||
"operation": MainLayoutOrganizationSelectorPaginationQuery_graphql
|
||||
}
|
||||
},
|
||||
"name": "MainLayout_OrganizationSelector_viewer",
|
||||
"selections": [
|
||||
{
|
||||
"alias": "organizations",
|
||||
"args": [
|
||||
{
|
||||
"kind": "Literal",
|
||||
"name": "orderBy",
|
||||
"value": {
|
||||
"direction": "ASC",
|
||||
"field": "NAME"
|
||||
}
|
||||
}
|
||||
],
|
||||
"concreteType": "OrganizationConnection",
|
||||
"kind": "LinkedField",
|
||||
"name": "__MainLayout_OrganizationSelector_organizations_connection",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "OrganizationEdge",
|
||||
"kind": "LinkedField",
|
||||
"name": "edges",
|
||||
"plural": true,
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "Organization",
|
||||
"kind": "LinkedField",
|
||||
"name": "node",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "id",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "name",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "logoUrl",
|
||||
"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": "hasNextPage",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "endCursor",
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": "__MainLayout_OrganizationSelector_organizations_connection(orderBy:{\"direction\":\"ASC\",\"field\":\"NAME\"})"
|
||||
}
|
||||
],
|
||||
"type": "Viewer",
|
||||
"abstractKey": null
|
||||
};
|
||||
})();
|
||||
|
||||
(node as any).hash = "0dc2841aeeb6ba5291cb45d8644ec4af";
|
||||
|
||||
export default node;
|
||||
@@ -9,18 +9,13 @@ import {
|
||||
Button,
|
||||
Card,
|
||||
IconPlusLarge,
|
||||
ActionDropdown,
|
||||
DropdownItem,
|
||||
IconTrashCan,
|
||||
} from "@probo/ui";
|
||||
import { usePageTitle } from "@probo/hooks";
|
||||
import { useDeleteOrganizationMutation } from "../hooks/graph/OrganizationGraph";
|
||||
import { DeleteOrganizationDialog } from "../components/organizations/DeleteOrganizationDialog";
|
||||
|
||||
const OrganizationsPageQuery = graphql`
|
||||
query OrganizationsPageQuery {
|
||||
viewer {
|
||||
organizations(first: 25) @connection(key: "OrganizationsPage_organizations") {
|
||||
organizations(first: 1000, orderBy: {field: NAME, direction: ASC}) @connection(key: "OrganizationsPage_organizations") {
|
||||
__id
|
||||
edges {
|
||||
node {
|
||||
@@ -67,7 +62,6 @@ export default function OrganizationsPage() {
|
||||
<OrganizationCard
|
||||
key={organization.id}
|
||||
organization={organization}
|
||||
connectionId={data.viewer.organizations.__id}
|
||||
/>
|
||||
))}
|
||||
<Card padded>
|
||||
@@ -98,23 +92,10 @@ type OrganizationCardProps = {
|
||||
name: string;
|
||||
logoUrl: string | null | undefined;
|
||||
};
|
||||
connectionId: string;
|
||||
};
|
||||
|
||||
function OrganizationCard({ organization, connectionId }: OrganizationCardProps) {
|
||||
function OrganizationCard({ organization }: OrganizationCardProps) {
|
||||
const { __ } = useTranslate();
|
||||
const [deleteOrganization, isDeleting] = useDeleteOrganizationMutation();
|
||||
|
||||
const handleDelete = () => {
|
||||
return deleteOrganization({
|
||||
variables: {
|
||||
input: {
|
||||
organizationId: organization.id,
|
||||
},
|
||||
connections: [connectionId],
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Card padded className="w-full">
|
||||
@@ -136,21 +117,6 @@ function OrganizationCard({ organization, connectionId }: OrganizationCardProps)
|
||||
{__("Select")}
|
||||
</Link>
|
||||
</Button>
|
||||
<DeleteOrganizationDialog
|
||||
organizationName={organization.name}
|
||||
onConfirm={handleDelete}
|
||||
isDeleting={isDeleting}
|
||||
>
|
||||
<ActionDropdown>
|
||||
<DropdownItem
|
||||
variant="danger"
|
||||
icon={IconTrashCan}
|
||||
disabled={isDeleting}
|
||||
>
|
||||
{__("Delete organization")}
|
||||
</DropdownItem>
|
||||
</ActionDropdown>
|
||||
</DeleteOrganizationDialog>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @generated SignedSource<<70d28036f17c3b03dcfecce6abd5b476>>
|
||||
* @generated SignedSource<<84d0e43eced78862d1c82603e9c332e8>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
@@ -31,13 +31,21 @@ export type OrganizationsPageQuery = {
|
||||
|
||||
const node: ConcreteRequest = (function(){
|
||||
var v0 = {
|
||||
"kind": "Literal",
|
||||
"name": "orderBy",
|
||||
"value": {
|
||||
"direction": "ASC",
|
||||
"field": "NAME"
|
||||
}
|
||||
},
|
||||
v1 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "id",
|
||||
"storageKey": null
|
||||
},
|
||||
v1 = [
|
||||
v2 = [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
@@ -54,7 +62,7 @@ v1 = [
|
||||
"name": "node",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v0/*: any*/),
|
||||
(v1/*: any*/),
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
@@ -127,12 +135,13 @@ v1 = [
|
||||
]
|
||||
}
|
||||
],
|
||||
v2 = [
|
||||
v3 = [
|
||||
{
|
||||
"kind": "Literal",
|
||||
"name": "first",
|
||||
"value": 25
|
||||
}
|
||||
"value": 1000
|
||||
},
|
||||
(v0/*: any*/)
|
||||
];
|
||||
return {
|
||||
"fragment": {
|
||||
@@ -151,13 +160,15 @@ return {
|
||||
"selections": [
|
||||
{
|
||||
"alias": "organizations",
|
||||
"args": null,
|
||||
"args": [
|
||||
(v0/*: any*/)
|
||||
],
|
||||
"concreteType": "OrganizationConnection",
|
||||
"kind": "LinkedField",
|
||||
"name": "__OrganizationsPage_organizations_connection",
|
||||
"plural": false,
|
||||
"selections": (v1/*: any*/),
|
||||
"storageKey": null
|
||||
"selections": (v2/*: any*/),
|
||||
"storageKey": "__OrganizationsPage_organizations_connection(orderBy:{\"direction\":\"ASC\",\"field\":\"NAME\"})"
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
@@ -182,31 +193,33 @@ return {
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v2/*: any*/),
|
||||
"args": (v3/*: any*/),
|
||||
"concreteType": "OrganizationConnection",
|
||||
"kind": "LinkedField",
|
||||
"name": "organizations",
|
||||
"plural": false,
|
||||
"selections": (v1/*: any*/),
|
||||
"storageKey": "organizations(first:25)"
|
||||
"selections": (v2/*: any*/),
|
||||
"storageKey": "organizations(first:1000,orderBy:{\"direction\":\"ASC\",\"field\":\"NAME\"})"
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v2/*: any*/),
|
||||
"filters": null,
|
||||
"args": (v3/*: any*/),
|
||||
"filters": [
|
||||
"orderBy"
|
||||
],
|
||||
"handle": "connection",
|
||||
"key": "OrganizationsPage_organizations",
|
||||
"kind": "LinkedHandle",
|
||||
"name": "organizations"
|
||||
},
|
||||
(v0/*: any*/)
|
||||
(v1/*: any*/)
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"params": {
|
||||
"cacheID": "ddaafef96749a932a0cee5286a3c2bbd",
|
||||
"cacheID": "1735764e6816660969c5f96922320ac5",
|
||||
"id": null,
|
||||
"metadata": {
|
||||
"connection": [
|
||||
@@ -223,11 +236,11 @@ return {
|
||||
},
|
||||
"name": "OrganizationsPageQuery",
|
||||
"operationKind": "query",
|
||||
"text": "query OrganizationsPageQuery {\n viewer {\n organizations(first: 25) {\n edges {\n node {\n id\n name\n logoUrl\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n id\n }\n}\n"
|
||||
"text": "query OrganizationsPageQuery {\n viewer {\n organizations(first: 1000, orderBy: {field: NAME, direction: ASC}) {\n edges {\n node {\n id\n name\n logoUrl\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n id\n }\n}\n"
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
(node as any).hash = "122ab4331082ffe892fa7fe48692d961";
|
||||
(node as any).hash = "6fde39384e4678f88f17c34bbd30e684";
|
||||
|
||||
export default node;
|
||||
|
||||
@@ -57,7 +57,11 @@ export default function NewOrganizationPage() {
|
||||
connections: [
|
||||
ConnectionHandler.getConnectionID(
|
||||
data.viewer.id,
|
||||
"NewOrganizationPageQuery"
|
||||
"OrganizationsPage_organizations"
|
||||
),
|
||||
ConnectionHandler.getConnectionID(
|
||||
data.viewer.id,
|
||||
"MainLayout_OrganizationSelector_organizations"
|
||||
),
|
||||
],
|
||||
},
|
||||
|
||||
@@ -41,8 +41,12 @@ type (
|
||||
|
||||
func (o Organization) CursorKey(orderBy OrganizationOrderField) page.CursorKey {
|
||||
switch orderBy {
|
||||
case OrganizationOrderFieldName:
|
||||
return page.NewCursorKey(o.ID, o.Name)
|
||||
case OrganizationOrderFieldCreatedAt:
|
||||
return page.NewCursorKey(o.ID, o.CreatedAt)
|
||||
case OrganizationOrderFieldUpdatedAt:
|
||||
return page.NewCursorKey(o.ID, o.UpdatedAt)
|
||||
}
|
||||
|
||||
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
||||
@@ -90,6 +94,57 @@ LIMIT 1;
|
||||
return nil
|
||||
}
|
||||
|
||||
// Tenant id scope is not applied in this functions because we want to access all user's organizations.
|
||||
func (o *Organizations) ListForUserID(
|
||||
ctx context.Context,
|
||||
conn pg.Conn,
|
||||
userID gid.GID,
|
||||
cursor *page.Cursor[OrganizationOrderField],
|
||||
) error {
|
||||
q := `
|
||||
WITH user_org AS (
|
||||
SELECT
|
||||
organization_id
|
||||
FROM
|
||||
users_organizations
|
||||
WHERE
|
||||
user_id = @user_id
|
||||
)
|
||||
SELECT
|
||||
tenant_id,
|
||||
id,
|
||||
name,
|
||||
logo_object_key,
|
||||
created_at,
|
||||
updated_at
|
||||
FROM
|
||||
organizations
|
||||
INNER JOIN
|
||||
user_org ON organizations.id = user_org.organization_id
|
||||
WHERE
|
||||
%s
|
||||
`
|
||||
|
||||
q = fmt.Sprintf(q, cursor.SQLFragment())
|
||||
|
||||
args := pgx.StrictNamedArgs{"user_id": userID}
|
||||
maps.Copy(args, cursor.SQLArguments())
|
||||
|
||||
rows, err := conn.Query(ctx, q, args)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot query organizations: %w", err)
|
||||
}
|
||||
|
||||
organizations, err := pgx.CollectRows(rows, pgx.RowToAddrOfStructByName[Organization])
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot collect organizations: %w", err)
|
||||
}
|
||||
|
||||
*o = organizations
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Organization) Insert(
|
||||
ctx context.Context,
|
||||
conn pg.Conn,
|
||||
|
||||
@@ -4870,25 +4870,26 @@ func (r *vendorServiceResolver) Vendor(ctx context.Context, obj *types.VendorSer
|
||||
func (r *viewerResolver) Organizations(ctx context.Context, obj *types.Viewer, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.OrganizationOrder, filter *types.OrganizationFilter) (*types.OrganizationConnection, error) {
|
||||
user := UserFromContext(ctx)
|
||||
|
||||
// For now, we're not using cursor pagination since we're loading all organizations
|
||||
organizations, err := r.usrmgrSvc.ListOrganizationsForUserID(ctx, user.ID)
|
||||
pageOrderBy := page.OrderBy[coredata.OrganizationOrderField]{
|
||||
Field: coredata.OrganizationOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.OrganizationOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
organizations, err := r.usrmgrSvc.ListOrganizationsForUserIDPaginated(ctx, user.ID, cursor)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("failed to list organizations for user: %w", err))
|
||||
}
|
||||
|
||||
var edges []*types.OrganizationEdge
|
||||
for _, organization := range organizations {
|
||||
edges = append(edges, types.NewOrganizationEdge(organization, coredata.OrganizationOrderFieldCreatedAt))
|
||||
}
|
||||
page := page.NewPage(organizations, cursor)
|
||||
|
||||
// The simple implementation doesn't handle pagination yet
|
||||
return &types.OrganizationConnection{
|
||||
Edges: edges,
|
||||
PageInfo: &types.PageInfo{
|
||||
HasNextPage: false,
|
||||
HasPreviousPage: false,
|
||||
},
|
||||
}, nil
|
||||
return types.NewOrganizationConnection(page), nil
|
||||
}
|
||||
|
||||
// Asset returns schema.AssetResolver implementation.
|
||||
|
||||
@@ -515,6 +515,33 @@ func (s Service) ListOrganizationsForUserID(
|
||||
return organizations, nil
|
||||
}
|
||||
|
||||
// Tenant id scope is not applied in this functions because we want to access all user's organizations.
|
||||
func (s Service) ListOrganizationsForUserIDPaginated(
|
||||
ctx context.Context,
|
||||
userID gid.GID,
|
||||
cursor *page.Cursor[coredata.OrganizationOrderField],
|
||||
) (coredata.Organizations, error) {
|
||||
organizations := coredata.Organizations{}
|
||||
|
||||
err := s.pg.WithConn(
|
||||
ctx,
|
||||
func(conn pg.Conn) error {
|
||||
err := organizations.ListForUserID(ctx, conn, userID, cursor)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot list user organizations: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return organizations, nil
|
||||
}
|
||||
|
||||
func (s Service) ListTenantsForUserID(
|
||||
ctx context.Context,
|
||||
userID gid.GID,
|
||||
|
||||
Reference in New Issue
Block a user