Rename MembershipLayout and create ViewerLayout for identity context pages
Signed-off-by: Émile Ré <emile@getprobo.com>
This commit is contained in:
64
apps/console/src/__generated__/iam/ViewerDropdownFragment.graphql.ts
generated
Normal file
64
apps/console/src/__generated__/iam/ViewerDropdownFragment.graphql.ts
generated
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
/**
|
||||||
|
* @generated SignedSource<<e7945358237630130f305751e60ad92a>>
|
||||||
|
* @lightSyntaxTransform
|
||||||
|
* @nogrep
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
// @ts-nocheck
|
||||||
|
|
||||||
|
import { ReaderFragment } from 'relay-runtime';
|
||||||
|
import { FragmentRefs } from "relay-runtime";
|
||||||
|
export type ViewerDropdownFragment$data = {
|
||||||
|
readonly canListAPIKeys: boolean;
|
||||||
|
readonly email: string;
|
||||||
|
readonly fullName: string;
|
||||||
|
readonly " $fragmentType": "ViewerDropdownFragment";
|
||||||
|
};
|
||||||
|
export type ViewerDropdownFragment$key = {
|
||||||
|
readonly " $data"?: ViewerDropdownFragment$data;
|
||||||
|
readonly " $fragmentSpreads": FragmentRefs<"ViewerDropdownFragment">;
|
||||||
|
};
|
||||||
|
|
||||||
|
const node: ReaderFragment = {
|
||||||
|
"argumentDefinitions": [],
|
||||||
|
"kind": "Fragment",
|
||||||
|
"metadata": null,
|
||||||
|
"name": "ViewerDropdownFragment",
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": "canListAPIKeys",
|
||||||
|
"args": [
|
||||||
|
{
|
||||||
|
"kind": "Literal",
|
||||||
|
"name": "action",
|
||||||
|
"value": "iam:personal-api-key:list"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "permission",
|
||||||
|
"storageKey": "permission(action:\"iam:personal-api-key:list\")"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "email",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "fullName",
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "Identity",
|
||||||
|
"abstractKey": null
|
||||||
|
};
|
||||||
|
|
||||||
|
(node as any).hash = "e96fe96007f4d949403890fda7180cba";
|
||||||
|
|
||||||
|
export default node;
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* @generated SignedSource<<8cb399eb2f38eaf3059531ea4bc3fa30>>
|
* @generated SignedSource<<93ee9324d2ee86042f9f46eda06d0770>>
|
||||||
* @lightSyntaxTransform
|
* @lightSyntaxTransform
|
||||||
* @nogrep
|
* @nogrep
|
||||||
*/
|
*/
|
||||||
@@ -9,15 +9,15 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
|
|
||||||
import { ConcreteRequest } from 'relay-runtime';
|
import { ConcreteRequest } from 'relay-runtime';
|
||||||
export type SessionDropdownSignOutMutation$variables = Record<PropertyKey, never>;
|
export type ViewerDropdownSignOutMutation$variables = Record<PropertyKey, never>;
|
||||||
export type SessionDropdownSignOutMutation$data = {
|
export type ViewerDropdownSignOutMutation$data = {
|
||||||
readonly signOut: {
|
readonly signOut: {
|
||||||
readonly success: boolean;
|
readonly success: boolean;
|
||||||
} | null | undefined;
|
} | null | undefined;
|
||||||
};
|
};
|
||||||
export type SessionDropdownSignOutMutation = {
|
export type ViewerDropdownSignOutMutation = {
|
||||||
response: SessionDropdownSignOutMutation$data;
|
response: ViewerDropdownSignOutMutation$data;
|
||||||
variables: SessionDropdownSignOutMutation$variables;
|
variables: ViewerDropdownSignOutMutation$variables;
|
||||||
};
|
};
|
||||||
|
|
||||||
const node: ConcreteRequest = (function(){
|
const node: ConcreteRequest = (function(){
|
||||||
@@ -46,7 +46,7 @@ return {
|
|||||||
"argumentDefinitions": [],
|
"argumentDefinitions": [],
|
||||||
"kind": "Fragment",
|
"kind": "Fragment",
|
||||||
"metadata": null,
|
"metadata": null,
|
||||||
"name": "SessionDropdownSignOutMutation",
|
"name": "ViewerDropdownSignOutMutation",
|
||||||
"selections": (v0/*: any*/),
|
"selections": (v0/*: any*/),
|
||||||
"type": "Mutation",
|
"type": "Mutation",
|
||||||
"abstractKey": null
|
"abstractKey": null
|
||||||
@@ -55,20 +55,20 @@ return {
|
|||||||
"operation": {
|
"operation": {
|
||||||
"argumentDefinitions": [],
|
"argumentDefinitions": [],
|
||||||
"kind": "Operation",
|
"kind": "Operation",
|
||||||
"name": "SessionDropdownSignOutMutation",
|
"name": "ViewerDropdownSignOutMutation",
|
||||||
"selections": (v0/*: any*/)
|
"selections": (v0/*: any*/)
|
||||||
},
|
},
|
||||||
"params": {
|
"params": {
|
||||||
"cacheID": "a677190a127d7f75d5c629fab236a7a3",
|
"cacheID": "9252bcfdab3361ae1690a713e2765de3",
|
||||||
"id": null,
|
"id": null,
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"name": "SessionDropdownSignOutMutation",
|
"name": "ViewerDropdownSignOutMutation",
|
||||||
"operationKind": "mutation",
|
"operationKind": "mutation",
|
||||||
"text": "mutation SessionDropdownSignOutMutation {\n signOut {\n success\n }\n}\n"
|
"text": "mutation ViewerDropdownSignOutMutation {\n signOut {\n success\n }\n}\n"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
|
||||||
(node as any).hash = "10c9bdf35ab3961c7488973e052cf978";
|
(node as any).hash = "a08b0de590063055e1ccbacd1d443a0f";
|
||||||
|
|
||||||
export default node;
|
export default node;
|
||||||
120
apps/console/src/__generated__/iam/ViewerLayoutQuery.graphql.ts
generated
Normal file
120
apps/console/src/__generated__/iam/ViewerLayoutQuery.graphql.ts
generated
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
/**
|
||||||
|
* @generated SignedSource<<ecd129a1f62f100fe57ee9b08f9321d0>>
|
||||||
|
* @lightSyntaxTransform
|
||||||
|
* @nogrep
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
// @ts-nocheck
|
||||||
|
|
||||||
|
import { ConcreteRequest } from 'relay-runtime';
|
||||||
|
import { FragmentRefs } from "relay-runtime";
|
||||||
|
export type ViewerLayoutQuery$variables = Record<PropertyKey, never>;
|
||||||
|
export type ViewerLayoutQuery$data = {
|
||||||
|
readonly viewer: {
|
||||||
|
readonly " $fragmentSpreads": FragmentRefs<"ViewerDropdownFragment">;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
export type ViewerLayoutQuery = {
|
||||||
|
response: ViewerLayoutQuery$data;
|
||||||
|
variables: ViewerLayoutQuery$variables;
|
||||||
|
};
|
||||||
|
|
||||||
|
const node: ConcreteRequest = {
|
||||||
|
"fragment": {
|
||||||
|
"argumentDefinitions": [],
|
||||||
|
"kind": "Fragment",
|
||||||
|
"metadata": null,
|
||||||
|
"name": "ViewerLayoutQuery",
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"kind": "RequiredField",
|
||||||
|
"field": {
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"concreteType": "Identity",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "viewer",
|
||||||
|
"plural": false,
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"args": null,
|
||||||
|
"kind": "FragmentSpread",
|
||||||
|
"name": "ViewerDropdownFragment"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
"action": "THROW"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "Query",
|
||||||
|
"abstractKey": null
|
||||||
|
},
|
||||||
|
"kind": "Request",
|
||||||
|
"operation": {
|
||||||
|
"argumentDefinitions": [],
|
||||||
|
"kind": "Operation",
|
||||||
|
"name": "ViewerLayoutQuery",
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"concreteType": "Identity",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "viewer",
|
||||||
|
"plural": false,
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": "canListAPIKeys",
|
||||||
|
"args": [
|
||||||
|
{
|
||||||
|
"kind": "Literal",
|
||||||
|
"name": "action",
|
||||||
|
"value": "iam:personal-api-key:list"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "permission",
|
||||||
|
"storageKey": "permission(action:\"iam:personal-api-key:list\")"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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": "id",
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"params": {
|
||||||
|
"cacheID": "faf40277113685d45576f1b466123787",
|
||||||
|
"id": null,
|
||||||
|
"metadata": {},
|
||||||
|
"name": "ViewerLayoutQuery",
|
||||||
|
"operationKind": "query",
|
||||||
|
"text": "query ViewerLayoutQuery {\n viewer {\n ...ViewerDropdownFragment\n id\n }\n}\n\nfragment ViewerDropdownFragment on Identity {\n canListAPIKeys: permission(action: \"iam:personal-api-key:list\")\n email\n fullName\n}\n"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
(node as any).hash = "48e174d981dbc9198a56aac976a20b21";
|
||||||
|
|
||||||
|
export default node;
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* @generated SignedSource<<73d5a0059348fd0c5950ae3a873cc383>>
|
* @generated SignedSource<<a87fd05a4f80d2d7094647468d695967>>
|
||||||
* @lightSyntaxTransform
|
* @lightSyntaxTransform
|
||||||
* @nogrep
|
* @nogrep
|
||||||
*/
|
*/
|
||||||
@@ -10,42 +10,29 @@
|
|||||||
|
|
||||||
import { ReaderFragment } from 'relay-runtime';
|
import { ReaderFragment } from 'relay-runtime';
|
||||||
import { FragmentRefs } from "relay-runtime";
|
import { FragmentRefs } from "relay-runtime";
|
||||||
export type SessionDropdownFragment$data = {
|
export type ViewerMembershipDropdownFragment$data = {
|
||||||
readonly canDelete: boolean;
|
|
||||||
readonly viewerMembership: {
|
readonly viewerMembership: {
|
||||||
readonly identity: {
|
readonly identity: {
|
||||||
|
readonly canListAPIKeys: boolean;
|
||||||
readonly email: string;
|
readonly email: string;
|
||||||
};
|
};
|
||||||
readonly profile: {
|
readonly profile: {
|
||||||
readonly fullName: string;
|
readonly fullName: string;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
readonly " $fragmentType": "SessionDropdownFragment";
|
readonly " $fragmentType": "ViewerMembershipDropdownFragment";
|
||||||
};
|
};
|
||||||
export type SessionDropdownFragment$key = {
|
export type ViewerMembershipDropdownFragment$key = {
|
||||||
readonly " $data"?: SessionDropdownFragment$data;
|
readonly " $data"?: ViewerMembershipDropdownFragment$data;
|
||||||
readonly " $fragmentSpreads": FragmentRefs<"SessionDropdownFragment">;
|
readonly " $fragmentSpreads": FragmentRefs<"ViewerMembershipDropdownFragment">;
|
||||||
};
|
};
|
||||||
|
|
||||||
const node: ReaderFragment = {
|
const node: ReaderFragment = {
|
||||||
"argumentDefinitions": [],
|
"argumentDefinitions": [],
|
||||||
"kind": "Fragment",
|
"kind": "Fragment",
|
||||||
"metadata": null,
|
"metadata": null,
|
||||||
"name": "SessionDropdownFragment",
|
"name": "ViewerMembershipDropdownFragment",
|
||||||
"selections": [
|
"selections": [
|
||||||
{
|
|
||||||
"alias": "canDelete",
|
|
||||||
"args": [
|
|
||||||
{
|
|
||||||
"kind": "Literal",
|
|
||||||
"name": "action",
|
|
||||||
"value": "iam:organization:delete"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"kind": "ScalarField",
|
|
||||||
"name": "permission",
|
|
||||||
"storageKey": "permission(action:\"iam:organization:delete\")"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"kind": "RequiredField",
|
"kind": "RequiredField",
|
||||||
"field": {
|
"field": {
|
||||||
@@ -72,6 +59,19 @@ const node: ReaderFragment = {
|
|||||||
"kind": "ScalarField",
|
"kind": "ScalarField",
|
||||||
"name": "email",
|
"name": "email",
|
||||||
"storageKey": null
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": "canListAPIKeys",
|
||||||
|
"args": [
|
||||||
|
{
|
||||||
|
"kind": "Literal",
|
||||||
|
"name": "action",
|
||||||
|
"value": "iam:personal-api-key:list"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "permission",
|
||||||
|
"storageKey": "permission(action:\"iam:personal-api-key:list\")"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"storageKey": null
|
"storageKey": null
|
||||||
@@ -110,6 +110,6 @@ const node: ReaderFragment = {
|
|||||||
"abstractKey": null
|
"abstractKey": null
|
||||||
};
|
};
|
||||||
|
|
||||||
(node as any).hash = "51810eafbf165e7b5eeec42cb268ae54";
|
(node as any).hash = "82c179a1ec2b90ce5f12c0959f97150f";
|
||||||
|
|
||||||
export default node;
|
export default node;
|
||||||
74
apps/console/src/__generated__/iam/ViewerMembershipDropdownSignOutMutation.graphql.ts
generated
Normal file
74
apps/console/src/__generated__/iam/ViewerMembershipDropdownSignOutMutation.graphql.ts
generated
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
/**
|
||||||
|
* @generated SignedSource<<5d6fc3e9d931dccebc57b68196c98bed>>
|
||||||
|
* @lightSyntaxTransform
|
||||||
|
* @nogrep
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
// @ts-nocheck
|
||||||
|
|
||||||
|
import { ConcreteRequest } from 'relay-runtime';
|
||||||
|
export type ViewerMembershipDropdownSignOutMutation$variables = Record<PropertyKey, never>;
|
||||||
|
export type ViewerMembershipDropdownSignOutMutation$data = {
|
||||||
|
readonly signOut: {
|
||||||
|
readonly success: boolean;
|
||||||
|
} | null | undefined;
|
||||||
|
};
|
||||||
|
export type ViewerMembershipDropdownSignOutMutation = {
|
||||||
|
response: ViewerMembershipDropdownSignOutMutation$data;
|
||||||
|
variables: ViewerMembershipDropdownSignOutMutation$variables;
|
||||||
|
};
|
||||||
|
|
||||||
|
const node: ConcreteRequest = (function(){
|
||||||
|
var v0 = [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"concreteType": "SignOutPayload",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "signOut",
|
||||||
|
"plural": false,
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "success",
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
];
|
||||||
|
return {
|
||||||
|
"fragment": {
|
||||||
|
"argumentDefinitions": [],
|
||||||
|
"kind": "Fragment",
|
||||||
|
"metadata": null,
|
||||||
|
"name": "ViewerMembershipDropdownSignOutMutation",
|
||||||
|
"selections": (v0/*: any*/),
|
||||||
|
"type": "Mutation",
|
||||||
|
"abstractKey": null
|
||||||
|
},
|
||||||
|
"kind": "Request",
|
||||||
|
"operation": {
|
||||||
|
"argumentDefinitions": [],
|
||||||
|
"kind": "Operation",
|
||||||
|
"name": "ViewerMembershipDropdownSignOutMutation",
|
||||||
|
"selections": (v0/*: any*/)
|
||||||
|
},
|
||||||
|
"params": {
|
||||||
|
"cacheID": "da5fc8d24f8fac6617c4e4de8d9a629d",
|
||||||
|
"id": null,
|
||||||
|
"metadata": {},
|
||||||
|
"name": "ViewerMembershipDropdownSignOutMutation",
|
||||||
|
"operationKind": "mutation",
|
||||||
|
"text": "mutation ViewerMembershipDropdownSignOutMutation {\n signOut {\n success\n }\n}\n"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
(node as any).hash = "856ff5d4affd9ad27871ab5f4fef3b1e";
|
||||||
|
|
||||||
|
export default node;
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* @generated SignedSource<<4268d9e187cf29b47f9438cf48cc3e73>>
|
* @generated SignedSource<<d089cfdf5c585ba8fcb83456438efe62>>
|
||||||
* @lightSyntaxTransform
|
* @lightSyntaxTransform
|
||||||
* @nogrep
|
* @nogrep
|
||||||
*/
|
*/
|
||||||
@@ -11,11 +11,11 @@
|
|||||||
import { ConcreteRequest } from 'relay-runtime';
|
import { ConcreteRequest } from 'relay-runtime';
|
||||||
import { FragmentRefs } from "relay-runtime";
|
import { FragmentRefs } from "relay-runtime";
|
||||||
export type MembershipRole = "ADMIN" | "AUDITOR" | "EMPLOYEE" | "OWNER" | "VIEWER";
|
export type MembershipRole = "ADMIN" | "AUDITOR" | "EMPLOYEE" | "OWNER" | "VIEWER";
|
||||||
export type MembershipLayoutQuery$variables = {
|
export type ViewerMembershipLayoutQuery$variables = {
|
||||||
hideSidebar: boolean;
|
hideSidebar: boolean;
|
||||||
organizationId: string;
|
organizationId: string;
|
||||||
};
|
};
|
||||||
export type MembershipLayoutQuery$data = {
|
export type ViewerMembershipLayoutQuery$data = {
|
||||||
readonly organization: {
|
readonly organization: {
|
||||||
readonly __typename: "Organization";
|
readonly __typename: "Organization";
|
||||||
readonly viewerMembership: {
|
readonly viewerMembership: {
|
||||||
@@ -24,7 +24,7 @@ export type MembershipLayoutQuery$data = {
|
|||||||
};
|
};
|
||||||
readonly role: MembershipRole;
|
readonly role: MembershipRole;
|
||||||
};
|
};
|
||||||
readonly " $fragmentSpreads": FragmentRefs<"MembershipsDropdown_organizationFragment" | "SessionDropdownFragment" | "SidebarFragment">;
|
readonly " $fragmentSpreads": FragmentRefs<"MembershipsDropdown_organizationFragment" | "SidebarFragment" | "ViewerMembershipDropdownFragment">;
|
||||||
} | {
|
} | {
|
||||||
// This will never be '%other', but we need some
|
// This will never be '%other', but we need some
|
||||||
// value in case none of the concrete values match.
|
// value in case none of the concrete values match.
|
||||||
@@ -38,9 +38,9 @@ export type MembershipLayoutQuery$data = {
|
|||||||
readonly " $fragmentSpreads": FragmentRefs<"MembershipsDropdown_viewerFragment">;
|
readonly " $fragmentSpreads": FragmentRefs<"MembershipsDropdown_viewerFragment">;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
export type MembershipLayoutQuery = {
|
export type ViewerMembershipLayoutQuery = {
|
||||||
response: MembershipLayoutQuery$data;
|
response: ViewerMembershipLayoutQuery$data;
|
||||||
variables: MembershipLayoutQuery$variables;
|
variables: ViewerMembershipLayoutQuery$variables;
|
||||||
};
|
};
|
||||||
|
|
||||||
const node: ConcreteRequest = (function(){
|
const node: ConcreteRequest = (function(){
|
||||||
@@ -111,7 +111,7 @@ return {
|
|||||||
],
|
],
|
||||||
"kind": "Fragment",
|
"kind": "Fragment",
|
||||||
"metadata": null,
|
"metadata": null,
|
||||||
"name": "MembershipLayoutQuery",
|
"name": "ViewerMembershipLayoutQuery",
|
||||||
"selections": [
|
"selections": [
|
||||||
{
|
{
|
||||||
"kind": "RequiredField",
|
"kind": "RequiredField",
|
||||||
@@ -135,7 +135,7 @@ return {
|
|||||||
{
|
{
|
||||||
"args": null,
|
"args": null,
|
||||||
"kind": "FragmentSpread",
|
"kind": "FragmentSpread",
|
||||||
"name": "SessionDropdownFragment"
|
"name": "ViewerMembershipDropdownFragment"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"condition": "hideSidebar",
|
"condition": "hideSidebar",
|
||||||
@@ -242,7 +242,7 @@ return {
|
|||||||
(v0/*: any*/)
|
(v0/*: any*/)
|
||||||
],
|
],
|
||||||
"kind": "Operation",
|
"kind": "Operation",
|
||||||
"name": "MembershipLayoutQuery",
|
"name": "ViewerMembershipLayoutQuery",
|
||||||
"selections": [
|
"selections": [
|
||||||
{
|
{
|
||||||
"alias": "organization",
|
"alias": "organization",
|
||||||
@@ -263,19 +263,6 @@ return {
|
|||||||
"name": "name",
|
"name": "name",
|
||||||
"storageKey": null
|
"storageKey": null
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"alias": "canDelete",
|
|
||||||
"args": [
|
|
||||||
{
|
|
||||||
"kind": "Literal",
|
|
||||||
"name": "action",
|
|
||||||
"value": "iam:organization:delete"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"kind": "ScalarField",
|
|
||||||
"name": "permission",
|
|
||||||
"storageKey": "permission(action:\"iam:organization:delete\")"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"alias": null,
|
"alias": null,
|
||||||
"args": null,
|
"args": null,
|
||||||
@@ -293,6 +280,19 @@ return {
|
|||||||
"plural": false,
|
"plural": false,
|
||||||
"selections": [
|
"selections": [
|
||||||
(v6/*: any*/),
|
(v6/*: any*/),
|
||||||
|
{
|
||||||
|
"alias": "canListAPIKeys",
|
||||||
|
"args": [
|
||||||
|
{
|
||||||
|
"kind": "Literal",
|
||||||
|
"name": "action",
|
||||||
|
"value": "iam:personal-api-key:list"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "permission",
|
||||||
|
"storageKey": "permission(action:\"iam:personal-api-key:list\")"
|
||||||
|
},
|
||||||
(v8/*: any*/)
|
(v8/*: any*/)
|
||||||
],
|
],
|
||||||
"storageKey": null
|
"storageKey": null
|
||||||
@@ -618,16 +618,16 @@ return {
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"params": {
|
"params": {
|
||||||
"cacheID": "5f50873fa9c14115e307b43d7c1ae822",
|
"cacheID": "d7e0b080876472d059c97bf57818c697",
|
||||||
"id": null,
|
"id": null,
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"name": "MembershipLayoutQuery",
|
"name": "ViewerMembershipLayoutQuery",
|
||||||
"operationKind": "query",
|
"operationKind": "query",
|
||||||
"text": "query MembershipLayoutQuery(\n $organizationId: ID!\n $hideSidebar: Boolean!\n) {\n organization: node(id: $organizationId) {\n __typename\n ... on Organization {\n ...MembershipsDropdown_organizationFragment\n ...SessionDropdownFragment\n ...SidebarFragment @skip(if: $hideSidebar)\n viewerMembership {\n role\n profile {\n fullName\n id\n }\n id\n }\n }\n id\n }\n viewer {\n email\n ...MembershipsDropdown_viewerFragment\n pendingInvitations {\n totalCount\n }\n id\n }\n}\n\nfragment MembershipsDropdown_organizationFragment on Organization {\n name\n}\n\nfragment MembershipsDropdown_viewerFragment on Identity {\n pendingInvitations {\n totalCount\n }\n}\n\nfragment SessionDropdownFragment on Organization {\n canDelete: permission(action: \"iam:organization:delete\")\n viewerMembership {\n identity {\n email\n id\n }\n profile {\n fullName\n id\n }\n id\n }\n}\n\nfragment SidebarFragment on Organization {\n canListMeetings: permission(action: \"core:meeting:list\")\n canListTasks: permission(action: \"core:task:list\")\n canListMeasures: permission(action: \"core:measures:list\")\n canListRisks: permission(action: \"core:risk:list\")\n canListFrameworks: permission(action: \"core:frameworks:list\")\n canListPeople: permission(action: \"core:people:list\")\n canListVendors: permission(action: \"core:vendor:list\")\n canListDocuments: permission(action: \"core:document:list\")\n canListAssets: permission(action: \"core:asset:list\")\n canListData: permission(action: \"core:datum:list\")\n canListAudits: permission(action: \"core:audit:list\")\n canListNonconformities: permission(action: \"core:nonconformity:list\")\n canListObligations: permission(action: \"core:obligation:list\")\n canListContinualImprovements: permission(action: \"core:continual-improvement:list\")\n canListProcessingActivities: permission(action: \"core:processing-activity:list\")\n canListRightsRequests: permission(action: \"core:rights-request:list\")\n canListSnapshots: permission(action: \"core:snapshot:list\")\n canGetTrustCenter: permission(action: \"core:trust-center:get\")\n canUpdateOrganization: permission(action: \"iam:organization:update\")\n canListStatesOfApplicability: permission(action: \"core:state-of-applicability:list\")\n}\n"
|
"text": "query ViewerMembershipLayoutQuery(\n $organizationId: ID!\n $hideSidebar: Boolean!\n) {\n organization: node(id: $organizationId) {\n __typename\n ... on Organization {\n ...MembershipsDropdown_organizationFragment\n ...ViewerMembershipDropdownFragment\n ...SidebarFragment @skip(if: $hideSidebar)\n viewerMembership {\n role\n profile {\n fullName\n id\n }\n id\n }\n }\n id\n }\n viewer {\n email\n ...MembershipsDropdown_viewerFragment\n pendingInvitations {\n totalCount\n }\n id\n }\n}\n\nfragment MembershipsDropdown_organizationFragment on Organization {\n name\n}\n\nfragment MembershipsDropdown_viewerFragment on Identity {\n pendingInvitations {\n totalCount\n }\n}\n\nfragment SidebarFragment on Organization {\n canListMeetings: permission(action: \"core:meeting:list\")\n canListTasks: permission(action: \"core:task:list\")\n canListMeasures: permission(action: \"core:measures:list\")\n canListRisks: permission(action: \"core:risk:list\")\n canListFrameworks: permission(action: \"core:frameworks:list\")\n canListPeople: permission(action: \"core:people:list\")\n canListVendors: permission(action: \"core:vendor:list\")\n canListDocuments: permission(action: \"core:document:list\")\n canListAssets: permission(action: \"core:asset:list\")\n canListData: permission(action: \"core:datum:list\")\n canListAudits: permission(action: \"core:audit:list\")\n canListNonconformities: permission(action: \"core:nonconformity:list\")\n canListObligations: permission(action: \"core:obligation:list\")\n canListContinualImprovements: permission(action: \"core:continual-improvement:list\")\n canListProcessingActivities: permission(action: \"core:processing-activity:list\")\n canListRightsRequests: permission(action: \"core:rights-request:list\")\n canListSnapshots: permission(action: \"core:snapshot:list\")\n canGetTrustCenter: permission(action: \"core:trust-center:get\")\n canUpdateOrganization: permission(action: \"iam:organization:update\")\n canListStatesOfApplicability: permission(action: \"core:state-of-applicability:list\")\n}\n\nfragment ViewerMembershipDropdownFragment on Organization {\n viewerMembership {\n identity {\n email\n canListAPIKeys: permission(action: \"iam:personal-api-key:list\")\n id\n }\n profile {\n fullName\n id\n }\n id\n }\n}\n"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
|
||||||
(node as any).hash = "e52fc7540b2908e5b4f2c4cef33b5b81";
|
(node as any).hash = "298aba62d7920932f86433919c623d4c";
|
||||||
|
|
||||||
export default node;
|
export default node;
|
||||||
42
apps/console/src/pages/iam/memberships/ViewerLayout.tsx
Normal file
42
apps/console/src/pages/iam/memberships/ViewerLayout.tsx
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import { graphql, usePreloadedQuery, type PreloadedQuery } from "react-relay";
|
||||||
|
import { Outlet } from "react-router";
|
||||||
|
import { CenteredLayout, Layout, Skeleton } from "@probo/ui";
|
||||||
|
import type { ViewerLayoutQuery } from "/__generated__/iam/ViewerLayoutQuery.graphql";
|
||||||
|
import { Suspense } from "react";
|
||||||
|
import { ViewerDropdown } from "./_components/ViewerDropdown";
|
||||||
|
|
||||||
|
export const viewerLayoutQuery = graphql`
|
||||||
|
query ViewerLayoutQuery {
|
||||||
|
viewer @required(action: THROW) {
|
||||||
|
...ViewerDropdownFragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export function ViewerLayout(props: {
|
||||||
|
hideSidebar?: boolean;
|
||||||
|
queryRef: PreloadedQuery<ViewerLayoutQuery>;
|
||||||
|
}) {
|
||||||
|
const { queryRef } = props;
|
||||||
|
|
||||||
|
const { viewer } = usePreloadedQuery<ViewerLayoutQuery>(
|
||||||
|
viewerLayoutQuery,
|
||||||
|
queryRef,
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Layout
|
||||||
|
headerTrailing={
|
||||||
|
<div className="ml-auto">
|
||||||
|
<Suspense fallback={<Skeleton className="w-32 h-8" />}>
|
||||||
|
<ViewerDropdown fKey={viewer} />
|
||||||
|
</Suspense>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<CenteredLayout>
|
||||||
|
<Outlet />
|
||||||
|
</CenteredLayout>
|
||||||
|
</Layout>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import { useQueryLoader } from "react-relay";
|
||||||
|
import { Suspense, useEffect } from "react";
|
||||||
|
import { CenteredLayoutSkeleton } from "@probo/ui";
|
||||||
|
import type { ViewerLayoutQuery } from "/__generated__/iam/ViewerLayoutQuery.graphql";
|
||||||
|
import { ViewerLayout, viewerLayoutQuery } from "./ViewerLayout";
|
||||||
|
import { IAMRelayProvider } from "/providers/IAMRelayProvider";
|
||||||
|
|
||||||
|
function ViewerLayoutLoader() {
|
||||||
|
const [queryRef, loadQuery] =
|
||||||
|
useQueryLoader<ViewerLayoutQuery>(viewerLayoutQuery);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
loadQuery({});
|
||||||
|
}, [loadQuery]);
|
||||||
|
|
||||||
|
if (!queryRef) {
|
||||||
|
return <CenteredLayoutSkeleton />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Suspense fallback={<CenteredLayoutSkeleton />}>
|
||||||
|
<ViewerLayout queryRef={queryRef} />
|
||||||
|
</Suspense>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function () {
|
||||||
|
return (
|
||||||
|
<IAMRelayProvider>
|
||||||
|
<ViewerLayoutLoader />
|
||||||
|
</IAMRelayProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
import {
|
||||||
|
DropdownSeparator,
|
||||||
|
IconArrowBoxLeft,
|
||||||
|
IconCircleQuestionmark,
|
||||||
|
IconKey,
|
||||||
|
UserDropdown,
|
||||||
|
UserDropdownItem,
|
||||||
|
useToast,
|
||||||
|
} from "@probo/ui";
|
||||||
|
import { graphql } from "relay-runtime";
|
||||||
|
import { useFragment, useMutation } from "react-relay";
|
||||||
|
import { useTranslate } from "@probo/i18n";
|
||||||
|
import type { ViewerDropdownFragment$key } from "/__generated__/iam/ViewerDropdownFragment.graphql";
|
||||||
|
import { formatError } from "@probo/helpers";
|
||||||
|
|
||||||
|
export const fragment = graphql`
|
||||||
|
fragment ViewerDropdownFragment on Identity {
|
||||||
|
canListAPIKeys: permission(action: "iam:personal-api-key:list")
|
||||||
|
email
|
||||||
|
fullName
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const signOutMutation = graphql`
|
||||||
|
mutation ViewerDropdownSignOutMutation {
|
||||||
|
signOut {
|
||||||
|
success
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export function ViewerDropdown(props: { fKey: ViewerDropdownFragment$key }) {
|
||||||
|
const { fKey } = props;
|
||||||
|
|
||||||
|
const { __ } = useTranslate();
|
||||||
|
const { toast } = useToast();
|
||||||
|
|
||||||
|
const { canListAPIKeys, email, fullName } =
|
||||||
|
useFragment<ViewerDropdownFragment$key>(fragment, fKey);
|
||||||
|
const [signOut] = useMutation(signOutMutation);
|
||||||
|
|
||||||
|
const handleLogout: React.MouseEventHandler<HTMLAnchorElement> = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
signOut({
|
||||||
|
variables: {},
|
||||||
|
onCompleted: (_, e) => {
|
||||||
|
if (e) {
|
||||||
|
toast({
|
||||||
|
title: __("Request failed"),
|
||||||
|
description: formatError(__("Cannot sign out"), e),
|
||||||
|
variant: "error",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
window.location.reload();
|
||||||
|
},
|
||||||
|
onError: (e) => {
|
||||||
|
toast({
|
||||||
|
title: __("Error"),
|
||||||
|
description: e.message,
|
||||||
|
variant: "error",
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<UserDropdown fullName={fullName} email={email}>
|
||||||
|
{canListAPIKeys && (
|
||||||
|
<UserDropdownItem
|
||||||
|
to="/me/api-keys"
|
||||||
|
icon={IconKey}
|
||||||
|
label={__("API Keys")}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<UserDropdownItem
|
||||||
|
to="mailto:support@getprobo.com"
|
||||||
|
icon={IconCircleQuestionmark}
|
||||||
|
label={__("Help")}
|
||||||
|
/>
|
||||||
|
<DropdownSeparator />
|
||||||
|
<UserDropdownItem
|
||||||
|
variant="danger"
|
||||||
|
to="/logout"
|
||||||
|
icon={IconArrowBoxLeft}
|
||||||
|
label="Logout"
|
||||||
|
onClick={handleLogout}
|
||||||
|
/>
|
||||||
|
</UserDropdown>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,22 +1,25 @@
|
|||||||
import { graphql, usePreloadedQuery, type PreloadedQuery } from "react-relay";
|
import { graphql, usePreloadedQuery, type PreloadedQuery } from "react-relay";
|
||||||
import { Link, Outlet } from "react-router";
|
import { Link, Outlet } from "react-router";
|
||||||
import { Badge, Button, IconPeopleAdd, Layout, Skeleton } from "@probo/ui";
|
import { Badge, Button, IconPeopleAdd, Layout, Skeleton } from "@probo/ui";
|
||||||
import { Sidebar } from "./_components/Sidebar";
|
import { Sidebar } from "../memberships/_components/Sidebar";
|
||||||
import { MembershipsDropdown } from "./MembershipsDropdown";
|
import { MembershipsDropdown } from "../memberships/MembershipsDropdown";
|
||||||
import type { MembershipLayoutQuery } from "/__generated__/iam/MembershipLayoutQuery.graphql";
|
import type { ViewerMembershipLayoutQuery } from "/__generated__/iam/ViewerMembershipLayoutQuery.graphql";
|
||||||
import { SessionDropdown } from "./_components/SessionDropdown";
|
import { ViewerMembershipDropdown } from "./_components/ViewerMembershipDropdown";
|
||||||
import { Suspense } from "react";
|
import { Suspense } from "react";
|
||||||
import { useTranslate } from "@probo/i18n";
|
import { useTranslate } from "@probo/i18n";
|
||||||
import { CoreRelayProvider } from "/providers/CoreRelayProvider";
|
import { CoreRelayProvider } from "/providers/CoreRelayProvider";
|
||||||
import { CurrentUser } from "/providers/CurrentUser";
|
import { CurrentUser } from "/providers/CurrentUser";
|
||||||
|
|
||||||
export const membershipLayoutQuery = graphql`
|
export const viewerMembershipLayoutQuery = graphql`
|
||||||
query MembershipLayoutQuery($organizationId: ID!, $hideSidebar: Boolean!) {
|
query ViewerMembershipLayoutQuery(
|
||||||
|
$organizationId: ID!
|
||||||
|
$hideSidebar: Boolean!
|
||||||
|
) {
|
||||||
organization: node(id: $organizationId) @required(action: THROW) {
|
organization: node(id: $organizationId) @required(action: THROW) {
|
||||||
__typename
|
__typename
|
||||||
... on Organization {
|
... on Organization {
|
||||||
...MembershipsDropdown_organizationFragment
|
...MembershipsDropdown_organizationFragment
|
||||||
...SessionDropdownFragment
|
...ViewerMembershipDropdownFragment
|
||||||
...SidebarFragment @skip(if: $hideSidebar)
|
...SidebarFragment @skip(if: $hideSidebar)
|
||||||
viewerMembership @required(action: THROW) {
|
viewerMembership @required(action: THROW) {
|
||||||
role
|
role
|
||||||
@@ -36,16 +39,17 @@ export const membershipLayoutQuery = graphql`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export function MembershipLayout(props: {
|
export function ViewerMembershipLayout(props: {
|
||||||
hideSidebar?: boolean;
|
hideSidebar?: boolean;
|
||||||
queryRef: PreloadedQuery<MembershipLayoutQuery>;
|
queryRef: PreloadedQuery<ViewerMembershipLayoutQuery>;
|
||||||
}) {
|
}) {
|
||||||
const { hideSidebar = false, queryRef } = props;
|
const { hideSidebar = false, queryRef } = props;
|
||||||
|
|
||||||
const { __ } = useTranslate();
|
const { __ } = useTranslate();
|
||||||
|
|
||||||
const { organization, viewer } = usePreloadedQuery<MembershipLayoutQuery>(
|
const { organization, viewer } =
|
||||||
membershipLayoutQuery,
|
usePreloadedQuery<ViewerMembershipLayoutQuery>(
|
||||||
|
viewerMembershipLayoutQuery,
|
||||||
queryRef,
|
queryRef,
|
||||||
);
|
);
|
||||||
if (organization.__typename !== "Organization") {
|
if (organization.__typename !== "Organization") {
|
||||||
@@ -54,9 +58,8 @@ export function MembershipLayout(props: {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout
|
<Layout
|
||||||
header={
|
headerLeading={
|
||||||
<>
|
<>
|
||||||
<div className="mr-auto">
|
|
||||||
<MembershipsDropdown
|
<MembershipsDropdown
|
||||||
organizationFKey={organization}
|
organizationFKey={organization}
|
||||||
viewerFKey={viewer}
|
viewerFKey={viewer}
|
||||||
@@ -73,12 +76,13 @@ export function MembershipLayout(props: {
|
|||||||
</Badge>
|
</Badge>
|
||||||
</Link>
|
</Link>
|
||||||
)}
|
)}
|
||||||
</div>
|
|
||||||
<Suspense fallback={<Skeleton className="w-32 h-8" />}>
|
|
||||||
<SessionDropdown fKey={organization} />
|
|
||||||
</Suspense>
|
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
|
headerTrailing={
|
||||||
|
<Suspense fallback={<Skeleton className="w-32 h-8" />}>
|
||||||
|
<ViewerMembershipDropdown fKey={organization} />
|
||||||
|
</Suspense>
|
||||||
|
}
|
||||||
sidebar={!hideSidebar && <Sidebar fKey={organization} />}
|
sidebar={!hideSidebar && <Sidebar fKey={organization} />}
|
||||||
>
|
>
|
||||||
<CoreRelayProvider>
|
<CoreRelayProvider>
|
||||||
@@ -2,14 +2,17 @@ import { useQueryLoader } from "react-relay";
|
|||||||
import { Suspense, useEffect } from "react";
|
import { Suspense, useEffect } from "react";
|
||||||
import { Skeleton } from "@probo/ui";
|
import { Skeleton } from "@probo/ui";
|
||||||
import { useOrganizationId } from "/hooks/useOrganizationId";
|
import { useOrganizationId } from "/hooks/useOrganizationId";
|
||||||
import type { MembershipLayoutQuery } from "/__generated__/iam/MembershipLayoutQuery.graphql";
|
import type { ViewerMembershipLayoutQuery } from "/__generated__/iam/ViewerMembershipLayoutQuery.graphql";
|
||||||
import { MembershipLayout, membershipLayoutQuery } from "./MembershipLayout";
|
import {
|
||||||
|
ViewerMembershipLayout,
|
||||||
|
viewerMembershipLayoutQuery,
|
||||||
|
} from "./ViewerMembershipLayout";
|
||||||
import { IAMRelayProvider } from "/providers/IAMRelayProvider";
|
import { IAMRelayProvider } from "/providers/IAMRelayProvider";
|
||||||
|
|
||||||
function MembershipLayoutLoader() {
|
function MembershipLayoutLoader() {
|
||||||
const organizationId = useOrganizationId();
|
const organizationId = useOrganizationId();
|
||||||
const [queryRef, loadQuery] = useQueryLoader<MembershipLayoutQuery>(
|
const [queryRef, loadQuery] = useQueryLoader<ViewerMembershipLayoutQuery>(
|
||||||
membershipLayoutQuery,
|
viewerMembershipLayoutQuery,
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -25,7 +28,7 @@ function MembershipLayoutLoader() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Suspense fallback={<Skeleton className="w-full h-screen" />}>
|
<Suspense fallback={<Skeleton className="w-full h-screen" />}>
|
||||||
<MembershipLayout queryRef={queryRef} />
|
<ViewerMembershipLayout queryRef={queryRef} />
|
||||||
</Suspense>
|
</Suspense>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -12,15 +12,15 @@ import { graphql } from "relay-runtime";
|
|||||||
import { useOrganizationId } from "/hooks/useOrganizationId";
|
import { useOrganizationId } from "/hooks/useOrganizationId";
|
||||||
import { useFragment, useMutation } from "react-relay";
|
import { useFragment, useMutation } from "react-relay";
|
||||||
import { useTranslate } from "@probo/i18n";
|
import { useTranslate } from "@probo/i18n";
|
||||||
import type { SessionDropdownFragment$key } from "/__generated__/iam/SessionDropdownFragment.graphql";
|
import type { ViewerMembershipDropdownFragment$key } from "/__generated__/iam/ViewerMembershipDropdownFragment.graphql";
|
||||||
import { formatError } from "@probo/helpers";
|
import { formatError } from "@probo/helpers";
|
||||||
|
|
||||||
export const fragment = graphql`
|
export const fragment = graphql`
|
||||||
fragment SessionDropdownFragment on Organization {
|
fragment ViewerMembershipDropdownFragment on Organization {
|
||||||
canDelete: permission(action: "iam:organization:delete")
|
|
||||||
viewerMembership @required(action: THROW) {
|
viewerMembership @required(action: THROW) {
|
||||||
identity @required(action: THROW) {
|
identity @required(action: THROW) {
|
||||||
email
|
email
|
||||||
|
canListAPIKeys: permission(action: "iam:personal-api-key:list")
|
||||||
}
|
}
|
||||||
profile @required(action: THROW) {
|
profile @required(action: THROW) {
|
||||||
fullName
|
fullName
|
||||||
@@ -30,14 +30,16 @@ export const fragment = graphql`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const signOutMutation = graphql`
|
const signOutMutation = graphql`
|
||||||
mutation SessionDropdownSignOutMutation {
|
mutation ViewerMembershipDropdownSignOutMutation {
|
||||||
signOut {
|
signOut {
|
||||||
success
|
success
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export function SessionDropdown(props: { fKey: SessionDropdownFragment$key }) {
|
export function ViewerMembershipDropdown(props: {
|
||||||
|
fKey: ViewerMembershipDropdownFragment$key;
|
||||||
|
}) {
|
||||||
const { fKey } = props;
|
const { fKey } = props;
|
||||||
|
|
||||||
const { __ } = useTranslate();
|
const { __ } = useTranslate();
|
||||||
@@ -45,12 +47,11 @@ export function SessionDropdown(props: { fKey: SessionDropdownFragment$key }) {
|
|||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
canDelete,
|
|
||||||
viewerMembership: {
|
viewerMembership: {
|
||||||
identity: { email },
|
identity: { canListAPIKeys, email },
|
||||||
profile: { fullName },
|
profile: { fullName },
|
||||||
},
|
},
|
||||||
} = useFragment<SessionDropdownFragment$key>(fragment, fKey);
|
} = useFragment<ViewerMembershipDropdownFragment$key>(fragment, fKey);
|
||||||
const [signOut] = useMutation(signOutMutation);
|
const [signOut] = useMutation(signOutMutation);
|
||||||
|
|
||||||
const handleLogout: React.MouseEventHandler<HTMLAnchorElement> = (e) => {
|
const handleLogout: React.MouseEventHandler<HTMLAnchorElement> = (e) => {
|
||||||
@@ -81,7 +82,7 @@ export function SessionDropdown(props: { fKey: SessionDropdownFragment$key }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<UserDropdown fullName={fullName} email={email}>
|
<UserDropdown fullName={fullName} email={email}>
|
||||||
{canDelete && (
|
{canListAPIKeys && (
|
||||||
<UserDropdownItem
|
<UserDropdownItem
|
||||||
to="/me/api-keys"
|
to="/me/api-keys"
|
||||||
icon={IconKey}
|
icon={IconKey}
|
||||||
@@ -4,15 +4,15 @@ import { Skeleton } from "@probo/ui";
|
|||||||
import { useOrganizationId } from "/hooks/useOrganizationId";
|
import { useOrganizationId } from "/hooks/useOrganizationId";
|
||||||
import { IAMRelayProvider } from "/providers/IAMRelayProvider";
|
import { IAMRelayProvider } from "/providers/IAMRelayProvider";
|
||||||
import {
|
import {
|
||||||
MembershipLayout,
|
ViewerMembershipLayout,
|
||||||
membershipLayoutQuery,
|
viewerMembershipLayoutQuery,
|
||||||
} from "/pages/iam/memberships/MembershipLayout";
|
} from "../../iam/organizations/ViewerMembershipLayout";
|
||||||
import type { MembershipLayoutQuery } from "/__generated__/iam/MembershipLayoutQuery.graphql";
|
import type { ViewerMembershipLayoutQuery } from "/__generated__/iam/ViewerMembershipLayoutQuery.graphql";
|
||||||
|
|
||||||
function EmployeeLayoutLoader() {
|
function EmployeeLayoutLoader() {
|
||||||
const organizationId = useOrganizationId();
|
const organizationId = useOrganizationId();
|
||||||
const [queryRef, loadQuery] = useQueryLoader<MembershipLayoutQuery>(
|
const [queryRef, loadQuery] = useQueryLoader<ViewerMembershipLayoutQuery>(
|
||||||
membershipLayoutQuery,
|
viewerMembershipLayoutQuery,
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -28,7 +28,7 @@ function EmployeeLayoutLoader() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Suspense fallback={<Skeleton className="w-full h-screen" />}>
|
<Suspense fallback={<Skeleton className="w-full h-screen" />}>
|
||||||
<MembershipLayout queryRef={queryRef} hideSidebar />
|
<ViewerMembershipLayout queryRef={queryRef} hideSidebar />
|
||||||
</Suspense>
|
</Suspense>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import {
|
|||||||
redirect,
|
redirect,
|
||||||
useRouteError,
|
useRouteError,
|
||||||
} from "react-router";
|
} from "react-router";
|
||||||
import { CenteredLayout, CenteredLayoutSkeleton } from "@probo/ui";
|
import { CenteredLayoutSkeleton } from "@probo/ui";
|
||||||
import { PageSkeleton } from "./components/skeletons/PageSkeleton.tsx";
|
import { PageSkeleton } from "./components/skeletons/PageSkeleton.tsx";
|
||||||
import { riskRoutes } from "./routes/riskRoutes.ts";
|
import { riskRoutes } from "./routes/riskRoutes.ts";
|
||||||
import { measureRoutes } from "./routes/measureRoutes.ts";
|
import { measureRoutes } from "./routes/measureRoutes.ts";
|
||||||
@@ -103,7 +103,7 @@ const routes = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/",
|
path: "/",
|
||||||
Component: CenteredLayout,
|
Component: lazy(() => import("./pages/iam/memberships/ViewerLayoutLoader")),
|
||||||
Fallback: CenteredLayoutSkeleton,
|
Fallback: CenteredLayoutSkeleton,
|
||||||
ErrorBoundary: ErrorBoundary,
|
ErrorBoundary: ErrorBoundary,
|
||||||
children: [
|
children: [
|
||||||
@@ -158,7 +158,7 @@ const routes = [
|
|||||||
{
|
{
|
||||||
path: "/organizations/:organizationId",
|
path: "/organizations/:organizationId",
|
||||||
Component: lazy(
|
Component: lazy(
|
||||||
() => import("./pages/iam/memberships/MembershipLayoutLoader"),
|
() => import("./pages/iam/organizations/ViewerMembershipLayoutLoader"),
|
||||||
),
|
),
|
||||||
ErrorBoundary: ErrorBoundary,
|
ErrorBoundary: ErrorBoundary,
|
||||||
children: [
|
children: [
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { Skeleton } from "../Atoms/Skeleton/Skeleton";
|
|||||||
|
|
||||||
export function CenteredLayout({ children }: PropsWithChildren) {
|
export function CenteredLayout({ children }: PropsWithChildren) {
|
||||||
return (
|
return (
|
||||||
<div className="grid place-items-center min-h-screen text-txt-primary bg-level-0">
|
<div className="grid place-items-center min-h-[calc(100vh-48px-(2*48px))] text-txt-primary bg-level-0">
|
||||||
<div className="w-full max-w-2xl flex flex-col items-center">
|
<div className="w-full max-w-2xl flex flex-col items-center">
|
||||||
{children ?? <Outlet />}
|
{children ?? <Outlet />}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -13,17 +13,24 @@ import { Toasts } from "../Atoms/Toasts/Toasts.tsx";
|
|||||||
import { createPortal } from "react-dom";
|
import { createPortal } from "react-dom";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import { ConfirmDialog } from "../Molecules/Dialog/ConfirmDialog.tsx";
|
import { ConfirmDialog } from "../Molecules/Dialog/ConfirmDialog.tsx";
|
||||||
|
import { Link } from "react-router";
|
||||||
|
|
||||||
type Props = PropsWithChildren<{
|
type Props = PropsWithChildren<{
|
||||||
header: ReactNode;
|
headerLeading?: ReactNode;
|
||||||
sidebar: ReactNode;
|
headerTrailing: ReactNode;
|
||||||
|
sidebar?: ReactNode;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
const LayoutContext = createContext({
|
const LayoutContext = createContext({
|
||||||
setDrawer: (() => {}) as (v: boolean) => void,
|
setDrawer: (() => {}) as (v: boolean) => void,
|
||||||
});
|
});
|
||||||
|
|
||||||
export function Layout({ header, sidebar, children }: Props) {
|
export function Layout({
|
||||||
|
headerLeading,
|
||||||
|
headerTrailing,
|
||||||
|
sidebar,
|
||||||
|
children,
|
||||||
|
}: Props) {
|
||||||
const [hasDrawer, setDrawer] = useState(false);
|
const [hasDrawer, setDrawer] = useState(false);
|
||||||
const layoutContext = useMemo(
|
const layoutContext = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
@@ -35,7 +42,11 @@ export function Layout({ header, sidebar, children }: Props) {
|
|||||||
<LayoutContext value={layoutContext}>
|
<LayoutContext value={layoutContext}>
|
||||||
<div className="text-txt-primary bg-level-0">
|
<div className="text-txt-primary bg-level-0">
|
||||||
<header className="absolute z-2 left-0 right-0 px-4 flex items-center border-b border-border-solid h-12 bg-level-0">
|
<header className="absolute z-2 left-0 right-0 px-4 flex items-center border-b border-border-solid h-12 bg-level-0">
|
||||||
|
<Link to="/">
|
||||||
<Logo className="w-12 h-5" />
|
<Logo className="w-12 h-5" />
|
||||||
|
</Link>
|
||||||
|
{headerLeading && (
|
||||||
|
<>
|
||||||
<svg
|
<svg
|
||||||
className="mx-3 text-txt-tertiary"
|
className="mx-3 text-txt-tertiary"
|
||||||
width="8"
|
width="8"
|
||||||
@@ -46,7 +57,10 @@ export function Layout({ header, sidebar, children }: Props) {
|
|||||||
>
|
>
|
||||||
<path d="M1 17L7 1" stroke="currentColor" />
|
<path d="M1 17L7 1" stroke="currentColor" />
|
||||||
</svg>
|
</svg>
|
||||||
{header}
|
{headerLeading}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
<div className="ml-auto">{headerTrailing}</div>
|
||||||
</header>
|
</header>
|
||||||
<div className="flex h-screen" id="main">
|
<div className="flex h-screen" id="main">
|
||||||
{sidebar && <Sidebar>{sidebar}</Sidebar>}
|
{sidebar && <Sidebar>{sidebar}</Sidebar>}
|
||||||
|
|||||||
@@ -1528,14 +1528,15 @@ func (r *queryResolver) Node(ctx context.Context, id gid.GID) (types.Node, error
|
|||||||
|
|
||||||
// Viewer is the resolver for the viewer field.
|
// Viewer is the resolver for the viewer field.
|
||||||
func (r *queryResolver) Viewer(ctx context.Context) (*types.Identity, error) {
|
func (r *queryResolver) Viewer(ctx context.Context) (*types.Identity, error) {
|
||||||
user := IdentityFromContext(ctx)
|
identity := IdentityFromContext(ctx)
|
||||||
|
|
||||||
return &types.Identity{
|
return &types.Identity{
|
||||||
ID: user.ID,
|
ID: identity.ID,
|
||||||
Email: user.EmailAddress,
|
Email: identity.EmailAddress,
|
||||||
EmailVerified: user.EmailAddressVerified,
|
EmailVerified: identity.EmailAddressVerified,
|
||||||
CreatedAt: user.CreatedAt,
|
FullName: identity.FullName,
|
||||||
UpdatedAt: user.UpdatedAt,
|
CreatedAt: identity.CreatedAt,
|
||||||
|
UpdatedAt: identity.UpdatedAt,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user