Polish the session details
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
"expand": "Expand",
|
||||
"save": "Save",
|
||||
"save_and_continue": "Save and continue",
|
||||
"sign_out": "Sign out",
|
||||
"start_over": "Start over"
|
||||
},
|
||||
"branding": {
|
||||
@@ -69,8 +70,7 @@
|
||||
},
|
||||
"compat_session_detail": {
|
||||
"client_details_title": "Client info",
|
||||
"name": "Name",
|
||||
"session_details_title": "Session"
|
||||
"name": "Name"
|
||||
},
|
||||
"device_type_icon_label": {
|
||||
"mobile": "Mobile",
|
||||
@@ -83,7 +83,7 @@
|
||||
},
|
||||
"end_session_button": {
|
||||
"confirmation_modal_title": "Are you sure you want to end this session?",
|
||||
"text": "Sign out"
|
||||
"text": "Remove device"
|
||||
},
|
||||
"error": {
|
||||
"hideDetails": "Hide details",
|
||||
@@ -233,6 +233,7 @@
|
||||
"current": "Current",
|
||||
"device_id_label": "Device ID",
|
||||
"finished_label": "Finished",
|
||||
"generic_browser_session": "Browser session",
|
||||
"ip_label": "IP Address",
|
||||
"last_active_label": "Last Active",
|
||||
"name_for_platform": "{{name}} for {{platform}}",
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
/* Copyright 2024 New Vector Ltd.
|
||||
* Copyright 2023, 2024 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
.block {
|
||||
width: 100%;
|
||||
color: var(--cpd-color-text-primary);
|
||||
padding-bottom: var(--cpd-space-5x);
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
padding-bottom: var(--cpd-space-2x);
|
||||
border-bottom: var(--cpd-border-width-2) solid var(--cpd-color-gray-400);
|
||||
|
||||
/* Workaround compound design tokens heading style being broken */
|
||||
font-weight: var(--cpd-font-weight-semibold) !important;
|
||||
font-size: var(--cpd-font-size-heading-sm) !important;
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
// Copyright 2024 New Vector Ltd.
|
||||
// Copyright 2023, 2024 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
// Please see LICENSE in the repository root for full details.
|
||||
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
import { Body, H1, H5 } from "@vector-im/compound-web";
|
||||
|
||||
import Block from "./Block";
|
||||
|
||||
const meta = {
|
||||
title: "UI/Block",
|
||||
component: Block,
|
||||
tags: ["autodocs"],
|
||||
} satisfies Meta<typeof Block>;
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof Block>;
|
||||
|
||||
export const Basic: Story = {
|
||||
render: (args) => (
|
||||
<Block {...args}>
|
||||
<H1>Title</H1>
|
||||
<H5>Subtitle</H5>
|
||||
<Body justified>
|
||||
Lorem ipsum dolor sit amet, officia excepteur ex fugiat reprehenderit
|
||||
enim labore culpa sint ad nisi Lorem pariatur mollit ex esse
|
||||
exercitation amet. Nisi anim cupidatat excepteur officia. Reprehenderit
|
||||
nostrud nostrud ipsum Lorem est aliquip amet voluptate voluptate dolor
|
||||
minim nulla est proident. Nostrud officia pariatur ut officia. Sit irure
|
||||
elit esse ea nulla sunt ex occaecat reprehenderit commodo officia dolor
|
||||
Lorem duis laboris cupidatat officia voluptate. Culpa proident
|
||||
adipisicing id nulla nisi laboris ex in Lorem sunt duis officia eiusmod.
|
||||
Aliqua reprehenderit commodo ex non excepteur duis sunt velit enim.
|
||||
Voluptate laboris sint cupidatat ullamco ut ea consectetur et est culpa
|
||||
et culpa duis.
|
||||
</Body>
|
||||
</Block>
|
||||
),
|
||||
};
|
||||
@@ -1,39 +0,0 @@
|
||||
// Copyright 2024 New Vector Ltd.
|
||||
// Copyright 2023, 2024 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
// Please see LICENSE in the repository root for full details.
|
||||
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import render from "../../test-utils/render";
|
||||
import Block from "./Block";
|
||||
|
||||
describe("Block", () => {
|
||||
it("render <Block />", () => {
|
||||
const { asFragment } = render(<Block />);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("render <Block /> with children", () => {
|
||||
const { asFragment } = render(
|
||||
<Block>
|
||||
<h1>Title</h1>
|
||||
<p>Body</p>
|
||||
</Block>,
|
||||
);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("passes down the className prop", () => {
|
||||
const { asFragment } = render(<Block className="test" />);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("renders with highlight", () => {
|
||||
const { asFragment } = render(<Block highlight />);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -1,33 +0,0 @@
|
||||
// Copyright 2024 New Vector Ltd.
|
||||
// Copyright 2022-2024 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
// Please see LICENSE in the repository root for full details.
|
||||
|
||||
import { Heading } from "@vector-im/compound-web";
|
||||
import cx from "classnames";
|
||||
import type { ReactNode } from "react";
|
||||
|
||||
import styles from "./Block.module.css";
|
||||
|
||||
type Props = React.PropsWithChildren<{
|
||||
title?: ReactNode;
|
||||
className?: string;
|
||||
highlight?: boolean;
|
||||
}>;
|
||||
|
||||
const Block: React.FC<Props> = ({ children, className, highlight, title }) => {
|
||||
return (
|
||||
<div className={cx(styles.block, className)} data-active={highlight}>
|
||||
{title && (
|
||||
<Heading as="h4" size="sm" weight="semibold" className={styles.title}>
|
||||
{title}
|
||||
</Heading>
|
||||
)}
|
||||
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Block;
|
||||
@@ -1,41 +0,0 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`Block > passes down the className prop 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="_block_17898c test"
|
||||
/>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`Block > render <Block /> 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="_block_17898c"
|
||||
/>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`Block > render <Block /> with children 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="_block_17898c"
|
||||
>
|
||||
<h1>
|
||||
Title
|
||||
</h1>
|
||||
<p>
|
||||
Body
|
||||
</p>
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`Block > renders with highlight 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="_block_17898c"
|
||||
data-active="true"
|
||||
/>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
@@ -1,7 +0,0 @@
|
||||
// Copyright 2024 New Vector Ltd.
|
||||
// Copyright 2023, 2024 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
// Please see LICENSE in the repository root for full details.
|
||||
|
||||
export { default } from "./Block";
|
||||
@@ -1,13 +0,0 @@
|
||||
/* Copyright 2024 New Vector Ltd.
|
||||
* Copyright 2023, 2024 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
.block-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-content: flex-start;
|
||||
gap: var(--cpd-space-6x);
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
// Copyright 2024 New Vector Ltd.
|
||||
// Copyright 2023, 2024 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
// Please see LICENSE in the repository root for full details.
|
||||
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
import { H2, Text } from "@vector-im/compound-web";
|
||||
|
||||
import Block from "../Block";
|
||||
|
||||
import BlockList from "./BlockList";
|
||||
|
||||
const meta = {
|
||||
title: "UI/Block List",
|
||||
component: BlockList,
|
||||
} satisfies Meta<typeof BlockList>;
|
||||
|
||||
export default meta;
|
||||
|
||||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
export const Basic: Story = {
|
||||
render: (args) => (
|
||||
<BlockList {...args}>
|
||||
<Block>
|
||||
<H2>Block 1</H2>
|
||||
<Text>Body 1</Text>
|
||||
</Block>
|
||||
<Block>
|
||||
<H2>Block 2</H2>
|
||||
<Text>Body 2</Text>
|
||||
</Block>
|
||||
</BlockList>
|
||||
),
|
||||
};
|
||||
@@ -1,34 +0,0 @@
|
||||
// Copyright 2024 New Vector Ltd.
|
||||
// Copyright 2023, 2024 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
// Please see LICENSE in the repository root for full details.
|
||||
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { describe, expect, it } from "vitest";
|
||||
import render from "../../test-utils/render";
|
||||
import Block from "../Block";
|
||||
import BlockList from "./BlockList";
|
||||
|
||||
describe("BlockList", () => {
|
||||
it("render an empty <BlockList />", () => {
|
||||
const { asFragment } = render(<BlockList />);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("render <BlockList /> with children", () => {
|
||||
const { asFragment } = render(
|
||||
<BlockList>
|
||||
<Block>Block 1</Block>
|
||||
<Block>Block 2</Block>
|
||||
</BlockList>,
|
||||
);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("passes down the className prop", () => {
|
||||
const { asFragment } = render(<BlockList className="foo" />);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -1,19 +0,0 @@
|
||||
// Copyright 2024 New Vector Ltd.
|
||||
// Copyright 2022-2024 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
// Please see LICENSE in the repository root for full details.
|
||||
|
||||
import cx from "classnames";
|
||||
|
||||
import styles from "./BlockList.module.css";
|
||||
|
||||
type Props = React.PropsWithChildren<{
|
||||
className?: string;
|
||||
}>;
|
||||
|
||||
const BlockList: React.FC<Props> = ({ className, children }) => {
|
||||
return <div className={cx(styles.blockList, className)}>{children}</div>;
|
||||
};
|
||||
|
||||
export default BlockList;
|
||||
@@ -1,36 +0,0 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`BlockList > passes down the className prop 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="_blockList_f8cc7f foo"
|
||||
/>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`BlockList > render <BlockList /> with children 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="_blockList_f8cc7f"
|
||||
>
|
||||
<div
|
||||
class="_block_17898c"
|
||||
>
|
||||
Block 1
|
||||
</div>
|
||||
<div
|
||||
class="_block_17898c"
|
||||
>
|
||||
Block 2
|
||||
</div>
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`BlockList > render an empty <BlockList /> 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="_blockList_f8cc7f"
|
||||
/>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
@@ -1,7 +0,0 @@
|
||||
// Copyright 2024 New Vector Ltd.
|
||||
// Copyright 2023, 2024 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
// Please see LICENSE in the repository root for full details.
|
||||
|
||||
export { default } from "./BlockList";
|
||||
@@ -7,15 +7,12 @@
|
||||
import IconChrome from "@browser-logos/chrome/chrome_64x64.png?url";
|
||||
import IconFirefox from "@browser-logos/firefox/firefox_64x64.png?url";
|
||||
import IconSafari from "@browser-logos/safari/safari_64x64.png?url";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import { Badge } from "@vector-im/compound-web";
|
||||
import { parseISO } from "date-fns";
|
||||
import { useCallback } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { type FragmentType, graphql, useFragment } from "../gql";
|
||||
import { graphqlRequest } from "../graphql";
|
||||
import DateTime from "./DateTime";
|
||||
import EndSessionButton from "./Session/EndSessionButton";
|
||||
import EndBrowserSessionButton from "./Session/EndBrowserSessionButton";
|
||||
import LastActive from "./Session/LastActive";
|
||||
import * as Card from "./SessionCard";
|
||||
|
||||
@@ -24,62 +21,17 @@ const FRAGMENT = graphql(/* GraphQL */ `
|
||||
id
|
||||
createdAt
|
||||
finishedAt
|
||||
...EndBrowserSessionButton_session
|
||||
userAgent {
|
||||
raw
|
||||
deviceType
|
||||
name
|
||||
os
|
||||
model
|
||||
deviceType
|
||||
}
|
||||
lastActiveIp
|
||||
lastActiveAt
|
||||
lastAuthentication {
|
||||
id
|
||||
createdAt
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
const END_SESSION_MUTATION = graphql(/* GraphQL */ `
|
||||
mutation EndBrowserSession($id: ID!) {
|
||||
endBrowserSession(input: { browserSessionId: $id }) {
|
||||
status
|
||||
browserSession {
|
||||
id
|
||||
...BrowserSession_session
|
||||
}
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
export const useEndBrowserSession = (
|
||||
sessionId: string,
|
||||
isCurrent: boolean,
|
||||
): (() => Promise<void>) => {
|
||||
const queryClient = useQueryClient();
|
||||
const endSession = useMutation({
|
||||
mutationFn: (id: string) =>
|
||||
graphqlRequest({ query: END_SESSION_MUTATION, variables: { id } }),
|
||||
onSuccess: (data) => {
|
||||
queryClient.invalidateQueries({ queryKey: ["sessionsOverview"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["browserSessionList"] });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ["sessionDetail", data.endBrowserSession.browserSession?.id],
|
||||
});
|
||||
|
||||
if (isCurrent) {
|
||||
window.location.reload();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const onSessionEnd = useCallback(async (): Promise<void> => {
|
||||
await endSession.mutateAsync(sessionId);
|
||||
}, [endSession.mutateAsync, sessionId]);
|
||||
|
||||
return onSessionEnd;
|
||||
};
|
||||
|
||||
export const browserLogoUri = (browser?: string): string | undefined => {
|
||||
const lcBrowser = browser?.toLowerCase();
|
||||
|
||||
@@ -105,8 +57,6 @@ const BrowserSession: React.FC<Props> = ({ session, isCurrent }) => {
|
||||
const data = useFragment(FRAGMENT, session);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const onSessionEnd = useEndBrowserSession(data.id, isCurrent);
|
||||
|
||||
const deviceType = data.userAgent?.deviceType ?? "UNKNOWN";
|
||||
|
||||
let deviceName: string | null = null;
|
||||
@@ -175,14 +125,7 @@ const BrowserSession: React.FC<Props> = ({ session, isCurrent }) => {
|
||||
|
||||
{!data.finishedAt && (
|
||||
<Card.Action>
|
||||
<EndSessionButton endSession={onSessionEnd}>
|
||||
<Card.Body compact>
|
||||
<Card.Header type={deviceType}>
|
||||
<Card.Name name={deviceName} />
|
||||
{clientName && <Card.Client name={clientName} />}
|
||||
</Card.Header>
|
||||
</Card.Body>
|
||||
</EndSessionButton>
|
||||
<EndBrowserSessionButton session={data} size="sm" />
|
||||
</Card.Action>
|
||||
)}
|
||||
</Card.Root>
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
/* Copyright 2024 New Vector Ltd.
|
||||
* Copyright 2023, 2024 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
gap: var(--cpd-space-2x);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2024 New Vector Ltd.
|
||||
// Copyright 2024, 2025 New Vector Ltd.
|
||||
// Copyright 2023, 2024 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
@@ -9,12 +9,9 @@ import { useTranslation } from "react-i18next";
|
||||
|
||||
import { type FragmentType, useFragment } from "../../gql";
|
||||
import { graphql } from "../../gql/gql";
|
||||
import BlockList from "../BlockList/BlockList";
|
||||
import ExternalLink from "../ExternalLink/ExternalLink";
|
||||
import ClientAvatar from "../Session/ClientAvatar";
|
||||
import SessionDetails from "../SessionDetail/SessionDetails";
|
||||
|
||||
import styles from "./OAuth2ClientDetail.module.css";
|
||||
import * as Info from "../SessionDetail/SessionInfo";
|
||||
|
||||
export const OAUTH2_CLIENT_FRAGMENT = graphql(/* GraphQL */ `
|
||||
fragment OAuth2Client_detail on Oauth2Client {
|
||||
@@ -47,21 +44,9 @@ const OAuth2ClientDetail: React.FC<Props> = ({ client }) => {
|
||||
const data = useFragment(OAUTH2_CLIENT_FRAGMENT, client);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const details = [
|
||||
{ label: t("frontend.oauth2_client_detail.name"), value: data.clientName },
|
||||
{
|
||||
label: t("frontend.oauth2_client_detail.terms"),
|
||||
value: data.tosUri && <FriendlyExternalLink uri={data.tosUri} />,
|
||||
},
|
||||
{
|
||||
label: t("frontend.oauth2_client_detail.policy"),
|
||||
value: data.policyUri && <FriendlyExternalLink uri={data.policyUri} />,
|
||||
},
|
||||
].filter(({ value }) => !!value);
|
||||
|
||||
return (
|
||||
<BlockList>
|
||||
<header className={styles.header}>
|
||||
<div className="flex flex-col gap-10">
|
||||
<header className="flex flex-row gap-2 justify-start items-center">
|
||||
<ClientAvatar
|
||||
logoUri={data.logoUri || undefined}
|
||||
name={data.clientName || data.clientId}
|
||||
@@ -69,11 +54,42 @@ const OAuth2ClientDetail: React.FC<Props> = ({ client }) => {
|
||||
/>
|
||||
<H3>{data.clientName}</H3>
|
||||
</header>
|
||||
<SessionDetails
|
||||
title={t("frontend.oauth2_client_detail.details_title")}
|
||||
details={details}
|
||||
/>
|
||||
</BlockList>
|
||||
<Info.DataSection>
|
||||
<Info.DataSectionHeader>
|
||||
{t("frontend.oauth2_client_detail.details_title")}
|
||||
</Info.DataSectionHeader>
|
||||
<Info.DataList>
|
||||
{data.clientName && (
|
||||
<Info.Data>
|
||||
<Info.DataLabel>
|
||||
{t("frontend.oauth2_client_detail.name")}
|
||||
</Info.DataLabel>
|
||||
<Info.DataValue>{data.clientName}</Info.DataValue>
|
||||
</Info.Data>
|
||||
)}
|
||||
{data.tosUri && (
|
||||
<Info.Data>
|
||||
<Info.DataLabel>
|
||||
{t("frontend.oauth2_client_detail.terms")}
|
||||
</Info.DataLabel>
|
||||
<Info.DataValue>
|
||||
<FriendlyExternalLink uri={data.tosUri} />
|
||||
</Info.DataValue>
|
||||
</Info.Data>
|
||||
)}
|
||||
{data.policyUri && (
|
||||
<Info.Data>
|
||||
<Info.DataLabel>
|
||||
{t("frontend.oauth2_client_detail.policy")}
|
||||
</Info.DataLabel>
|
||||
<Info.DataValue>
|
||||
<FriendlyExternalLink uri={data.policyUri} />
|
||||
</Info.DataValue>
|
||||
</Info.Data>
|
||||
)}
|
||||
</Info.DataList>
|
||||
</Info.DataSection>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
exports[`<OAuth2ClientDetail> > renders client details 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="_blockList_f8cc7f"
|
||||
class="flex flex-col gap-10"
|
||||
>
|
||||
<header
|
||||
class="_header_477219"
|
||||
class="flex flex-row gap-2 justify-start items-center"
|
||||
>
|
||||
<h3
|
||||
class="_typography_yh5dq_162 _font-heading-md-semibold_yh5dq_121"
|
||||
@@ -14,71 +14,85 @@ exports[`<OAuth2ClientDetail> > renders client details 1`] = `
|
||||
Test Client
|
||||
</h3>
|
||||
</header>
|
||||
<div
|
||||
class="_block_17898c"
|
||||
<section
|
||||
class="flex flex-col gap-6"
|
||||
>
|
||||
<h4
|
||||
class="_typography_yh5dq_162 _font-heading-sm-semibold_yh5dq_102 _title_17898c"
|
||||
class="_typography_yh5dq_162 _font-heading-sm-semibold_yh5dq_102"
|
||||
>
|
||||
Client info
|
||||
</h4>
|
||||
<div
|
||||
class="_wrapper_040867"
|
||||
>
|
||||
<div
|
||||
class="_datum_040867"
|
||||
class="_separator_144s5_17"
|
||||
data-kind="section"
|
||||
data-orientation="horizontal"
|
||||
role="separator"
|
||||
/>
|
||||
</h4>
|
||||
<ul
|
||||
class="flex flex-wrap gap-x-10 gap-y-6"
|
||||
>
|
||||
<li
|
||||
class="flex flex-col min-w-0"
|
||||
>
|
||||
<h5
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40"
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40 text-secondary"
|
||||
>
|
||||
Name
|
||||
</h5>
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59 _datumValue_040867"
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59 text-ellipsis overflow-hidden"
|
||||
>
|
||||
Test Client
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
class="_datum_040867"
|
||||
</li>
|
||||
<li
|
||||
class="flex flex-col min-w-0"
|
||||
>
|
||||
<h5
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40"
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40 text-secondary"
|
||||
>
|
||||
Terms of service
|
||||
</h5>
|
||||
<a
|
||||
class="_link_ue21z_17 _externalLink_a97355"
|
||||
data-kind="primary"
|
||||
data-size="medium"
|
||||
href="https://client.org/tos"
|
||||
rel="noreferrer noopener"
|
||||
target="_blank"
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59 text-ellipsis overflow-hidden"
|
||||
>
|
||||
client.org/tos
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="_datum_040867"
|
||||
<a
|
||||
class="_link_ue21z_17 _externalLink_a97355"
|
||||
data-kind="primary"
|
||||
data-size="medium"
|
||||
href="https://client.org/tos"
|
||||
rel="noreferrer noopener"
|
||||
target="_blank"
|
||||
>
|
||||
client.org/tos
|
||||
</a>
|
||||
</p>
|
||||
</li>
|
||||
<li
|
||||
class="flex flex-col min-w-0"
|
||||
>
|
||||
<h5
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40"
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40 text-secondary"
|
||||
>
|
||||
Policy
|
||||
</h5>
|
||||
<a
|
||||
class="_link_ue21z_17 _externalLink_a97355"
|
||||
data-kind="primary"
|
||||
data-size="medium"
|
||||
href="https://client.org/policy"
|
||||
rel="noreferrer noopener"
|
||||
target="_blank"
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59 text-ellipsis overflow-hidden"
|
||||
>
|
||||
client.org/policy
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a
|
||||
class="_link_ue21z_17 _externalLink_a97355"
|
||||
data-kind="primary"
|
||||
data-size="medium"
|
||||
href="https://client.org/policy"
|
||||
rel="noreferrer noopener"
|
||||
target="_blank"
|
||||
>
|
||||
client.org/policy
|
||||
</a>
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
// Copyright 2024 New Vector Ltd.
|
||||
// Copyright 2024, 2025 New Vector Ltd.
|
||||
// Copyright 2022-2024 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
// Please see LICENSE in the repository root for full details.
|
||||
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import { parseISO } from "date-fns";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { type FragmentType, graphql, useFragment } from "../gql";
|
||||
import { graphqlRequest } from "../graphql";
|
||||
import simplifyUrl from "../utils/simplifyUrl";
|
||||
import { browserLogoUri } from "./BrowserSession";
|
||||
import DateTime from "./DateTime";
|
||||
import EndSessionButton from "./Session/EndSessionButton";
|
||||
import EndCompatSessionButton from "./Session/EndCompatSessionButton";
|
||||
import LastActive from "./Session/LastActive";
|
||||
import * as Card from "./SessionCard";
|
||||
|
||||
@@ -23,6 +22,7 @@ export const FRAGMENT = graphql(/* GraphQL */ `
|
||||
finishedAt
|
||||
lastActiveIp
|
||||
lastActiveAt
|
||||
...EndCompatSessionButton_session
|
||||
userAgent {
|
||||
name
|
||||
os
|
||||
@@ -36,59 +36,11 @@ export const FRAGMENT = graphql(/* GraphQL */ `
|
||||
}
|
||||
`);
|
||||
|
||||
export const END_SESSION_MUTATION = graphql(/* GraphQL */ `
|
||||
mutation EndCompatSession($id: ID!) {
|
||||
endCompatSession(input: { compatSessionId: $id }) {
|
||||
status
|
||||
compatSession {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
export const simplifyUrl = (url: string): string => {
|
||||
let parsed: URL;
|
||||
try {
|
||||
parsed = new URL(url);
|
||||
} catch (_e) {
|
||||
// Not a valid URL, return the original
|
||||
return url;
|
||||
}
|
||||
|
||||
// Clear out the search params and hash
|
||||
parsed.search = "";
|
||||
parsed.hash = "";
|
||||
|
||||
if (parsed.protocol === "https:") {
|
||||
return parsed.hostname;
|
||||
}
|
||||
|
||||
// Return the simplified URL
|
||||
return parsed.toString();
|
||||
};
|
||||
|
||||
const CompatSession: React.FC<{
|
||||
session: FragmentType<typeof FRAGMENT>;
|
||||
}> = ({ session }) => {
|
||||
const { t } = useTranslation();
|
||||
const data = useFragment(FRAGMENT, session);
|
||||
const queryClient = useQueryClient();
|
||||
const endSession = useMutation({
|
||||
mutationFn: (id: string) =>
|
||||
graphqlRequest({ query: END_SESSION_MUTATION, variables: { id } }),
|
||||
onSuccess: (data) => {
|
||||
queryClient.invalidateQueries({ queryKey: ["sessionsOverview"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["appSessionList"] });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ["sessionDetail", data.endCompatSession.compatSession?.id],
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const onSessionEnd = async (): Promise<void> => {
|
||||
await endSession.mutateAsync(data.id);
|
||||
};
|
||||
|
||||
const clientName = data.ssoLogin?.redirectUri
|
||||
? simplifyUrl(data.ssoLogin.redirectUri)
|
||||
@@ -146,14 +98,7 @@ const CompatSession: React.FC<{
|
||||
|
||||
{!data.finishedAt && (
|
||||
<Card.Action>
|
||||
<EndSessionButton endSession={onSessionEnd}>
|
||||
<Card.Body compact>
|
||||
<Card.Header type={deviceType}>
|
||||
<Card.Name name={deviceName} />
|
||||
{clientName && <Card.Client name={clientName} />}
|
||||
</Card.Header>
|
||||
</Card.Body>
|
||||
</EndSessionButton>
|
||||
<EndCompatSessionButton session={data} size="sm" />
|
||||
</Card.Action>
|
||||
)}
|
||||
</Card.Root>
|
||||
|
||||
@@ -8,8 +8,6 @@ import IconError from "@vector-im/compound-design-tokens/assets/web/icons/error"
|
||||
import { Button } from "@vector-im/compound-web";
|
||||
import { useState } from "react";
|
||||
import { Translation } from "react-i18next";
|
||||
|
||||
import BlockList from "./BlockList";
|
||||
import styles from "./GenericError.module.css";
|
||||
import PageHeading from "./PageHeading";
|
||||
|
||||
@@ -21,7 +19,7 @@ const GenericError: React.FC<{ error: unknown; dontSuspend?: boolean }> = ({
|
||||
return (
|
||||
<Translation useSuspense={!dontSuspend}>
|
||||
{(t) => (
|
||||
<BlockList>
|
||||
<div className="flex flex-col gap-10">
|
||||
<PageHeading
|
||||
invalid
|
||||
Icon={IconError}
|
||||
@@ -46,7 +44,7 @@ const GenericError: React.FC<{ error: unknown; dontSuspend?: boolean }> = ({
|
||||
<code>{String(error)}</code>
|
||||
</pre>
|
||||
)}
|
||||
</BlockList>
|
||||
</div>
|
||||
)}
|
||||
</Translation>
|
||||
);
|
||||
|
||||
@@ -1,18 +1,10 @@
|
||||
// Copyright 2024 New Vector Ltd.
|
||||
// Copyright 2022-2024 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
// Please see LICENSE in the repository root for full details.
|
||||
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import { parseISO } from "date-fns";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { type FragmentType, graphql, useFragment } from "../gql";
|
||||
import type { DeviceType, Oauth2ApplicationType } from "../gql/graphql";
|
||||
import { graphqlRequest } from "../graphql";
|
||||
import { getDeviceIdFromScope } from "../utils/deviceIdFromScope";
|
||||
import DateTime from "./DateTime";
|
||||
import EndSessionButton from "./Session/EndSessionButton";
|
||||
import EndOAuth2SessionButton from "./Session/EndOAuth2SessionButton";
|
||||
import LastActive from "./Session/LastActive";
|
||||
import * as Card from "./SessionCard";
|
||||
|
||||
@@ -25,6 +17,8 @@ export const FRAGMENT = graphql(/* GraphQL */ `
|
||||
lastActiveIp
|
||||
lastActiveAt
|
||||
|
||||
...EndOAuth2SessionButton_session
|
||||
|
||||
userAgent {
|
||||
name
|
||||
model
|
||||
@@ -42,17 +36,6 @@ export const FRAGMENT = graphql(/* GraphQL */ `
|
||||
}
|
||||
`);
|
||||
|
||||
export const END_SESSION_MUTATION = graphql(/* GraphQL */ `
|
||||
mutation EndOAuth2Session($id: ID!) {
|
||||
endOauth2Session(input: { oauth2SessionId: $id }) {
|
||||
status
|
||||
oauth2Session {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
const getDeviceTypeFromClientAppType = (
|
||||
appType?: Oauth2ApplicationType | null,
|
||||
): DeviceType => {
|
||||
@@ -72,22 +55,6 @@ type Props = {
|
||||
const OAuth2Session: React.FC<Props> = ({ session }) => {
|
||||
const { t } = useTranslation();
|
||||
const data = useFragment(FRAGMENT, session);
|
||||
const queryClient = useQueryClient();
|
||||
const endSession = useMutation({
|
||||
mutationFn: (id: string) =>
|
||||
graphqlRequest({ query: END_SESSION_MUTATION, variables: { id } }),
|
||||
onSuccess: (data) => {
|
||||
queryClient.invalidateQueries({ queryKey: ["sessionsOverview"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["appSessionList"] });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ["sessionDetail", data.endOauth2Session.oauth2Session?.id],
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const onSessionEnd = async (): Promise<void> => {
|
||||
await endSession.mutateAsync(data.id);
|
||||
};
|
||||
|
||||
const deviceId = getDeviceIdFromScope(data.scope);
|
||||
|
||||
@@ -149,17 +116,7 @@ const OAuth2Session: React.FC<Props> = ({ session }) => {
|
||||
|
||||
{!data.finishedAt && (
|
||||
<Card.Action>
|
||||
<EndSessionButton endSession={onSessionEnd}>
|
||||
<Card.Body compact>
|
||||
<Card.Header type={deviceType}>
|
||||
<Card.Name name={deviceName} />
|
||||
<Card.Client
|
||||
name={clientName}
|
||||
logoUri={data.client.logoUri ?? undefined}
|
||||
/>
|
||||
</Card.Header>
|
||||
</Card.Body>
|
||||
</EndSessionButton>
|
||||
<EndOAuth2SessionButton session={data} size="sm" />
|
||||
</Card.Action>
|
||||
)}
|
||||
</Card.Root>
|
||||
|
||||
128
frontend/src/components/Session/EndBrowserSessionButton.tsx
Normal file
128
frontend/src/components/Session/EndBrowserSessionButton.tsx
Normal file
@@ -0,0 +1,128 @@
|
||||
// Copyright 2025 New Vector Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
// Please see LICENSE in the repository root for full details.
|
||||
|
||||
import {
|
||||
type UseMutationResult,
|
||||
useMutation,
|
||||
useQueryClient,
|
||||
} from "@tanstack/react-query";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { type FragmentType, graphql, useFragment } from "../../gql";
|
||||
import { graphqlRequest } from "../../graphql";
|
||||
import * as Card from "../SessionCard";
|
||||
import EndSessionButton from "./EndSessionButton";
|
||||
|
||||
const FRAGMENT = graphql(/* GraphQL */ `
|
||||
fragment EndBrowserSessionButton_session on BrowserSession {
|
||||
id
|
||||
userAgent {
|
||||
name
|
||||
os
|
||||
model
|
||||
deviceType
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
const END_SESSION_MUTATION = graphql(/* GraphQL */ `
|
||||
mutation EndBrowserSession($id: ID!) {
|
||||
endBrowserSession(input: { browserSessionId: $id }) {
|
||||
status
|
||||
browserSession {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
export const useEndBrowserSession = (
|
||||
sessionId: string,
|
||||
isCurrent: boolean,
|
||||
): UseMutationResult<unknown, unknown, void> => {
|
||||
const queryClient = useQueryClient();
|
||||
const endSession = useMutation({
|
||||
mutationFn: () =>
|
||||
graphqlRequest({
|
||||
query: END_SESSION_MUTATION,
|
||||
variables: { id: sessionId },
|
||||
}),
|
||||
onSuccess: (data) => {
|
||||
queryClient.invalidateQueries({ queryKey: ["sessionsOverview"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["browserSessionList"] });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ["sessionDetail", data.endBrowserSession.browserSession?.id],
|
||||
});
|
||||
|
||||
if (isCurrent) {
|
||||
window.location.reload();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return endSession;
|
||||
};
|
||||
|
||||
type Props = {
|
||||
session: FragmentType<typeof FRAGMENT>;
|
||||
size: "sm" | "lg";
|
||||
};
|
||||
|
||||
const EndBrowserSessionButton: React.FC<Props> = ({ session, size }) => {
|
||||
const { t } = useTranslation();
|
||||
const data = useFragment(FRAGMENT, session);
|
||||
const queryClient = useQueryClient();
|
||||
const endSession = useMutation({
|
||||
mutationFn: () =>
|
||||
graphqlRequest({
|
||||
query: END_SESSION_MUTATION,
|
||||
variables: { id: data.id },
|
||||
}),
|
||||
onSuccess: (data) => {
|
||||
queryClient.invalidateQueries({ queryKey: ["sessionsOverview"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["appSessionList"] });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ["sessionDetail", data.endBrowserSession.browserSession?.id],
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const deviceType = data.userAgent?.deviceType ?? "UNKNOWN";
|
||||
|
||||
let deviceName: string | null = null;
|
||||
let clientName: string | null = null;
|
||||
|
||||
// If we have a model, use that as the device name, and the browser (+ OS) as the client name
|
||||
if (data.userAgent?.model) {
|
||||
deviceName = data.userAgent.model;
|
||||
if (data.userAgent?.name) {
|
||||
if (data.userAgent?.os) {
|
||||
clientName = t("frontend.session.name_for_platform", {
|
||||
name: data.userAgent.name,
|
||||
platform: data.userAgent.os,
|
||||
});
|
||||
} else {
|
||||
clientName = data.userAgent.name;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Else use the browser as the device name
|
||||
deviceName = data.userAgent?.name ?? t("frontend.session.unknown_browser");
|
||||
// and if we have an OS, use that as the client name
|
||||
clientName = data.userAgent?.os ?? null;
|
||||
}
|
||||
|
||||
return (
|
||||
<EndSessionButton mutation={endSession} size={size}>
|
||||
<Card.Body compact>
|
||||
<Card.Header type={deviceType}>
|
||||
<Card.Name name={deviceName} />
|
||||
{clientName && <Card.Client name={clientName} />}
|
||||
</Card.Header>
|
||||
</Card.Body>
|
||||
</EndSessionButton>
|
||||
);
|
||||
};
|
||||
|
||||
export default EndBrowserSessionButton;
|
||||
89
frontend/src/components/Session/EndCompatSessionButton.tsx
Normal file
89
frontend/src/components/Session/EndCompatSessionButton.tsx
Normal file
@@ -0,0 +1,89 @@
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { type FragmentType, graphql, useFragment } from "../../gql";
|
||||
import { graphqlRequest } from "../../graphql";
|
||||
import simplifyUrl from "../../utils/simplifyUrl";
|
||||
import * as Card from "../SessionCard";
|
||||
import EndSessionButton from "./EndSessionButton";
|
||||
|
||||
const FRAGMENT = graphql(/* GraphQL */ `
|
||||
fragment EndCompatSessionButton_session on CompatSession {
|
||||
id
|
||||
userAgent {
|
||||
name
|
||||
os
|
||||
model
|
||||
deviceType
|
||||
}
|
||||
ssoLogin {
|
||||
id
|
||||
redirectUri
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
const END_SESSION_MUTATION = graphql(/* GraphQL */ `
|
||||
mutation EndCompatSession($id: ID!) {
|
||||
endCompatSession(input: { compatSessionId: $id }) {
|
||||
status
|
||||
compatSession {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
type Props = {
|
||||
session: FragmentType<typeof FRAGMENT>;
|
||||
size: "sm" | "lg";
|
||||
};
|
||||
|
||||
const EndCompatSessionButton: React.FC<Props> = ({ session, size }) => {
|
||||
const { t } = useTranslation();
|
||||
const data = useFragment(FRAGMENT, session);
|
||||
const queryClient = useQueryClient();
|
||||
const endSession = useMutation({
|
||||
mutationFn: () =>
|
||||
graphqlRequest({
|
||||
query: END_SESSION_MUTATION,
|
||||
variables: { id: data.id },
|
||||
}),
|
||||
onSuccess: (data) => {
|
||||
queryClient.invalidateQueries({ queryKey: ["sessionsOverview"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["appSessionList"] });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ["sessionDetail", data.endCompatSession.compatSession?.id],
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const clientName = data.ssoLogin?.redirectUri
|
||||
? simplifyUrl(data.ssoLogin.redirectUri)
|
||||
: undefined;
|
||||
|
||||
const deviceType = data.userAgent?.deviceType ?? "UNKNOWN";
|
||||
|
||||
const deviceName =
|
||||
data.userAgent?.model ??
|
||||
(data.userAgent?.name
|
||||
? data.userAgent?.os
|
||||
? t("frontend.session.name_for_platform", {
|
||||
name: data.userAgent.name,
|
||||
platform: data.userAgent.os,
|
||||
})
|
||||
: data.userAgent.name
|
||||
: t("frontend.session.unknown_device"));
|
||||
|
||||
return (
|
||||
<EndSessionButton mutation={endSession} size={size}>
|
||||
<Card.Body compact>
|
||||
<Card.Header type={deviceType}>
|
||||
<Card.Name name={deviceName} />
|
||||
{clientName && <Card.Client name={clientName} />}
|
||||
</Card.Header>
|
||||
</Card.Body>
|
||||
</EndSessionButton>
|
||||
);
|
||||
};
|
||||
|
||||
export default EndCompatSessionButton;
|
||||
115
frontend/src/components/Session/EndOAuth2SessionButton.tsx
Normal file
115
frontend/src/components/Session/EndOAuth2SessionButton.tsx
Normal file
@@ -0,0 +1,115 @@
|
||||
// Copyright 2025 New Vector Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
// Please see LICENSE in the repository root for full details.
|
||||
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { type FragmentType, graphql, useFragment } from "../../gql";
|
||||
import type { DeviceType, Oauth2ApplicationType } from "../../gql/graphql";
|
||||
import { graphqlRequest } from "../../graphql";
|
||||
import * as Card from "../SessionCard";
|
||||
import EndSessionButton from "./EndSessionButton";
|
||||
|
||||
const FRAGMENT = graphql(/* GraphQL */ `
|
||||
fragment EndOAuth2SessionButton_session on Oauth2Session {
|
||||
id
|
||||
|
||||
userAgent {
|
||||
name
|
||||
model
|
||||
os
|
||||
deviceType
|
||||
}
|
||||
|
||||
client {
|
||||
clientId
|
||||
clientName
|
||||
applicationType
|
||||
logoUri
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
const END_SESSION_MUTATION = graphql(/* GraphQL */ `
|
||||
mutation EndOAuth2Session($id: ID!) {
|
||||
endOauth2Session(input: { oauth2SessionId: $id }) {
|
||||
status
|
||||
oauth2Session {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
const getDeviceTypeFromClientAppType = (
|
||||
appType?: Oauth2ApplicationType | null,
|
||||
): DeviceType => {
|
||||
if (appType === "WEB") {
|
||||
return "PC";
|
||||
}
|
||||
if (appType === "NATIVE") {
|
||||
return "MOBILE";
|
||||
}
|
||||
return "UNKNOWN";
|
||||
};
|
||||
|
||||
type Props = {
|
||||
session: FragmentType<typeof FRAGMENT>;
|
||||
size: "sm" | "lg";
|
||||
};
|
||||
|
||||
const EndOAuth2SessionButton: React.FC<Props> = ({ session, size }) => {
|
||||
const { t } = useTranslation();
|
||||
const data = useFragment(FRAGMENT, session);
|
||||
const queryClient = useQueryClient();
|
||||
const endSession = useMutation({
|
||||
mutationFn: () =>
|
||||
graphqlRequest({
|
||||
query: END_SESSION_MUTATION,
|
||||
variables: { id: data.id },
|
||||
}),
|
||||
onSuccess: (data) => {
|
||||
queryClient.invalidateQueries({ queryKey: ["sessionsOverview"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["appSessionList"] });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ["sessionDetail", data.endOauth2Session.oauth2Session?.id],
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const deviceType =
|
||||
(data.userAgent?.deviceType === "UNKNOWN"
|
||||
? null
|
||||
: data.userAgent?.deviceType) ??
|
||||
getDeviceTypeFromClientAppType(data.client.applicationType);
|
||||
|
||||
const clientName = data.client.clientName || data.client.clientId;
|
||||
|
||||
const deviceName =
|
||||
data.userAgent?.model ??
|
||||
(data.userAgent?.name
|
||||
? data.userAgent?.os
|
||||
? t("frontend.session.name_for_platform", {
|
||||
name: data.userAgent.name,
|
||||
platform: data.userAgent.os,
|
||||
})
|
||||
: data.userAgent.name
|
||||
: t("frontend.session.unknown_device"));
|
||||
|
||||
return (
|
||||
<EndSessionButton mutation={endSession} size={size}>
|
||||
<Card.Body compact>
|
||||
<Card.Header type={deviceType}>
|
||||
<Card.Name name={deviceName} />
|
||||
<Card.Client
|
||||
name={clientName}
|
||||
logoUri={data.client.logoUri ?? undefined}
|
||||
/>
|
||||
</Card.Header>
|
||||
</Card.Body>
|
||||
</EndSessionButton>
|
||||
);
|
||||
};
|
||||
|
||||
export default EndOAuth2SessionButton;
|
||||
@@ -1,39 +0,0 @@
|
||||
// Copyright 2024 New Vector Ltd.
|
||||
// Copyright 2024 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
// Please see LICENSE in the repository root for full details.
|
||||
|
||||
import { action } from "@storybook/addon-actions";
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
|
||||
import EndSessionButton from "./EndSessionButton";
|
||||
|
||||
const endSession = action("end-session");
|
||||
|
||||
const meta = {
|
||||
title: "UI/Session/End Session Button",
|
||||
component: EndSessionButton,
|
||||
tags: ["autodocs"],
|
||||
args: {
|
||||
endSession: async (): Promise<void> => {
|
||||
await new Promise((resolve) => setTimeout(resolve, 300));
|
||||
endSession();
|
||||
},
|
||||
},
|
||||
argTypes: {
|
||||
children: { control: "text" },
|
||||
},
|
||||
} satisfies Meta<typeof EndSessionButton>;
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof EndSessionButton>;
|
||||
|
||||
export const Basic: Story = {};
|
||||
|
||||
export const WithChildren: Story = {
|
||||
args: {
|
||||
children:
|
||||
"Lorem ipsum dolor sit amet, officia excepteur ex fugiat reprehenderit enim labore culpa sint ad nisi Lorem pariatur mollit ex esse exercitation amet. Nisi anim cupidatat excepteur officia. Reprehenderit nostrud nostrud ipsum Lorem est aliquip amet voluptate voluptate dolor minim nulla est proident. Nostrud officia pariatur ut officia. Sit irure elit esse ea nulla sunt ex occaecat reprehenderit commodo officia dolor Lorem duis laboris cupidatat officia voluptate. Culpa proident adipisicing id nulla nisi laboris ex in Lorem sunt duis officia eiusmod. Aliqua reprehenderit commodo ex non excepteur duis sunt velit enim. Voluptate laboris sint cupidatat ullamco ut ea consectetur et est culpa et culpa duis.",
|
||||
},
|
||||
};
|
||||
@@ -1,14 +1,14 @@
|
||||
// Copyright 2024 New Vector Ltd.
|
||||
// Copyright 2024, 2025 New Vector Ltd.
|
||||
// Copyright 2023, 2024 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
// Please see LICENSE in the repository root for full details.
|
||||
|
||||
import IconSignOut from "@vector-im/compound-design-tokens/assets/web/icons/sign-out";
|
||||
import type { UseMutationResult } from "@tanstack/react-query";
|
||||
import IconDelete from "@vector-im/compound-design-tokens/assets/web/icons/delete";
|
||||
import { Button } from "@vector-im/compound-web";
|
||||
import { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import * as Dialog from "../Dialog";
|
||||
import LoadingSpinner from "../LoadingSpinner/LoadingSpinner";
|
||||
|
||||
@@ -17,25 +17,17 @@ import LoadingSpinner from "../LoadingSpinner/LoadingSpinner";
|
||||
* Handles loading state while endSession is in progress
|
||||
*/
|
||||
const EndSessionButton: React.FC<
|
||||
React.PropsWithChildren<{ endSession: () => Promise<void> }>
|
||||
> = ({ children, endSession }) => {
|
||||
const [inProgress, setInProgress] = useState(false);
|
||||
React.PropsWithChildren<{
|
||||
mutation: UseMutationResult<unknown, unknown, void>;
|
||||
size: "sm" | "lg";
|
||||
}>
|
||||
> = ({ children, mutation, size }) => {
|
||||
const [open, setOpen] = useState(false);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const onConfirm = async (
|
||||
e: React.MouseEvent<HTMLButtonElement>,
|
||||
): Promise<void> => {
|
||||
const onConfirm = (e: React.MouseEvent<HTMLButtonElement>): void => {
|
||||
e.preventDefault();
|
||||
|
||||
setInProgress(true);
|
||||
try {
|
||||
await endSession();
|
||||
setOpen(false);
|
||||
} catch (error) {
|
||||
console.error("Failed to end session", error);
|
||||
}
|
||||
setInProgress(false);
|
||||
mutation.mutate(void 0, { onSuccess: () => setOpen(false) });
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -43,7 +35,7 @@ const EndSessionButton: React.FC<
|
||||
open={open}
|
||||
onOpenChange={setOpen}
|
||||
trigger={
|
||||
<Button kind="secondary" destructive size="sm" Icon={IconSignOut}>
|
||||
<Button kind="secondary" destructive size={size} Icon={IconDelete}>
|
||||
{t("frontend.end_session_button.text")}
|
||||
</Button>
|
||||
}
|
||||
@@ -59,10 +51,10 @@ const EndSessionButton: React.FC<
|
||||
kind="primary"
|
||||
destructive
|
||||
onClick={onConfirm}
|
||||
disabled={inProgress}
|
||||
Icon={inProgress ? undefined : IconSignOut}
|
||||
disabled={mutation.isPending}
|
||||
Icon={mutation.isPending ? undefined : IconDelete}
|
||||
>
|
||||
{inProgress && <LoadingSpinner inline />}
|
||||
{mutation.isPending && <LoadingSpinner inline />}
|
||||
{t("frontend.end_session_button.text")}
|
||||
</Button>
|
||||
|
||||
|
||||
@@ -111,6 +111,10 @@
|
||||
flex-wrap: wrap;
|
||||
gap: var(--cpd-space-4x) var(--cpd-space-10x);
|
||||
|
||||
& > * {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
& .key {
|
||||
font: var(--cpd-font-body-sm-regular);
|
||||
letter-spacing: var(--cpd-font-letter-spacing-body-sm);
|
||||
@@ -121,6 +125,8 @@
|
||||
font: var(--cpd-font-body-md-regular);
|
||||
letter-spacing: var(--cpd-font-letter-spacing-body-md);
|
||||
color: var(--cpd-color-text-primary);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
/* Copyright 2024 New Vector Ltd.
|
||||
* Copyright 2023, 2024 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
.current-badge {
|
||||
align-self: flex-start;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2024 New Vector Ltd.
|
||||
// Copyright 2024, 2025 New Vector Ltd.
|
||||
// Copyright 2023, 2024 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
@@ -7,22 +7,19 @@
|
||||
import { Badge } from "@vector-im/compound-web";
|
||||
import { parseISO } from "date-fns";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { type FragmentType, graphql, useFragment } from "../../gql";
|
||||
import BlockList from "../BlockList/BlockList";
|
||||
import { useEndBrowserSession } from "../BrowserSession";
|
||||
import DateTime from "../DateTime";
|
||||
import EndSessionButton from "../Session/EndSessionButton";
|
||||
|
||||
import styles from "./BrowserSessionDetail.module.css";
|
||||
import SessionDetails from "./SessionDetails";
|
||||
import EndBrowserSessionButton from "../Session/EndBrowserSessionButton";
|
||||
import LastActive from "../Session/LastActive";
|
||||
import SessionHeader from "./SessionHeader";
|
||||
import * as Info from "./SessionInfo";
|
||||
|
||||
const FRAGMENT = graphql(/* GraphQL */ `
|
||||
fragment BrowserSession_detail on BrowserSession {
|
||||
id
|
||||
createdAt
|
||||
finishedAt
|
||||
...EndBrowserSessionButton_session
|
||||
userAgent {
|
||||
name
|
||||
model
|
||||
@@ -50,51 +47,79 @@ const BrowserSessionDetail: React.FC<Props> = ({ session, isCurrent }) => {
|
||||
const data = useFragment(FRAGMENT, session);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const onSessionEnd = useEndBrowserSession(data.id, isCurrent);
|
||||
|
||||
let sessionName = "Browser session";
|
||||
let sessionName = t("frontend.session.generic_browser_session");
|
||||
if (data.userAgent) {
|
||||
if (data.userAgent.model && data.userAgent.name) {
|
||||
sessionName = `${data.userAgent.name} on ${data.userAgent.model}`;
|
||||
sessionName = t("frontend.session.name_for_platform", {
|
||||
name: data.userAgent.name,
|
||||
platform: data.userAgent.model,
|
||||
});
|
||||
} else if (data.userAgent.name && data.userAgent.os) {
|
||||
sessionName = `${data.userAgent.name} on ${data.userAgent.os}`;
|
||||
sessionName = t("frontend.session.name_for_platform", {
|
||||
name: data.userAgent.name,
|
||||
platform: data.userAgent.os,
|
||||
});
|
||||
} else if (data.userAgent.name) {
|
||||
sessionName = data.userAgent.name;
|
||||
}
|
||||
}
|
||||
|
||||
const finishedAt = data.finishedAt
|
||||
? [
|
||||
{
|
||||
label: t("frontend.session.finished_label"),
|
||||
value: <DateTime datetime={parseISO(data.finishedAt)} />,
|
||||
},
|
||||
]
|
||||
: [];
|
||||
|
||||
const sessionDetails = [...finishedAt];
|
||||
|
||||
return (
|
||||
<BlockList>
|
||||
<div className="flex flex-col gap-10">
|
||||
{isCurrent && (
|
||||
<Badge className={styles.currentBadge} kind="green">
|
||||
<Badge className="self-start" kind="green">
|
||||
{t("frontend.browser_session_details.current_badge")}
|
||||
</Badge>
|
||||
)}
|
||||
<SessionHeader to="/sessions/browsers">{sessionName}</SessionHeader>
|
||||
<SessionDetails
|
||||
title={t("frontend.session.title")}
|
||||
lastActive={data.lastActiveAt ? parseISO(data.lastActiveAt) : undefined}
|
||||
signedIn={
|
||||
data.lastAuthentication
|
||||
? parseISO(data.lastAuthentication.createdAt)
|
||||
: undefined
|
||||
}
|
||||
ipAddress={data.lastActiveIp ?? undefined}
|
||||
details={sessionDetails}
|
||||
/>
|
||||
{!data.finishedAt && <EndSessionButton endSession={onSessionEnd} />}
|
||||
</BlockList>
|
||||
<Info.DataSection>
|
||||
<Info.DataSectionHeader>
|
||||
{t("frontend.session.title")}
|
||||
</Info.DataSectionHeader>
|
||||
<Info.DataList>
|
||||
{data.lastActiveAt && (
|
||||
<Info.Data>
|
||||
<Info.DataLabel>
|
||||
{t("frontend.session.last_active_label")}
|
||||
</Info.DataLabel>
|
||||
<Info.DataValue>
|
||||
<LastActive lastActive={parseISO(data.lastActiveAt)} />
|
||||
</Info.DataValue>
|
||||
</Info.Data>
|
||||
)}
|
||||
|
||||
<Info.Data>
|
||||
<Info.DataLabel>
|
||||
{t("frontend.session.signed_in_label")}
|
||||
</Info.DataLabel>
|
||||
<Info.DataValue>
|
||||
<DateTime datetime={data.createdAt} />
|
||||
</Info.DataValue>
|
||||
</Info.Data>
|
||||
|
||||
{data.finishedAt && (
|
||||
<Info.Data>
|
||||
<Info.DataLabel>
|
||||
{t("frontend.session.finished_label")}
|
||||
</Info.DataLabel>
|
||||
<Info.DataValue>
|
||||
<DateTime datetime={data.finishedAt} />
|
||||
</Info.DataValue>
|
||||
</Info.Data>
|
||||
)}
|
||||
|
||||
{data.lastActiveIp && (
|
||||
<Info.Data>
|
||||
<Info.DataLabel>{t("frontend.session.ip_label")}</Info.DataLabel>
|
||||
<Info.DataValue>
|
||||
<code>{data.lastActiveIp}</code>
|
||||
</Info.DataValue>
|
||||
</Info.Data>
|
||||
)}
|
||||
</Info.DataList>
|
||||
</Info.DataSection>
|
||||
{!data.finishedAt && <EndBrowserSessionButton session={data} size="lg" />}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ describe("<CompatSessionDetail>", () => {
|
||||
|
||||
expect(container).toMatchSnapshot();
|
||||
expect(queryByText("Finished")).toBeFalsy();
|
||||
expect(getByText("Sign out")).toBeTruthy();
|
||||
expect(getByText("Remove device")).toBeTruthy();
|
||||
});
|
||||
|
||||
it("renders a compatability session without an ssoLogin", () => {
|
||||
@@ -56,7 +56,7 @@ describe("<CompatSessionDetail>", () => {
|
||||
|
||||
expect(container).toMatchSnapshot();
|
||||
expect(queryByText("Finished")).toBeFalsy();
|
||||
expect(getByText("Sign out")).toBeTruthy();
|
||||
expect(getByText("Remove device")).toBeTruthy();
|
||||
});
|
||||
|
||||
it("renders a finished compatability session details", () => {
|
||||
@@ -74,6 +74,6 @@ describe("<CompatSessionDetail>", () => {
|
||||
|
||||
expect(container).toMatchSnapshot();
|
||||
expect(getByText("Finished")).toBeTruthy();
|
||||
expect(queryByText("Sign out")).toBeFalsy();
|
||||
expect(queryByText("Remove device")).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,21 +1,19 @@
|
||||
// Copyright 2024 New Vector Ltd.
|
||||
// Copyright 2024, 2025 New Vector Ltd.
|
||||
// Copyright 2022-2024 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
// Please see LICENSE in the repository root for full details.
|
||||
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import { VisualList } from "@vector-im/compound-web";
|
||||
import { parseISO } from "date-fns";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { type FragmentType, graphql, useFragment } from "../../gql";
|
||||
import { graphqlRequest } from "../../graphql";
|
||||
import BlockList from "../BlockList/BlockList";
|
||||
import { END_SESSION_MUTATION, simplifyUrl } from "../CompatSession";
|
||||
import simplifyUrl from "../../utils/simplifyUrl";
|
||||
import DateTime from "../DateTime";
|
||||
import ExternalLink from "../ExternalLink/ExternalLink";
|
||||
import EndSessionButton from "../Session/EndSessionButton";
|
||||
import SessionDetails from "./SessionDetails";
|
||||
import EndCompatSessionButton from "../Session/EndCompatSessionButton";
|
||||
import LastActive from "../Session/LastActive";
|
||||
import SessionHeader from "./SessionHeader";
|
||||
import * as Info from "./SessionInfo";
|
||||
|
||||
export const FRAGMENT = graphql(/* GraphQL */ `
|
||||
fragment CompatSession_detail on CompatSession {
|
||||
@@ -25,11 +23,15 @@ export const FRAGMENT = graphql(/* GraphQL */ `
|
||||
finishedAt
|
||||
lastActiveIp
|
||||
lastActiveAt
|
||||
|
||||
...EndCompatSessionButton_session
|
||||
|
||||
userAgent {
|
||||
name
|
||||
os
|
||||
model
|
||||
}
|
||||
|
||||
ssoLogin {
|
||||
id
|
||||
redirectUri
|
||||
@@ -43,74 +45,111 @@ type Props = {
|
||||
|
||||
const CompatSessionDetail: React.FC<Props> = ({ session }) => {
|
||||
const data = useFragment(FRAGMENT, session);
|
||||
const queryClient = useQueryClient();
|
||||
const endSession = useMutation({
|
||||
mutationFn: (id: string) =>
|
||||
graphqlRequest({ query: END_SESSION_MUTATION, variables: { id } }),
|
||||
onSuccess: (data) => {
|
||||
queryClient.invalidateQueries({ queryKey: ["sessionsOverview"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["appSessionList"] });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ["sessionDetail", data.endCompatSession.compatSession?.id],
|
||||
});
|
||||
},
|
||||
});
|
||||
const { t } = useTranslation();
|
||||
|
||||
const onSessionEnd = async (): Promise<void> => {
|
||||
await endSession.mutateAsync(data.id);
|
||||
};
|
||||
const deviceName =
|
||||
data.userAgent?.model ??
|
||||
(data.userAgent?.name
|
||||
? data.userAgent?.os
|
||||
? t("frontend.session.name_for_platform", {
|
||||
name: data.userAgent.name,
|
||||
platform: data.userAgent.os,
|
||||
})
|
||||
: data.userAgent.name
|
||||
: t("frontend.session.unknown_device"));
|
||||
|
||||
const finishedAt = data.finishedAt
|
||||
? [
|
||||
{
|
||||
label: t("frontend.session.finished_label"),
|
||||
value: <DateTime datetime={parseISO(data.finishedAt)} />,
|
||||
},
|
||||
]
|
||||
: [];
|
||||
|
||||
const sessionDetails = [...finishedAt];
|
||||
|
||||
const clientDetails: { label: string; value: string | React.ReactElement }[] =
|
||||
[];
|
||||
|
||||
if (data.ssoLogin?.redirectUri) {
|
||||
clientDetails.push({
|
||||
label: t("frontend.compat_session_detail.name"),
|
||||
value: data.userAgent?.name ?? simplifyUrl(data.ssoLogin.redirectUri),
|
||||
});
|
||||
clientDetails.push({
|
||||
label: t("frontend.session.uri_label"),
|
||||
value: (
|
||||
<ExternalLink target="_blank" href={data.ssoLogin?.redirectUri}>
|
||||
{data.ssoLogin?.redirectUri}
|
||||
</ExternalLink>
|
||||
),
|
||||
});
|
||||
}
|
||||
const clientName = data.ssoLogin?.redirectUri
|
||||
? simplifyUrl(data.ssoLogin.redirectUri)
|
||||
: data.deviceId || data.id;
|
||||
|
||||
return (
|
||||
<BlockList>
|
||||
<SessionHeader to="/sessions">{data.deviceId || data.id}</SessionHeader>
|
||||
<SessionDetails
|
||||
title={t("frontend.compat_session_detail.session_details_title")}
|
||||
deviceId={data.deviceId}
|
||||
signedIn={parseISO(data.createdAt)}
|
||||
lastActive={data.lastActiveAt ? parseISO(data.lastActiveAt) : undefined}
|
||||
ipAddress={data.lastActiveIp ?? undefined}
|
||||
details={sessionDetails}
|
||||
// These scopes need to be kept in sync with `templates/pages/sso.html`
|
||||
scopes={["openid", "urn:matrix:org.matrix.msc2967.client:api:*"]}
|
||||
/>
|
||||
{clientDetails.length > 0 ? (
|
||||
<SessionDetails
|
||||
title={t("frontend.compat_session_detail.client_details_title")}
|
||||
details={clientDetails}
|
||||
/>
|
||||
) : null}
|
||||
{!data.finishedAt && <EndSessionButton endSession={onSessionEnd} />}
|
||||
</BlockList>
|
||||
<div className="flex flex-col gap-10">
|
||||
<SessionHeader to="/sessions">
|
||||
{clientName}: {deviceName}
|
||||
</SessionHeader>
|
||||
<Info.DataSection>
|
||||
<Info.DataSectionHeader>
|
||||
{t("frontend.session.title")}
|
||||
</Info.DataSectionHeader>
|
||||
<Info.DataList>
|
||||
{data.lastActiveAt && (
|
||||
<Info.Data>
|
||||
<Info.DataLabel>
|
||||
{t("frontend.session.last_active_label")}
|
||||
</Info.DataLabel>
|
||||
<Info.DataValue>
|
||||
<LastActive lastActive={parseISO(data.lastActiveAt)} />
|
||||
</Info.DataValue>
|
||||
</Info.Data>
|
||||
)}
|
||||
|
||||
<Info.Data>
|
||||
<Info.DataLabel>
|
||||
{t("frontend.session.signed_in_label")}
|
||||
</Info.DataLabel>
|
||||
<Info.DataValue>
|
||||
<DateTime datetime={data.createdAt} />
|
||||
</Info.DataValue>
|
||||
</Info.Data>
|
||||
|
||||
{data.finishedAt && (
|
||||
<Info.Data>
|
||||
<Info.DataLabel>
|
||||
{t("frontend.session.finished_label")}
|
||||
</Info.DataLabel>
|
||||
<Info.DataValue>
|
||||
<DateTime datetime={data.finishedAt} />
|
||||
</Info.DataValue>
|
||||
</Info.Data>
|
||||
)}
|
||||
|
||||
<Info.Data>
|
||||
<Info.DataLabel>
|
||||
{t("frontend.session.device_id_label")}
|
||||
</Info.DataLabel>
|
||||
<Info.DataValue>{data.deviceId}</Info.DataValue>
|
||||
</Info.Data>
|
||||
|
||||
{data.lastActiveIp && (
|
||||
<Info.Data>
|
||||
<Info.DataLabel>{t("frontend.session.ip_label")}</Info.DataLabel>
|
||||
<Info.DataValue>
|
||||
<code>{data.lastActiveIp}</code>
|
||||
</Info.DataValue>
|
||||
</Info.Data>
|
||||
)}
|
||||
</Info.DataList>
|
||||
|
||||
<Info.Data>
|
||||
<Info.DataLabel>{t("frontend.session.scopes_label")}</Info.DataLabel>
|
||||
<VisualList className="mt-1">
|
||||
<Info.ScopeViewProfile />
|
||||
<Info.ScopeViewMessages />
|
||||
<Info.ScopeSendMessages />
|
||||
</VisualList>
|
||||
</Info.Data>
|
||||
</Info.DataSection>
|
||||
|
||||
<Info.DataSection>
|
||||
<Info.DataSectionHeader>
|
||||
{t("frontend.compat_session_detail.client_details_title")}
|
||||
</Info.DataSectionHeader>
|
||||
<Info.DataList>
|
||||
<Info.Data>
|
||||
<Info.DataLabel>
|
||||
{t("frontend.compat_session_detail.name")}
|
||||
</Info.DataLabel>
|
||||
<Info.DataValue>{deviceName}</Info.DataValue>
|
||||
</Info.Data>
|
||||
<Info.Data>
|
||||
<Info.DataLabel>{t("frontend.session.uri_label")}</Info.DataLabel>
|
||||
<Info.DataValue>{data.ssoLogin?.redirectUri}</Info.DataValue>
|
||||
</Info.Data>
|
||||
</Info.DataList>
|
||||
</Info.DataSection>
|
||||
|
||||
{!data.finishedAt && <EndCompatSessionButton session={data} size="lg" />}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ describe("<OAuth2SessionDetail>", () => {
|
||||
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
expect(queryByText("Finished")).toBeFalsy();
|
||||
expect(getByText("Sign out")).toBeTruthy();
|
||||
expect(getByText("Remove device")).toBeTruthy();
|
||||
});
|
||||
|
||||
it("renders a finished session details", () => {
|
||||
@@ -62,6 +62,6 @@ describe("<OAuth2SessionDetail>", () => {
|
||||
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
expect(getByText("Finished")).toBeTruthy();
|
||||
expect(queryByText("Sign out")).toBeFalsy();
|
||||
expect(queryByText("Remove device")).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,23 +1,19 @@
|
||||
// Copyright 2024 New Vector Ltd.
|
||||
// Copyright 2024, 2025 New Vector Ltd.
|
||||
// Copyright 2023, 2024 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
// Please see LICENSE in the repository root for full details.
|
||||
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import { parseISO } from "date-fns";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { type FragmentType, graphql, useFragment } from "../../gql";
|
||||
import { graphqlRequest } from "../../graphql";
|
||||
import { getDeviceIdFromScope } from "../../utils/deviceIdFromScope";
|
||||
import BlockList from "../BlockList/BlockList";
|
||||
import DateTime from "../DateTime";
|
||||
import { Link } from "../Link";
|
||||
import { END_SESSION_MUTATION } from "../OAuth2Session";
|
||||
import ClientAvatar from "../Session/ClientAvatar";
|
||||
import EndSessionButton from "../Session/EndSessionButton";
|
||||
import SessionDetails from "./SessionDetails";
|
||||
import EndOAuth2SessionButton from "../Session/EndOAuth2SessionButton";
|
||||
import LastActive from "../Session/LastActive";
|
||||
import SessionHeader from "./SessionHeader";
|
||||
import * as Info from "./SessionInfo";
|
||||
|
||||
export const FRAGMENT = graphql(/* GraphQL */ `
|
||||
fragment OAuth2Session_detail on Oauth2Session {
|
||||
@@ -27,6 +23,15 @@ export const FRAGMENT = graphql(/* GraphQL */ `
|
||||
finishedAt
|
||||
lastActiveIp
|
||||
lastActiveAt
|
||||
|
||||
...EndOAuth2SessionButton_session
|
||||
|
||||
userAgent {
|
||||
name
|
||||
model
|
||||
os
|
||||
}
|
||||
|
||||
client {
|
||||
id
|
||||
clientId
|
||||
@@ -43,90 +48,129 @@ type Props = {
|
||||
|
||||
const OAuth2SessionDetail: React.FC<Props> = ({ session }) => {
|
||||
const data = useFragment(FRAGMENT, session);
|
||||
const queryClient = useQueryClient();
|
||||
const endSession = useMutation({
|
||||
mutationFn: (id: string) =>
|
||||
graphqlRequest({ query: END_SESSION_MUTATION, variables: { id } }),
|
||||
onSuccess: (data) => {
|
||||
queryClient.invalidateQueries({ queryKey: ["sessionsOverview"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["appSessionList"] });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ["sessionDetail", data.endOauth2Session.oauth2Session?.id],
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
const onSessionEnd = async (): Promise<void> => {
|
||||
await endSession.mutateAsync(data.id);
|
||||
};
|
||||
|
||||
const deviceId = getDeviceIdFromScope(data.scope);
|
||||
const clientName = data.client.clientName || data.client.clientId;
|
||||
|
||||
const finishedAt = data.finishedAt
|
||||
? [
|
||||
{
|
||||
label: t("frontend.session.finished_label"),
|
||||
value: <DateTime datetime={parseISO(data.finishedAt)} />,
|
||||
},
|
||||
]
|
||||
: [];
|
||||
|
||||
const sessionDetails = [...finishedAt];
|
||||
|
||||
const clientTitle = (
|
||||
<Link to="/clients/$id" params={{ id: data.client.id }}>
|
||||
{t("frontend.oauth2_session_detail.client_title")}
|
||||
</Link>
|
||||
);
|
||||
const clientDetails = [
|
||||
{
|
||||
label: t("frontend.oauth2_session_detail.client_details_name"),
|
||||
value: (
|
||||
<>
|
||||
<ClientAvatar
|
||||
name={data.client.clientName || data.client.clientId}
|
||||
logoUri={data.client.logoUri || undefined}
|
||||
size="var(--cpd-space-4x)"
|
||||
/>
|
||||
{data.client.clientName}
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
label: t("frontend.session.client_id_label"),
|
||||
value: <code>{data.client.clientId}</code>,
|
||||
},
|
||||
{
|
||||
label: t("frontend.session.uri_label"),
|
||||
value: (
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
href={data.client.clientUri || undefined}
|
||||
>
|
||||
{data.client.clientUri}
|
||||
</a>
|
||||
),
|
||||
},
|
||||
];
|
||||
const deviceName =
|
||||
data.userAgent?.model ??
|
||||
(data.userAgent?.name
|
||||
? data.userAgent?.os
|
||||
? t("frontend.session.name_for_platform", {
|
||||
name: data.userAgent.name,
|
||||
platform: data.userAgent.os,
|
||||
})
|
||||
: data.userAgent.name
|
||||
: t("frontend.session.unknown_device"));
|
||||
|
||||
return (
|
||||
<BlockList>
|
||||
<SessionHeader to="/sessions">{deviceId || data.id}</SessionHeader>
|
||||
<SessionDetails
|
||||
title={t("frontend.session.title")}
|
||||
lastActive={data.lastActiveAt ? parseISO(data.lastActiveAt) : undefined}
|
||||
signedIn={parseISO(data.createdAt)}
|
||||
deviceId={deviceId}
|
||||
ipAddress={data.lastActiveIp ?? undefined}
|
||||
scopes={data.scope.split(" ")}
|
||||
details={sessionDetails}
|
||||
/>
|
||||
<SessionDetails title={clientTitle} details={clientDetails} />
|
||||
{!data.finishedAt && <EndSessionButton endSession={onSessionEnd} />}
|
||||
</BlockList>
|
||||
<div className="flex flex-col gap-10">
|
||||
<SessionHeader to="/sessions">
|
||||
{clientName}: {deviceName}
|
||||
</SessionHeader>
|
||||
<Info.DataSection>
|
||||
<Info.DataSectionHeader>
|
||||
{t("frontend.session.title")}
|
||||
</Info.DataSectionHeader>
|
||||
<Info.DataList>
|
||||
{data.lastActiveAt && (
|
||||
<Info.Data>
|
||||
<Info.DataLabel>
|
||||
{t("frontend.session.last_active_label")}
|
||||
</Info.DataLabel>
|
||||
<Info.DataValue>
|
||||
<LastActive lastActive={parseISO(data.lastActiveAt)} />
|
||||
</Info.DataValue>
|
||||
</Info.Data>
|
||||
)}
|
||||
|
||||
<Info.Data>
|
||||
<Info.DataLabel>
|
||||
{t("frontend.session.signed_in_label")}
|
||||
</Info.DataLabel>
|
||||
<Info.DataValue>
|
||||
<DateTime datetime={data.createdAt} />
|
||||
</Info.DataValue>
|
||||
</Info.Data>
|
||||
|
||||
{data.finishedAt && (
|
||||
<Info.Data>
|
||||
<Info.DataLabel>
|
||||
{t("frontend.session.finished_label")}
|
||||
</Info.DataLabel>
|
||||
<Info.DataValue>
|
||||
<DateTime datetime={data.finishedAt} />
|
||||
</Info.DataValue>
|
||||
</Info.Data>
|
||||
)}
|
||||
|
||||
<Info.Data>
|
||||
<Info.DataLabel>
|
||||
{t("frontend.session.device_id_label")}
|
||||
</Info.DataLabel>
|
||||
<Info.DataValue>{deviceId}</Info.DataValue>
|
||||
</Info.Data>
|
||||
|
||||
{data.lastActiveIp && (
|
||||
<Info.Data>
|
||||
<Info.DataLabel>{t("frontend.session.ip_label")}</Info.DataLabel>
|
||||
<Info.DataValue>
|
||||
<code>{data.lastActiveIp}</code>
|
||||
</Info.DataValue>
|
||||
</Info.Data>
|
||||
)}
|
||||
</Info.DataList>
|
||||
|
||||
<Info.Data>
|
||||
<Info.DataLabel>{t("frontend.session.scopes_label")}</Info.DataLabel>
|
||||
<Info.ScopeList scope={data.scope} />
|
||||
</Info.Data>
|
||||
</Info.DataSection>
|
||||
|
||||
<Info.DataSection>
|
||||
<Info.DataSectionHeader>
|
||||
{t("frontend.oauth2_session_detail.client_title")}
|
||||
</Info.DataSectionHeader>
|
||||
<Info.DataList>
|
||||
<Info.Data>
|
||||
<Info.DataLabel>
|
||||
{t("frontend.oauth2_session_detail.client_details_name")}
|
||||
</Info.DataLabel>
|
||||
<Info.DataValue>
|
||||
<ClientAvatar
|
||||
name={data.client.clientName || data.client.clientId}
|
||||
logoUri={data.client.logoUri || undefined}
|
||||
size="var(--cpd-space-4x)"
|
||||
/>
|
||||
{data.client.clientName}
|
||||
</Info.DataValue>
|
||||
</Info.Data>
|
||||
<Info.Data>
|
||||
<Info.DataLabel>
|
||||
{t("frontend.session.client_id_label")}
|
||||
</Info.DataLabel>
|
||||
<Info.DataValue>
|
||||
<code>{data.client.clientId}</code>
|
||||
</Info.DataValue>
|
||||
</Info.Data>
|
||||
<Info.Data>
|
||||
<Info.DataLabel>{t("frontend.session.uri_label")}</Info.DataLabel>
|
||||
<Info.DataValue>
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
href={data.client.clientUri || undefined}
|
||||
>
|
||||
{data.client.clientUri}
|
||||
</a>
|
||||
</Info.DataValue>
|
||||
</Info.Data>
|
||||
</Info.DataList>
|
||||
</Info.DataSection>
|
||||
|
||||
{!data.finishedAt && <EndOAuth2SessionButton session={data} size="lg" />}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
/* Copyright 2024 New Vector Ltd.
|
||||
* Copyright 2023, 2024 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
.wrapper {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--cpd-space-4x);
|
||||
margin-bottom: var(--cpd-space-4x);
|
||||
margin-top: var(--cpd-space-8x);
|
||||
}
|
||||
|
||||
.wrapper h5 {
|
||||
color: var(--cpd-color-text-secondary);
|
||||
}
|
||||
|
||||
.wrapper .datum {
|
||||
width: max-content;
|
||||
}
|
||||
|
||||
.datum {
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.datum-value {
|
||||
font-size: var(--cpd-font-size-body-md);
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
// Copyright 2024 New Vector Ltd.
|
||||
// Copyright 2022-2024 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
// Please see LICENSE in the repository root for full details.
|
||||
|
||||
import IconChat from "@vector-im/compound-design-tokens/assets/web/icons/chat";
|
||||
import IconComputer from "@vector-im/compound-design-tokens/assets/web/icons/computer";
|
||||
import IconError from "@vector-im/compound-design-tokens/assets/web/icons/error";
|
||||
import IconInfo from "@vector-im/compound-design-tokens/assets/web/icons/info";
|
||||
import IconSend from "@vector-im/compound-design-tokens/assets/web/icons/send";
|
||||
import IconUserProfile from "@vector-im/compound-design-tokens/assets/web/icons/user-profile";
|
||||
import { Text } from "@vector-im/compound-web";
|
||||
import type { ReactNode } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import Block from "../Block/Block";
|
||||
import DateTime from "../DateTime";
|
||||
import LastActive from "../Session/LastActive";
|
||||
import { VisualList, VisualListItem } from "../VisualList/VisualList";
|
||||
|
||||
import styles from "./SessionDetails.module.css";
|
||||
|
||||
type Detail = { label: string; value: ReactNode };
|
||||
type Props = {
|
||||
title: string | ReactNode;
|
||||
lastActive?: Date;
|
||||
signedIn?: Date;
|
||||
deviceId?: string | null;
|
||||
ipAddress?: string;
|
||||
scopes?: string[];
|
||||
details?: Detail[];
|
||||
};
|
||||
|
||||
const Scope: React.FC<{ scope: string }> = ({ scope }) => {
|
||||
const { t } = useTranslation();
|
||||
// Filter out "urn:matrix:org.matrix.msc2967.client:device:"
|
||||
if (scope.startsWith("urn:matrix:org.matrix.msc2967.client:device:")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Needs to be manually kept in sync with /templates/components/scope.html
|
||||
const scopeMap: Record<string, [number, typeof IconInfo, string][]> = {
|
||||
openid: [[0, IconUserProfile, t("mas.scope.view_profile")]],
|
||||
"urn:mas:graphql:*": [
|
||||
[1, IconInfo, t("mas.scope.edit_profile")],
|
||||
[2, IconComputer, t("mas.scope.manage_sessions")],
|
||||
],
|
||||
"urn:matrix:org.matrix.msc2967.client:api:*": [
|
||||
[3, IconChat, t("mas.scope.view_messages")],
|
||||
[4, IconSend, t("mas.scope.send_messages")],
|
||||
],
|
||||
"urn:synapse:admin:*": [[5, IconError, t("mas.scope.synapse_admin")]],
|
||||
"urn:mas:admin": [[6, IconError, t("mas.scope.mas_admin")]],
|
||||
} as const;
|
||||
|
||||
const mappedScopes: [number | string, typeof IconInfo, string][] = scopeMap[
|
||||
scope
|
||||
] ?? [[scope, IconInfo, scope]];
|
||||
|
||||
return (
|
||||
<>
|
||||
{mappedScopes.map(([key, Icon, text]) => (
|
||||
<VisualListItem key={key} Icon={Icon} label={text} />
|
||||
))}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const Datum: React.FC<{ label: string; value: ReactNode }> = ({
|
||||
label,
|
||||
value,
|
||||
}) => {
|
||||
return (
|
||||
<div className={styles.datum}>
|
||||
<Text size="sm" weight="regular" as="h5">
|
||||
{label}
|
||||
</Text>
|
||||
{typeof value === "string" ? (
|
||||
<Text size="md" className={styles.datumValue}>
|
||||
{value}
|
||||
</Text>
|
||||
) : (
|
||||
value
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const SessionDetails: React.FC<Props> = ({
|
||||
title,
|
||||
lastActive,
|
||||
signedIn,
|
||||
deviceId,
|
||||
ipAddress,
|
||||
details,
|
||||
scopes,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<Block title={title}>
|
||||
<div className={styles.wrapper}>
|
||||
{lastActive && (
|
||||
<Datum
|
||||
label={t("frontend.session.last_active_label")}
|
||||
value={
|
||||
<LastActive
|
||||
className={styles.datumValue}
|
||||
lastActive={lastActive}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{signedIn && (
|
||||
<Datum
|
||||
label={t("frontend.session.signed_in_label")}
|
||||
value={
|
||||
<DateTime className={styles.datumValue} datetime={signedIn} />
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{deviceId && (
|
||||
<Datum
|
||||
label={t("frontend.session.device_id_label")}
|
||||
value={deviceId}
|
||||
/>
|
||||
)}
|
||||
{ipAddress && (
|
||||
<Datum
|
||||
label={t("frontend.session.ip_label")}
|
||||
value={<code className={styles.datumValue}>{ipAddress}</code>}
|
||||
/>
|
||||
)}
|
||||
{details?.map(({ label, value }) => (
|
||||
<Datum key={label} label={label} value={value} />
|
||||
))}
|
||||
</div>
|
||||
|
||||
{scopes?.length && (
|
||||
<Datum
|
||||
label={t("frontend.session.scopes_label")}
|
||||
value={
|
||||
<VisualList>
|
||||
{scopes.map((scope) => (
|
||||
<Scope key={scope} scope={scope} />
|
||||
))}
|
||||
</VisualList>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</Block>
|
||||
);
|
||||
};
|
||||
|
||||
export default SessionDetails;
|
||||
183
frontend/src/components/SessionDetail/SessionInfo.tsx
Normal file
183
frontend/src/components/SessionDetail/SessionInfo.tsx
Normal file
@@ -0,0 +1,183 @@
|
||||
// Copyright 2025 New Vector Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
// Please see LICENSE in the repository root for full details.
|
||||
|
||||
import IconChat from "@vector-im/compound-design-tokens/assets/web/icons/chat";
|
||||
import IconComputer from "@vector-im/compound-design-tokens/assets/web/icons/computer";
|
||||
import IconError from "@vector-im/compound-design-tokens/assets/web/icons/error";
|
||||
import IconInfo from "@vector-im/compound-design-tokens/assets/web/icons/info";
|
||||
import IconSend from "@vector-im/compound-design-tokens/assets/web/icons/send";
|
||||
import IconUserProfile from "@vector-im/compound-design-tokens/assets/web/icons/user-profile";
|
||||
import {
|
||||
Heading,
|
||||
Separator,
|
||||
Text,
|
||||
VisualList,
|
||||
VisualListItem,
|
||||
} from "@vector-im/compound-web";
|
||||
import cx from "classnames";
|
||||
import type * as React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
export const ScopeViewProfile: React.FC = () => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<VisualListItem Icon={IconUserProfile}>
|
||||
{t("mas.scope.view_profile")}
|
||||
</VisualListItem>
|
||||
);
|
||||
};
|
||||
|
||||
const ScopeEditProfile: React.FC = () => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<VisualListItem Icon={IconInfo}>
|
||||
{t("mas.scope.edit_profile")}
|
||||
</VisualListItem>
|
||||
);
|
||||
};
|
||||
|
||||
const ScopeManageSessions: React.FC = () => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<VisualListItem Icon={IconComputer}>
|
||||
{t("mas.scope.manage_sessions")}
|
||||
</VisualListItem>
|
||||
);
|
||||
};
|
||||
|
||||
export const ScopeViewMessages: React.FC = () => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<VisualListItem Icon={IconChat}>
|
||||
{t("mas.scope.view_messages")}
|
||||
</VisualListItem>
|
||||
);
|
||||
};
|
||||
|
||||
export const ScopeSendMessages: React.FC = () => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<VisualListItem Icon={IconSend}>
|
||||
{t("mas.scope.send_messages")}
|
||||
</VisualListItem>
|
||||
);
|
||||
};
|
||||
|
||||
const ScopeSynapseAdmin: React.FC = () => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<VisualListItem Icon={IconError}>
|
||||
{t("mas.scope.synapse_admin")}
|
||||
</VisualListItem>
|
||||
);
|
||||
};
|
||||
|
||||
const ScopeMasAdmin: React.FC = () => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<VisualListItem Icon={IconError}>{t("mas.scope.mas_admin")}</VisualListItem>
|
||||
);
|
||||
};
|
||||
|
||||
const ScopeOther: React.FC<{ scope: string }> = ({ scope }) => {
|
||||
return <VisualListItem Icon={IconInfo}>{scope}</VisualListItem>;
|
||||
};
|
||||
|
||||
const Scope: React.FC<{ scope: string }> = ({ scope }) => {
|
||||
// Filter out "urn:matrix:org.matrix.msc2967.client:device:"
|
||||
if (scope.startsWith("urn:matrix:org.matrix.msc2967.client:device:")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (scope) {
|
||||
case "openid":
|
||||
return <ScopeViewProfile />;
|
||||
case "urn:mas:graphql:*":
|
||||
return (
|
||||
<>
|
||||
<ScopeEditProfile />
|
||||
<ScopeManageSessions />
|
||||
</>
|
||||
);
|
||||
case "urn:matrix:org.matrix.msc2967.client:api:*":
|
||||
return (
|
||||
<>
|
||||
<ScopeViewMessages />
|
||||
<ScopeSendMessages />
|
||||
</>
|
||||
);
|
||||
case "urn:synapse:admin:*":
|
||||
return <ScopeSynapseAdmin />;
|
||||
case "urn:mas:admin":
|
||||
return <ScopeMasAdmin />;
|
||||
default:
|
||||
return <ScopeOther scope={scope} />;
|
||||
}
|
||||
};
|
||||
|
||||
export const ScopeList: React.FC<{ scope: string }> = ({ scope }) => {
|
||||
const scopes = scope.split(" ");
|
||||
return (
|
||||
<VisualList className="mt-1">
|
||||
{scopes.map((scope) => (
|
||||
<Scope key={scope} scope={scope} />
|
||||
))}
|
||||
</VisualList>
|
||||
);
|
||||
};
|
||||
|
||||
export const Data: React.FC<
|
||||
React.PropsWithChildren<{ className?: string }>
|
||||
> = ({ children, className }) => (
|
||||
<li className={cx("flex flex-col min-w-0", className)}>{children}</li>
|
||||
);
|
||||
|
||||
export const DataLabel: React.FC<
|
||||
React.PropsWithChildren<{ className?: string }>
|
||||
> = ({ children, className }) => (
|
||||
<Text
|
||||
size="sm"
|
||||
weight="regular"
|
||||
as="h5"
|
||||
className={cx("text-secondary", className)}
|
||||
>
|
||||
{children}
|
||||
</Text>
|
||||
);
|
||||
|
||||
export const DataValue: React.FC<
|
||||
React.PropsWithChildren<{ className?: string }>
|
||||
> = ({ children, className }) => (
|
||||
<Text
|
||||
size="md"
|
||||
weight="regular"
|
||||
className={cx("text-ellipsis overflow-hidden", className)}
|
||||
>
|
||||
{children}
|
||||
</Text>
|
||||
);
|
||||
|
||||
export const DataList: React.FC<
|
||||
React.PropsWithChildren<{ className?: string }>
|
||||
> = ({ children, className }) => (
|
||||
<ul className={cx("flex flex-wrap gap-x-10 gap-y-6", className)}>
|
||||
{children}
|
||||
</ul>
|
||||
);
|
||||
|
||||
export const DataSection: React.FC<
|
||||
React.PropsWithChildren<{ className?: string }>
|
||||
> = ({ children, className }) => (
|
||||
<section className={cx("flex flex-col gap-6", className)}>{children}</section>
|
||||
);
|
||||
|
||||
export const DataSectionHeader: React.FC<
|
||||
React.PropsWithChildren<{ className?: string }>
|
||||
> = ({ children, className }) => (
|
||||
<Heading as="h4" size="sm" weight="semibold" className={className}>
|
||||
{children}
|
||||
<Separator kind="section" />
|
||||
</Heading>
|
||||
);
|
||||
@@ -3,7 +3,7 @@
|
||||
exports[`<CompatSessionDetail> > renders a compatability session details 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="_blockList_f8cc7f"
|
||||
class="flex flex-col gap-10"
|
||||
>
|
||||
<header
|
||||
class="_header_92353c"
|
||||
@@ -27,99 +27,116 @@ exports[`<CompatSessionDetail> > renders a compatability session details 1`] = `
|
||||
<h3
|
||||
class="_typography_yh5dq_162 _font-heading-md-semibold_yh5dq_121"
|
||||
>
|
||||
abcd1234
|
||||
element.io
|
||||
:
|
||||
Unknown device
|
||||
</h3>
|
||||
</header>
|
||||
<div
|
||||
class="_block_17898c"
|
||||
<section
|
||||
class="flex flex-col gap-6"
|
||||
>
|
||||
<h4
|
||||
class="_typography_yh5dq_162 _font-heading-sm-semibold_yh5dq_102 _title_17898c"
|
||||
>
|
||||
Session
|
||||
</h4>
|
||||
<div
|
||||
class="_wrapper_040867"
|
||||
class="_typography_yh5dq_162 _font-heading-sm-semibold_yh5dq_102"
|
||||
>
|
||||
Device details
|
||||
<div
|
||||
class="_datum_040867"
|
||||
class="_separator_144s5_17"
|
||||
data-kind="section"
|
||||
data-orientation="horizontal"
|
||||
role="separator"
|
||||
/>
|
||||
</h4>
|
||||
<ul
|
||||
class="flex flex-wrap gap-x-10 gap-y-6"
|
||||
>
|
||||
<li
|
||||
class="flex flex-col min-w-0"
|
||||
>
|
||||
<h5
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40"
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40 text-secondary"
|
||||
>
|
||||
Last Active
|
||||
</h5>
|
||||
<span
|
||||
class="_datumValue_040867"
|
||||
title="Sat, 29 Jul 2023, 03:35"
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59 text-ellipsis overflow-hidden"
|
||||
>
|
||||
Inactive for 90+ days
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="_datum_040867"
|
||||
<span
|
||||
title="Sat, 29 Jul 2023, 03:35"
|
||||
>
|
||||
Inactive for 90+ days
|
||||
</span>
|
||||
</p>
|
||||
</li>
|
||||
<li
|
||||
class="flex flex-col min-w-0"
|
||||
>
|
||||
<h5
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40"
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40 text-secondary"
|
||||
>
|
||||
Signed in
|
||||
</h5>
|
||||
<time
|
||||
class="_datumValue_040867"
|
||||
datetime="2023-06-29T03:35:17Z"
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59 text-ellipsis overflow-hidden"
|
||||
>
|
||||
Thu, 29 Jun 2023, 03:35
|
||||
</time>
|
||||
</div>
|
||||
<div
|
||||
class="_datum_040867"
|
||||
<time
|
||||
datetime="2023-06-29T03:35:17Z"
|
||||
>
|
||||
Thu, 29 Jun 2023, 03:35
|
||||
</time>
|
||||
</p>
|
||||
</li>
|
||||
<li
|
||||
class="flex flex-col min-w-0"
|
||||
>
|
||||
<h5
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40"
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40 text-secondary"
|
||||
>
|
||||
Device ID
|
||||
</h5>
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59 _datumValue_040867"
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59 text-ellipsis overflow-hidden"
|
||||
>
|
||||
abcd1234
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
class="_datum_040867"
|
||||
</li>
|
||||
<li
|
||||
class="flex flex-col min-w-0"
|
||||
>
|
||||
<h5
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40"
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40 text-secondary"
|
||||
>
|
||||
IP Address
|
||||
</h5>
|
||||
<code
|
||||
class="_datumValue_040867"
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59 text-ellipsis overflow-hidden"
|
||||
>
|
||||
1.2.3.4
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_datum_040867"
|
||||
<code>
|
||||
1.2.3.4
|
||||
</code>
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
<li
|
||||
class="flex flex-col min-w-0"
|
||||
>
|
||||
<h5
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40"
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40 text-secondary"
|
||||
>
|
||||
Scopes
|
||||
</h5>
|
||||
<ul
|
||||
class="_list_7f22f8"
|
||||
class="_visual-list_4dcf8_17 mt-1"
|
||||
>
|
||||
<li
|
||||
class="_item_7f22f8"
|
||||
class="_visual-list-item_bqeu7_17"
|
||||
>
|
||||
<svg
|
||||
color="var(--cpd-color-icon-tertiary)"
|
||||
aria-hidden="true"
|
||||
class="_visual-list-item-icon_bqeu7_26"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
height="24px"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
width="24px"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
@@ -132,42 +149,36 @@ exports[`<CompatSessionDetail> > renders a compatability session details 1`] = `
|
||||
d="M16.23 18.792a12.47 12.47 0 0 0-1.455-.455 11.6 11.6 0 0 0-5.55 0c-.487.12-.972.271-1.455.455a8.04 8.04 0 0 1-1.729-1.454c.89-.412 1.794-.729 2.709-.95A13.76 13.76 0 0 1 12 16c1.1 0 2.183.13 3.25.387a14.78 14.78 0 0 1 2.709.95 8.042 8.042 0 0 1-1.73 1.455Z"
|
||||
/>
|
||||
</svg>
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59"
|
||||
>
|
||||
See your profile info and contact details
|
||||
</p>
|
||||
See your profile info and contact details
|
||||
</li>
|
||||
<li
|
||||
class="_item_7f22f8"
|
||||
class="_visual-list-item_bqeu7_17"
|
||||
>
|
||||
<svg
|
||||
color="var(--cpd-color-icon-tertiary)"
|
||||
aria-hidden="true"
|
||||
class="_visual-list-item-icon_bqeu7_26"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
height="24px"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
width="24px"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="m1.5 21.25 1.45-4.95a10.232 10.232 0 0 1-.712-2.1A10.167 10.167 0 0 1 2 12a9.74 9.74 0 0 1 .788-3.9 10.099 10.099 0 0 1 2.137-3.175c.9-.9 1.958-1.612 3.175-2.137A9.737 9.737 0 0 1 12 2a9.74 9.74 0 0 1 3.9.788 10.098 10.098 0 0 1 3.175 2.137c.9.9 1.613 1.958 2.137 3.175A9.738 9.738 0 0 1 22 12a9.738 9.738 0 0 1-.788 3.9 10.098 10.098 0 0 1-2.137 3.175c-.9.9-1.958 1.613-3.175 2.137A9.737 9.737 0 0 1 12 22c-.75 0-1.483-.08-2.2-.238a10.23 10.23 0 0 1-2.1-.712L2.75 22.5a.936.936 0 0 1-1-.25.936.936 0 0 1-.25-1Zm2.45-1.2 3.2-.95a.949.949 0 0 1 .275-.063c.1-.008.192-.012.275-.012.15 0 .296.013.438.038.141.024.279.07.412.137a7.435 7.435 0 0 0 1.675.6c.583.133 1.175.2 1.775.2 2.233 0 4.125-.775 5.675-2.325C19.225 16.125 20 14.233 20 12c0-2.233-.775-4.125-2.325-5.675C16.125 4.775 14.233 4 12 4c-2.233 0-4.125.775-5.675 2.325C4.775 7.875 4 9.767 4 12c0 .6.067 1.192.2 1.775s.333 1.142.6 1.675c.117.217.18.446.188.688a2.29 2.29 0 0 1-.088.712l-.95 3.2Z"
|
||||
/>
|
||||
</svg>
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59"
|
||||
>
|
||||
View your existing messages and data
|
||||
</p>
|
||||
View your existing messages and data
|
||||
</li>
|
||||
<li
|
||||
class="_item_7f22f8"
|
||||
class="_visual-list-item_bqeu7_17"
|
||||
>
|
||||
<svg
|
||||
color="var(--cpd-color-icon-tertiary)"
|
||||
aria-hidden="true"
|
||||
class="_visual-list-item-icon_bqeu7_26"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
height="24px"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
width="24px"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
@@ -176,68 +187,65 @@ exports[`<CompatSessionDetail> > renders a compatability session details 1`] = `
|
||||
fill-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59"
|
||||
>
|
||||
Send new messages on your behalf
|
||||
</p>
|
||||
Send new messages on your behalf
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_block_17898c"
|
||||
</li>
|
||||
</section>
|
||||
<section
|
||||
class="flex flex-col gap-6"
|
||||
>
|
||||
<h4
|
||||
class="_typography_yh5dq_162 _font-heading-sm-semibold_yh5dq_102 _title_17898c"
|
||||
class="_typography_yh5dq_162 _font-heading-sm-semibold_yh5dq_102"
|
||||
>
|
||||
Client info
|
||||
</h4>
|
||||
<div
|
||||
class="_wrapper_040867"
|
||||
>
|
||||
<div
|
||||
class="_datum_040867"
|
||||
class="_separator_144s5_17"
|
||||
data-kind="section"
|
||||
data-orientation="horizontal"
|
||||
role="separator"
|
||||
/>
|
||||
</h4>
|
||||
<ul
|
||||
class="flex flex-wrap gap-x-10 gap-y-6"
|
||||
>
|
||||
<li
|
||||
class="flex flex-col min-w-0"
|
||||
>
|
||||
<h5
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40"
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40 text-secondary"
|
||||
>
|
||||
Name
|
||||
</h5>
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59 _datumValue_040867"
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59 text-ellipsis overflow-hidden"
|
||||
>
|
||||
element.io
|
||||
Unknown device
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
class="_datum_040867"
|
||||
</li>
|
||||
<li
|
||||
class="flex flex-col min-w-0"
|
||||
>
|
||||
<h5
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40"
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40 text-secondary"
|
||||
>
|
||||
Uri
|
||||
</h5>
|
||||
<a
|
||||
class="_link_ue21z_17 _externalLink_a97355"
|
||||
data-kind="primary"
|
||||
data-size="medium"
|
||||
href="https://element.io"
|
||||
rel="noreferrer noopener"
|
||||
target="_blank"
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59 text-ellipsis overflow-hidden"
|
||||
>
|
||||
https://element.io
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
<button
|
||||
aria-controls="radix-:r0:"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="dialog"
|
||||
class="_button_i91xf_17 _has-icon_i91xf_66 _destructive_i91xf_116"
|
||||
data-kind="secondary"
|
||||
data-size="sm"
|
||||
data-size="lg"
|
||||
data-state="closed"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
@@ -252,10 +260,10 @@ exports[`<CompatSessionDetail> > renders a compatability session details 1`] = `
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M9 12.031c0-.283.096-.52.288-.712A.968.968 0 0 1 10 11.03h7.15l-1.875-1.875a.96.96 0 0 1-.3-.7c0-.266.108-.508.325-.725a.93.93 0 0 1 .712-.287.977.977 0 0 1 .688.287l3.6 3.6c.1.1.17.209.212.325.042.117.063.242.063.375 0 .134-.02.259-.063.375a.877.877 0 0 1-.212.325l-3.6 3.6a.93.93 0 0 1-.712.288.977.977 0 0 1-.688-.288 1.02 1.02 0 0 1-.313-.712.931.931 0 0 1 .288-.713l1.875-1.875H10a.968.968 0 0 1-.712-.287A.968.968 0 0 1 9 12.03Zm-6-7c0-.55.196-1.02.588-1.412A1.926 1.926 0 0 1 5 3.03h6a.97.97 0 0 1 .713.288.968.968 0 0 1 .287.712.97.97 0 0 1-.287.713.968.968 0 0 1-.713.287H5v14h6a.97.97 0 0 1 .713.288.968.968 0 0 1 .287.712.97.97 0 0 1-.287.713.968.968 0 0 1-.713.287H5c-.55 0-1.02-.196-1.412-.587A1.926 1.926 0 0 1 3 19.03v-14Z"
|
||||
d="M7 21c-.55 0-1.02-.196-1.412-.587A1.926 1.926 0 0 1 5 19V6a.968.968 0 0 1-.713-.287A.968.968 0 0 1 4 5c0-.283.096-.52.287-.713A.968.968 0 0 1 5 4h4a.97.97 0 0 1 .287-.712A.968.968 0 0 1 10 3h4a.97.97 0 0 1 .713.288A.968.968 0 0 1 15 4h4a.97.97 0 0 1 .712.287c.192.192.288.43.288.713s-.096.52-.288.713A.968.968 0 0 1 19 6v13c0 .55-.196 1.02-.587 1.413A1.926 1.926 0 0 1 17 21H7ZM7 6v13h10V6H7Zm2 10c0 .283.096.52.287.712.192.192.43.288.713.288s.52-.096.713-.288A.968.968 0 0 0 11 16V9a.967.967 0 0 0-.287-.713A.968.968 0 0 0 10 8a.968.968 0 0 0-.713.287A.968.968 0 0 0 9 9v7Zm4 0c0 .283.096.52.287.712.192.192.43.288.713.288s.52-.096.713-.288A.968.968 0 0 0 15 16V9a.967.967 0 0 0-.287-.713A.968.968 0 0 0 14 8a.968.968 0 0 0-.713.287A.967.967 0 0 0 13 9v7Z"
|
||||
/>
|
||||
</svg>
|
||||
Sign out
|
||||
Remove device
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -264,7 +272,7 @@ exports[`<CompatSessionDetail> > renders a compatability session details 1`] = `
|
||||
exports[`<CompatSessionDetail> > renders a compatability session without an ssoLogin 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="_blockList_f8cc7f"
|
||||
class="flex flex-col gap-10"
|
||||
>
|
||||
<header
|
||||
class="_header_92353c"
|
||||
@@ -289,98 +297,115 @@ exports[`<CompatSessionDetail> > renders a compatability session without an ssoL
|
||||
class="_typography_yh5dq_162 _font-heading-md-semibold_yh5dq_121"
|
||||
>
|
||||
abcd1234
|
||||
:
|
||||
Unknown device
|
||||
</h3>
|
||||
</header>
|
||||
<div
|
||||
class="_block_17898c"
|
||||
<section
|
||||
class="flex flex-col gap-6"
|
||||
>
|
||||
<h4
|
||||
class="_typography_yh5dq_162 _font-heading-sm-semibold_yh5dq_102 _title_17898c"
|
||||
>
|
||||
Session
|
||||
</h4>
|
||||
<div
|
||||
class="_wrapper_040867"
|
||||
class="_typography_yh5dq_162 _font-heading-sm-semibold_yh5dq_102"
|
||||
>
|
||||
Device details
|
||||
<div
|
||||
class="_datum_040867"
|
||||
class="_separator_144s5_17"
|
||||
data-kind="section"
|
||||
data-orientation="horizontal"
|
||||
role="separator"
|
||||
/>
|
||||
</h4>
|
||||
<ul
|
||||
class="flex flex-wrap gap-x-10 gap-y-6"
|
||||
>
|
||||
<li
|
||||
class="flex flex-col min-w-0"
|
||||
>
|
||||
<h5
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40"
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40 text-secondary"
|
||||
>
|
||||
Last Active
|
||||
</h5>
|
||||
<span
|
||||
class="_datumValue_040867"
|
||||
title="Sat, 29 Jul 2023, 03:35"
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59 text-ellipsis overflow-hidden"
|
||||
>
|
||||
Inactive for 90+ days
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="_datum_040867"
|
||||
<span
|
||||
title="Sat, 29 Jul 2023, 03:35"
|
||||
>
|
||||
Inactive for 90+ days
|
||||
</span>
|
||||
</p>
|
||||
</li>
|
||||
<li
|
||||
class="flex flex-col min-w-0"
|
||||
>
|
||||
<h5
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40"
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40 text-secondary"
|
||||
>
|
||||
Signed in
|
||||
</h5>
|
||||
<time
|
||||
class="_datumValue_040867"
|
||||
datetime="2023-06-29T03:35:17Z"
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59 text-ellipsis overflow-hidden"
|
||||
>
|
||||
Thu, 29 Jun 2023, 03:35
|
||||
</time>
|
||||
</div>
|
||||
<div
|
||||
class="_datum_040867"
|
||||
<time
|
||||
datetime="2023-06-29T03:35:17Z"
|
||||
>
|
||||
Thu, 29 Jun 2023, 03:35
|
||||
</time>
|
||||
</p>
|
||||
</li>
|
||||
<li
|
||||
class="flex flex-col min-w-0"
|
||||
>
|
||||
<h5
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40"
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40 text-secondary"
|
||||
>
|
||||
Device ID
|
||||
</h5>
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59 _datumValue_040867"
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59 text-ellipsis overflow-hidden"
|
||||
>
|
||||
abcd1234
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
class="_datum_040867"
|
||||
</li>
|
||||
<li
|
||||
class="flex flex-col min-w-0"
|
||||
>
|
||||
<h5
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40"
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40 text-secondary"
|
||||
>
|
||||
IP Address
|
||||
</h5>
|
||||
<code
|
||||
class="_datumValue_040867"
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59 text-ellipsis overflow-hidden"
|
||||
>
|
||||
1.2.3.4
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_datum_040867"
|
||||
<code>
|
||||
1.2.3.4
|
||||
</code>
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
<li
|
||||
class="flex flex-col min-w-0"
|
||||
>
|
||||
<h5
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40"
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40 text-secondary"
|
||||
>
|
||||
Scopes
|
||||
</h5>
|
||||
<ul
|
||||
class="_list_7f22f8"
|
||||
class="_visual-list_4dcf8_17 mt-1"
|
||||
>
|
||||
<li
|
||||
class="_item_7f22f8"
|
||||
class="_visual-list-item_bqeu7_17"
|
||||
>
|
||||
<svg
|
||||
color="var(--cpd-color-icon-tertiary)"
|
||||
aria-hidden="true"
|
||||
class="_visual-list-item-icon_bqeu7_26"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
height="24px"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
width="24px"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
@@ -393,42 +418,36 @@ exports[`<CompatSessionDetail> > renders a compatability session without an ssoL
|
||||
d="M16.23 18.792a12.47 12.47 0 0 0-1.455-.455 11.6 11.6 0 0 0-5.55 0c-.487.12-.972.271-1.455.455a8.04 8.04 0 0 1-1.729-1.454c.89-.412 1.794-.729 2.709-.95A13.76 13.76 0 0 1 12 16c1.1 0 2.183.13 3.25.387a14.78 14.78 0 0 1 2.709.95 8.042 8.042 0 0 1-1.73 1.455Z"
|
||||
/>
|
||||
</svg>
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59"
|
||||
>
|
||||
See your profile info and contact details
|
||||
</p>
|
||||
See your profile info and contact details
|
||||
</li>
|
||||
<li
|
||||
class="_item_7f22f8"
|
||||
class="_visual-list-item_bqeu7_17"
|
||||
>
|
||||
<svg
|
||||
color="var(--cpd-color-icon-tertiary)"
|
||||
aria-hidden="true"
|
||||
class="_visual-list-item-icon_bqeu7_26"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
height="24px"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
width="24px"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="m1.5 21.25 1.45-4.95a10.232 10.232 0 0 1-.712-2.1A10.167 10.167 0 0 1 2 12a9.74 9.74 0 0 1 .788-3.9 10.099 10.099 0 0 1 2.137-3.175c.9-.9 1.958-1.612 3.175-2.137A9.737 9.737 0 0 1 12 2a9.74 9.74 0 0 1 3.9.788 10.098 10.098 0 0 1 3.175 2.137c.9.9 1.613 1.958 2.137 3.175A9.738 9.738 0 0 1 22 12a9.738 9.738 0 0 1-.788 3.9 10.098 10.098 0 0 1-2.137 3.175c-.9.9-1.958 1.613-3.175 2.137A9.737 9.737 0 0 1 12 22c-.75 0-1.483-.08-2.2-.238a10.23 10.23 0 0 1-2.1-.712L2.75 22.5a.936.936 0 0 1-1-.25.936.936 0 0 1-.25-1Zm2.45-1.2 3.2-.95a.949.949 0 0 1 .275-.063c.1-.008.192-.012.275-.012.15 0 .296.013.438.038.141.024.279.07.412.137a7.435 7.435 0 0 0 1.675.6c.583.133 1.175.2 1.775.2 2.233 0 4.125-.775 5.675-2.325C19.225 16.125 20 14.233 20 12c0-2.233-.775-4.125-2.325-5.675C16.125 4.775 14.233 4 12 4c-2.233 0-4.125.775-5.675 2.325C4.775 7.875 4 9.767 4 12c0 .6.067 1.192.2 1.775s.333 1.142.6 1.675c.117.217.18.446.188.688a2.29 2.29 0 0 1-.088.712l-.95 3.2Z"
|
||||
/>
|
||||
</svg>
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59"
|
||||
>
|
||||
View your existing messages and data
|
||||
</p>
|
||||
View your existing messages and data
|
||||
</li>
|
||||
<li
|
||||
class="_item_7f22f8"
|
||||
class="_visual-list-item_bqeu7_17"
|
||||
>
|
||||
<svg
|
||||
color="var(--cpd-color-icon-tertiary)"
|
||||
aria-hidden="true"
|
||||
class="_visual-list-item-icon_bqeu7_26"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
height="24px"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
width="24px"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
@@ -437,22 +456,63 @@ exports[`<CompatSessionDetail> > renders a compatability session without an ssoL
|
||||
fill-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59"
|
||||
>
|
||||
Send new messages on your behalf
|
||||
</p>
|
||||
Send new messages on your behalf
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</section>
|
||||
<section
|
||||
class="flex flex-col gap-6"
|
||||
>
|
||||
<h4
|
||||
class="_typography_yh5dq_162 _font-heading-sm-semibold_yh5dq_102"
|
||||
>
|
||||
Client info
|
||||
<div
|
||||
class="_separator_144s5_17"
|
||||
data-kind="section"
|
||||
data-orientation="horizontal"
|
||||
role="separator"
|
||||
/>
|
||||
</h4>
|
||||
<ul
|
||||
class="flex flex-wrap gap-x-10 gap-y-6"
|
||||
>
|
||||
<li
|
||||
class="flex flex-col min-w-0"
|
||||
>
|
||||
<h5
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40 text-secondary"
|
||||
>
|
||||
Name
|
||||
</h5>
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59 text-ellipsis overflow-hidden"
|
||||
>
|
||||
Unknown device
|
||||
</p>
|
||||
</li>
|
||||
<li
|
||||
class="flex flex-col min-w-0"
|
||||
>
|
||||
<h5
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40 text-secondary"
|
||||
>
|
||||
Uri
|
||||
</h5>
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59 text-ellipsis overflow-hidden"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
<button
|
||||
aria-controls="radix-:r3:"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="dialog"
|
||||
class="_button_i91xf_17 _has-icon_i91xf_66 _destructive_i91xf_116"
|
||||
data-kind="secondary"
|
||||
data-size="sm"
|
||||
data-size="lg"
|
||||
data-state="closed"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
@@ -467,10 +527,10 @@ exports[`<CompatSessionDetail> > renders a compatability session without an ssoL
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M9 12.031c0-.283.096-.52.288-.712A.968.968 0 0 1 10 11.03h7.15l-1.875-1.875a.96.96 0 0 1-.3-.7c0-.266.108-.508.325-.725a.93.93 0 0 1 .712-.287.977.977 0 0 1 .688.287l3.6 3.6c.1.1.17.209.212.325.042.117.063.242.063.375 0 .134-.02.259-.063.375a.877.877 0 0 1-.212.325l-3.6 3.6a.93.93 0 0 1-.712.288.977.977 0 0 1-.688-.288 1.02 1.02 0 0 1-.313-.712.931.931 0 0 1 .288-.713l1.875-1.875H10a.968.968 0 0 1-.712-.287A.968.968 0 0 1 9 12.03Zm-6-7c0-.55.196-1.02.588-1.412A1.926 1.926 0 0 1 5 3.03h6a.97.97 0 0 1 .713.288.968.968 0 0 1 .287.712.97.97 0 0 1-.287.713.968.968 0 0 1-.713.287H5v14h6a.97.97 0 0 1 .713.288.968.968 0 0 1 .287.712.97.97 0 0 1-.287.713.968.968 0 0 1-.713.287H5c-.55 0-1.02-.196-1.412-.587A1.926 1.926 0 0 1 3 19.03v-14Z"
|
||||
d="M7 21c-.55 0-1.02-.196-1.412-.587A1.926 1.926 0 0 1 5 19V6a.968.968 0 0 1-.713-.287A.968.968 0 0 1 4 5c0-.283.096-.52.287-.713A.968.968 0 0 1 5 4h4a.97.97 0 0 1 .287-.712A.968.968 0 0 1 10 3h4a.97.97 0 0 1 .713.288A.968.968 0 0 1 15 4h4a.97.97 0 0 1 .712.287c.192.192.288.43.288.713s-.096.52-.288.713A.968.968 0 0 1 19 6v13c0 .55-.196 1.02-.587 1.413A1.926 1.926 0 0 1 17 21H7ZM7 6v13h10V6H7Zm2 10c0 .283.096.52.287.712.192.192.43.288.713.288s.52-.096.713-.288A.968.968 0 0 0 11 16V9a.967.967 0 0 0-.287-.713A.968.968 0 0 0 10 8a.968.968 0 0 0-.713.287A.968.968 0 0 0 9 9v7Zm4 0c0 .283.096.52.287.712.192.192.43.288.713.288s.52-.096.713-.288A.968.968 0 0 0 15 16V9a.967.967 0 0 0-.287-.713A.968.968 0 0 0 14 8a.968.968 0 0 0-.713.287A.967.967 0 0 0 13 9v7Z"
|
||||
/>
|
||||
</svg>
|
||||
Sign out
|
||||
Remove device
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -479,7 +539,7 @@ exports[`<CompatSessionDetail> > renders a compatability session without an ssoL
|
||||
exports[`<CompatSessionDetail> > renders a finished compatability session details 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="_blockList_f8cc7f"
|
||||
class="flex flex-col gap-10"
|
||||
>
|
||||
<header
|
||||
class="_header_92353c"
|
||||
@@ -503,113 +563,134 @@ exports[`<CompatSessionDetail> > renders a finished compatability session detail
|
||||
<h3
|
||||
class="_typography_yh5dq_162 _font-heading-md-semibold_yh5dq_121"
|
||||
>
|
||||
abcd1234
|
||||
element.io
|
||||
:
|
||||
Unknown device
|
||||
</h3>
|
||||
</header>
|
||||
<div
|
||||
class="_block_17898c"
|
||||
<section
|
||||
class="flex flex-col gap-6"
|
||||
>
|
||||
<h4
|
||||
class="_typography_yh5dq_162 _font-heading-sm-semibold_yh5dq_102 _title_17898c"
|
||||
>
|
||||
Session
|
||||
</h4>
|
||||
<div
|
||||
class="_wrapper_040867"
|
||||
class="_typography_yh5dq_162 _font-heading-sm-semibold_yh5dq_102"
|
||||
>
|
||||
Device details
|
||||
<div
|
||||
class="_datum_040867"
|
||||
class="_separator_144s5_17"
|
||||
data-kind="section"
|
||||
data-orientation="horizontal"
|
||||
role="separator"
|
||||
/>
|
||||
</h4>
|
||||
<ul
|
||||
class="flex flex-wrap gap-x-10 gap-y-6"
|
||||
>
|
||||
<li
|
||||
class="flex flex-col min-w-0"
|
||||
>
|
||||
<h5
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40"
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40 text-secondary"
|
||||
>
|
||||
Last Active
|
||||
</h5>
|
||||
<span
|
||||
class="_datumValue_040867"
|
||||
title="Sat, 29 Jul 2023, 03:35"
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59 text-ellipsis overflow-hidden"
|
||||
>
|
||||
Inactive for 90+ days
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="_datum_040867"
|
||||
<span
|
||||
title="Sat, 29 Jul 2023, 03:35"
|
||||
>
|
||||
Inactive for 90+ days
|
||||
</span>
|
||||
</p>
|
||||
</li>
|
||||
<li
|
||||
class="flex flex-col min-w-0"
|
||||
>
|
||||
<h5
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40"
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40 text-secondary"
|
||||
>
|
||||
Signed in
|
||||
</h5>
|
||||
<time
|
||||
class="_datumValue_040867"
|
||||
datetime="2023-06-29T03:35:17Z"
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59 text-ellipsis overflow-hidden"
|
||||
>
|
||||
Thu, 29 Jun 2023, 03:35
|
||||
</time>
|
||||
</div>
|
||||
<div
|
||||
class="_datum_040867"
|
||||
<time
|
||||
datetime="2023-06-29T03:35:17Z"
|
||||
>
|
||||
Thu, 29 Jun 2023, 03:35
|
||||
</time>
|
||||
</p>
|
||||
</li>
|
||||
<li
|
||||
class="flex flex-col min-w-0"
|
||||
>
|
||||
<h5
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40"
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40 text-secondary"
|
||||
>
|
||||
Finished
|
||||
</h5>
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59 text-ellipsis overflow-hidden"
|
||||
>
|
||||
<time
|
||||
datetime="2023-07-29T03:35:17Z"
|
||||
>
|
||||
Sat, 29 Jul 2023, 03:35
|
||||
</time>
|
||||
</p>
|
||||
</li>
|
||||
<li
|
||||
class="flex flex-col min-w-0"
|
||||
>
|
||||
<h5
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40 text-secondary"
|
||||
>
|
||||
Device ID
|
||||
</h5>
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59 _datumValue_040867"
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59 text-ellipsis overflow-hidden"
|
||||
>
|
||||
abcd1234
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
class="_datum_040867"
|
||||
</li>
|
||||
<li
|
||||
class="flex flex-col min-w-0"
|
||||
>
|
||||
<h5
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40"
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40 text-secondary"
|
||||
>
|
||||
IP Address
|
||||
</h5>
|
||||
<code
|
||||
class="_datumValue_040867"
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59 text-ellipsis overflow-hidden"
|
||||
>
|
||||
1.2.3.4
|
||||
</code>
|
||||
</div>
|
||||
<div
|
||||
class="_datum_040867"
|
||||
>
|
||||
<h5
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40"
|
||||
>
|
||||
Finished
|
||||
</h5>
|
||||
<time
|
||||
datetime="2023-07-29T03:35:17Z"
|
||||
>
|
||||
Sat, 29 Jul 2023, 03:35
|
||||
</time>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_datum_040867"
|
||||
<code>
|
||||
1.2.3.4
|
||||
</code>
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
<li
|
||||
class="flex flex-col min-w-0"
|
||||
>
|
||||
<h5
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40"
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40 text-secondary"
|
||||
>
|
||||
Scopes
|
||||
</h5>
|
||||
<ul
|
||||
class="_list_7f22f8"
|
||||
class="_visual-list_4dcf8_17 mt-1"
|
||||
>
|
||||
<li
|
||||
class="_item_7f22f8"
|
||||
class="_visual-list-item_bqeu7_17"
|
||||
>
|
||||
<svg
|
||||
color="var(--cpd-color-icon-tertiary)"
|
||||
aria-hidden="true"
|
||||
class="_visual-list-item-icon_bqeu7_26"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
height="24px"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
width="24px"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
@@ -622,42 +703,36 @@ exports[`<CompatSessionDetail> > renders a finished compatability session detail
|
||||
d="M16.23 18.792a12.47 12.47 0 0 0-1.455-.455 11.6 11.6 0 0 0-5.55 0c-.487.12-.972.271-1.455.455a8.04 8.04 0 0 1-1.729-1.454c.89-.412 1.794-.729 2.709-.95A13.76 13.76 0 0 1 12 16c1.1 0 2.183.13 3.25.387a14.78 14.78 0 0 1 2.709.95 8.042 8.042 0 0 1-1.73 1.455Z"
|
||||
/>
|
||||
</svg>
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59"
|
||||
>
|
||||
See your profile info and contact details
|
||||
</p>
|
||||
See your profile info and contact details
|
||||
</li>
|
||||
<li
|
||||
class="_item_7f22f8"
|
||||
class="_visual-list-item_bqeu7_17"
|
||||
>
|
||||
<svg
|
||||
color="var(--cpd-color-icon-tertiary)"
|
||||
aria-hidden="true"
|
||||
class="_visual-list-item-icon_bqeu7_26"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
height="24px"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
width="24px"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="m1.5 21.25 1.45-4.95a10.232 10.232 0 0 1-.712-2.1A10.167 10.167 0 0 1 2 12a9.74 9.74 0 0 1 .788-3.9 10.099 10.099 0 0 1 2.137-3.175c.9-.9 1.958-1.612 3.175-2.137A9.737 9.737 0 0 1 12 2a9.74 9.74 0 0 1 3.9.788 10.098 10.098 0 0 1 3.175 2.137c.9.9 1.613 1.958 2.137 3.175A9.738 9.738 0 0 1 22 12a9.738 9.738 0 0 1-.788 3.9 10.098 10.098 0 0 1-2.137 3.175c-.9.9-1.958 1.613-3.175 2.137A9.737 9.737 0 0 1 12 22c-.75 0-1.483-.08-2.2-.238a10.23 10.23 0 0 1-2.1-.712L2.75 22.5a.936.936 0 0 1-1-.25.936.936 0 0 1-.25-1Zm2.45-1.2 3.2-.95a.949.949 0 0 1 .275-.063c.1-.008.192-.012.275-.012.15 0 .296.013.438.038.141.024.279.07.412.137a7.435 7.435 0 0 0 1.675.6c.583.133 1.175.2 1.775.2 2.233 0 4.125-.775 5.675-2.325C19.225 16.125 20 14.233 20 12c0-2.233-.775-4.125-2.325-5.675C16.125 4.775 14.233 4 12 4c-2.233 0-4.125.775-5.675 2.325C4.775 7.875 4 9.767 4 12c0 .6.067 1.192.2 1.775s.333 1.142.6 1.675c.117.217.18.446.188.688a2.29 2.29 0 0 1-.088.712l-.95 3.2Z"
|
||||
/>
|
||||
</svg>
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59"
|
||||
>
|
||||
View your existing messages and data
|
||||
</p>
|
||||
View your existing messages and data
|
||||
</li>
|
||||
<li
|
||||
class="_item_7f22f8"
|
||||
class="_visual-list-item_bqeu7_17"
|
||||
>
|
||||
<svg
|
||||
color="var(--cpd-color-icon-tertiary)"
|
||||
aria-hidden="true"
|
||||
class="_visual-list-item-icon_bqeu7_26"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
height="24px"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
width="24px"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
@@ -666,61 +741,58 @@ exports[`<CompatSessionDetail> > renders a finished compatability session detail
|
||||
fill-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59"
|
||||
>
|
||||
Send new messages on your behalf
|
||||
</p>
|
||||
Send new messages on your behalf
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_block_17898c"
|
||||
</li>
|
||||
</section>
|
||||
<section
|
||||
class="flex flex-col gap-6"
|
||||
>
|
||||
<h4
|
||||
class="_typography_yh5dq_162 _font-heading-sm-semibold_yh5dq_102 _title_17898c"
|
||||
class="_typography_yh5dq_162 _font-heading-sm-semibold_yh5dq_102"
|
||||
>
|
||||
Client info
|
||||
</h4>
|
||||
<div
|
||||
class="_wrapper_040867"
|
||||
>
|
||||
<div
|
||||
class="_datum_040867"
|
||||
class="_separator_144s5_17"
|
||||
data-kind="section"
|
||||
data-orientation="horizontal"
|
||||
role="separator"
|
||||
/>
|
||||
</h4>
|
||||
<ul
|
||||
class="flex flex-wrap gap-x-10 gap-y-6"
|
||||
>
|
||||
<li
|
||||
class="flex flex-col min-w-0"
|
||||
>
|
||||
<h5
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40"
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40 text-secondary"
|
||||
>
|
||||
Name
|
||||
</h5>
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59 _datumValue_040867"
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59 text-ellipsis overflow-hidden"
|
||||
>
|
||||
element.io
|
||||
Unknown device
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
class="_datum_040867"
|
||||
</li>
|
||||
<li
|
||||
class="flex flex-col min-w-0"
|
||||
>
|
||||
<h5
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40"
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40 text-secondary"
|
||||
>
|
||||
Uri
|
||||
</h5>
|
||||
<a
|
||||
class="_link_ue21z_17 _externalLink_a97355"
|
||||
data-kind="primary"
|
||||
data-size="medium"
|
||||
href="https://element.io"
|
||||
rel="noreferrer noopener"
|
||||
target="_blank"
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59 text-ellipsis overflow-hidden"
|
||||
>
|
||||
https://element.io
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
exports[`<OAuth2SessionDetail> > renders a finished session details 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="_blockList_f8cc7f"
|
||||
class="flex flex-col gap-10"
|
||||
>
|
||||
<header
|
||||
class="_header_92353c"
|
||||
@@ -27,113 +27,132 @@ exports[`<OAuth2SessionDetail> > renders a finished session details 1`] = `
|
||||
<h3
|
||||
class="_typography_yh5dq_162 _font-heading-md-semibold_yh5dq_121"
|
||||
>
|
||||
abcd1234
|
||||
Element: Unknown device
|
||||
</h3>
|
||||
</header>
|
||||
<div
|
||||
class="_block_17898c"
|
||||
<section
|
||||
class="flex flex-col gap-6"
|
||||
>
|
||||
<h4
|
||||
class="_typography_yh5dq_162 _font-heading-sm-semibold_yh5dq_102 _title_17898c"
|
||||
class="_typography_yh5dq_162 _font-heading-sm-semibold_yh5dq_102"
|
||||
>
|
||||
Device details
|
||||
</h4>
|
||||
<div
|
||||
class="_wrapper_040867"
|
||||
>
|
||||
<div
|
||||
class="_datum_040867"
|
||||
class="_separator_144s5_17"
|
||||
data-kind="section"
|
||||
data-orientation="horizontal"
|
||||
role="separator"
|
||||
/>
|
||||
</h4>
|
||||
<ul
|
||||
class="flex flex-wrap gap-x-10 gap-y-6"
|
||||
>
|
||||
<li
|
||||
class="flex flex-col min-w-0"
|
||||
>
|
||||
<h5
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40"
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40 text-secondary"
|
||||
>
|
||||
Last Active
|
||||
</h5>
|
||||
<span
|
||||
class="_datumValue_040867"
|
||||
title="Sat, 29 Jul 2023, 03:35"
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59 text-ellipsis overflow-hidden"
|
||||
>
|
||||
Inactive for 90+ days
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="_datum_040867"
|
||||
<span
|
||||
title="Sat, 29 Jul 2023, 03:35"
|
||||
>
|
||||
Inactive for 90+ days
|
||||
</span>
|
||||
</p>
|
||||
</li>
|
||||
<li
|
||||
class="flex flex-col min-w-0"
|
||||
>
|
||||
<h5
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40"
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40 text-secondary"
|
||||
>
|
||||
Signed in
|
||||
</h5>
|
||||
<time
|
||||
class="_datumValue_040867"
|
||||
datetime="2023-06-29T03:35:17Z"
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59 text-ellipsis overflow-hidden"
|
||||
>
|
||||
Thu, 29 Jun 2023, 03:35
|
||||
</time>
|
||||
</div>
|
||||
<div
|
||||
class="_datum_040867"
|
||||
<time
|
||||
datetime="2023-06-29T03:35:17Z"
|
||||
>
|
||||
Thu, 29 Jun 2023, 03:35
|
||||
</time>
|
||||
</p>
|
||||
</li>
|
||||
<li
|
||||
class="flex flex-col min-w-0"
|
||||
>
|
||||
<h5
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40"
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40 text-secondary"
|
||||
>
|
||||
Finished
|
||||
</h5>
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59 text-ellipsis overflow-hidden"
|
||||
>
|
||||
<time
|
||||
datetime="2023-07-29T03:35:17Z"
|
||||
>
|
||||
Sat, 29 Jul 2023, 03:35
|
||||
</time>
|
||||
</p>
|
||||
</li>
|
||||
<li
|
||||
class="flex flex-col min-w-0"
|
||||
>
|
||||
<h5
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40 text-secondary"
|
||||
>
|
||||
Device ID
|
||||
</h5>
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59 _datumValue_040867"
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59 text-ellipsis overflow-hidden"
|
||||
>
|
||||
abcd1234
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
class="_datum_040867"
|
||||
</li>
|
||||
<li
|
||||
class="flex flex-col min-w-0"
|
||||
>
|
||||
<h5
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40"
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40 text-secondary"
|
||||
>
|
||||
IP Address
|
||||
</h5>
|
||||
<code
|
||||
class="_datumValue_040867"
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59 text-ellipsis overflow-hidden"
|
||||
>
|
||||
1.2.3.4
|
||||
</code>
|
||||
</div>
|
||||
<div
|
||||
class="_datum_040867"
|
||||
>
|
||||
<h5
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40"
|
||||
>
|
||||
Finished
|
||||
</h5>
|
||||
<time
|
||||
datetime="2023-07-29T03:35:17Z"
|
||||
>
|
||||
Sat, 29 Jul 2023, 03:35
|
||||
</time>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_datum_040867"
|
||||
<code>
|
||||
1.2.3.4
|
||||
</code>
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
<li
|
||||
class="flex flex-col min-w-0"
|
||||
>
|
||||
<h5
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40"
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40 text-secondary"
|
||||
>
|
||||
Scopes
|
||||
</h5>
|
||||
<ul
|
||||
class="_list_7f22f8"
|
||||
class="_visual-list_4dcf8_17 mt-1"
|
||||
>
|
||||
<li
|
||||
class="_item_7f22f8"
|
||||
class="_visual-list-item_bqeu7_17"
|
||||
>
|
||||
<svg
|
||||
color="var(--cpd-color-icon-tertiary)"
|
||||
aria-hidden="true"
|
||||
class="_visual-list-item-icon_bqeu7_26"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
height="24px"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
width="24px"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
@@ -146,42 +165,36 @@ exports[`<OAuth2SessionDetail> > renders a finished session details 1`] = `
|
||||
d="M16.23 18.792a12.47 12.47 0 0 0-1.455-.455 11.6 11.6 0 0 0-5.55 0c-.487.12-.972.271-1.455.455a8.04 8.04 0 0 1-1.729-1.454c.89-.412 1.794-.729 2.709-.95A13.76 13.76 0 0 1 12 16c1.1 0 2.183.13 3.25.387a14.78 14.78 0 0 1 2.709.95 8.042 8.042 0 0 1-1.73 1.455Z"
|
||||
/>
|
||||
</svg>
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59"
|
||||
>
|
||||
See your profile info and contact details
|
||||
</p>
|
||||
See your profile info and contact details
|
||||
</li>
|
||||
<li
|
||||
class="_item_7f22f8"
|
||||
class="_visual-list-item_bqeu7_17"
|
||||
>
|
||||
<svg
|
||||
color="var(--cpd-color-icon-tertiary)"
|
||||
aria-hidden="true"
|
||||
class="_visual-list-item-icon_bqeu7_26"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
height="24px"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
width="24px"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="m1.5 21.25 1.45-4.95a10.232 10.232 0 0 1-.712-2.1A10.167 10.167 0 0 1 2 12a9.74 9.74 0 0 1 .788-3.9 10.099 10.099 0 0 1 2.137-3.175c.9-.9 1.958-1.612 3.175-2.137A9.737 9.737 0 0 1 12 2a9.74 9.74 0 0 1 3.9.788 10.098 10.098 0 0 1 3.175 2.137c.9.9 1.613 1.958 2.137 3.175A9.738 9.738 0 0 1 22 12a9.738 9.738 0 0 1-.788 3.9 10.098 10.098 0 0 1-2.137 3.175c-.9.9-1.958 1.613-3.175 2.137A9.737 9.737 0 0 1 12 22c-.75 0-1.483-.08-2.2-.238a10.23 10.23 0 0 1-2.1-.712L2.75 22.5a.936.936 0 0 1-1-.25.936.936 0 0 1-.25-1Zm2.45-1.2 3.2-.95a.949.949 0 0 1 .275-.063c.1-.008.192-.012.275-.012.15 0 .296.013.438.038.141.024.279.07.412.137a7.435 7.435 0 0 0 1.675.6c.583.133 1.175.2 1.775.2 2.233 0 4.125-.775 5.675-2.325C19.225 16.125 20 14.233 20 12c0-2.233-.775-4.125-2.325-5.675C16.125 4.775 14.233 4 12 4c-2.233 0-4.125.775-5.675 2.325C4.775 7.875 4 9.767 4 12c0 .6.067 1.192.2 1.775s.333 1.142.6 1.675c.117.217.18.446.188.688a2.29 2.29 0 0 1-.088.712l-.95 3.2Z"
|
||||
/>
|
||||
</svg>
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59"
|
||||
>
|
||||
View your existing messages and data
|
||||
</p>
|
||||
View your existing messages and data
|
||||
</li>
|
||||
<li
|
||||
class="_item_7f22f8"
|
||||
class="_visual-list-item_bqeu7_17"
|
||||
>
|
||||
<svg
|
||||
color="var(--cpd-color-icon-tertiary)"
|
||||
aria-hidden="true"
|
||||
class="_visual-list-item-icon_bqeu7_26"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
height="24px"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
width="24px"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
@@ -190,74 +203,80 @@ exports[`<OAuth2SessionDetail> > renders a finished session details 1`] = `
|
||||
fill-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59"
|
||||
>
|
||||
Send new messages on your behalf
|
||||
</p>
|
||||
Send new messages on your behalf
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_block_17898c"
|
||||
</li>
|
||||
</section>
|
||||
<section
|
||||
class="flex flex-col gap-6"
|
||||
>
|
||||
<h4
|
||||
class="_typography_yh5dq_162 _font-heading-sm-semibold_yh5dq_102 _title_17898c"
|
||||
>
|
||||
<a
|
||||
class="_link_ue21z_17"
|
||||
data-kind="primary"
|
||||
data-size="medium"
|
||||
href="/clients/test-id"
|
||||
rel="noreferrer noopener"
|
||||
>
|
||||
Client info
|
||||
</a>
|
||||
</h4>
|
||||
<div
|
||||
class="_wrapper_040867"
|
||||
class="_typography_yh5dq_162 _font-heading-sm-semibold_yh5dq_102"
|
||||
>
|
||||
Client info
|
||||
<div
|
||||
class="_datum_040867"
|
||||
class="_separator_144s5_17"
|
||||
data-kind="section"
|
||||
data-orientation="horizontal"
|
||||
role="separator"
|
||||
/>
|
||||
</h4>
|
||||
<ul
|
||||
class="flex flex-wrap gap-x-10 gap-y-6"
|
||||
>
|
||||
<li
|
||||
class="flex flex-col min-w-0"
|
||||
>
|
||||
<h5
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40"
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40 text-secondary"
|
||||
>
|
||||
Name
|
||||
</h5>
|
||||
Element
|
||||
</div>
|
||||
<div
|
||||
class="_datum_040867"
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59 text-ellipsis overflow-hidden"
|
||||
>
|
||||
Element
|
||||
</p>
|
||||
</li>
|
||||
<li
|
||||
class="flex flex-col min-w-0"
|
||||
>
|
||||
<h5
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40"
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40 text-secondary"
|
||||
>
|
||||
Client ID
|
||||
</h5>
|
||||
<code>
|
||||
test-client-id
|
||||
</code>
|
||||
</div>
|
||||
<div
|
||||
class="_datum_040867"
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59 text-ellipsis overflow-hidden"
|
||||
>
|
||||
<code>
|
||||
test-client-id
|
||||
</code>
|
||||
</p>
|
||||
</li>
|
||||
<li
|
||||
class="flex flex-col min-w-0"
|
||||
>
|
||||
<h5
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40"
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40 text-secondary"
|
||||
>
|
||||
Uri
|
||||
</h5>
|
||||
<a
|
||||
href="https://element.io"
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59 text-ellipsis overflow-hidden"
|
||||
>
|
||||
https://element.io
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a
|
||||
href="https://element.io"
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
https://element.io
|
||||
</a>
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
@@ -265,7 +284,7 @@ exports[`<OAuth2SessionDetail> > renders a finished session details 1`] = `
|
||||
exports[`<OAuth2SessionDetail> > renders session details 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="_blockList_f8cc7f"
|
||||
class="flex flex-col gap-10"
|
||||
>
|
||||
<header
|
||||
class="_header_92353c"
|
||||
@@ -289,99 +308,114 @@ exports[`<OAuth2SessionDetail> > renders session details 1`] = `
|
||||
<h3
|
||||
class="_typography_yh5dq_162 _font-heading-md-semibold_yh5dq_121"
|
||||
>
|
||||
abcd1234
|
||||
Element: Unknown device
|
||||
</h3>
|
||||
</header>
|
||||
<div
|
||||
class="_block_17898c"
|
||||
<section
|
||||
class="flex flex-col gap-6"
|
||||
>
|
||||
<h4
|
||||
class="_typography_yh5dq_162 _font-heading-sm-semibold_yh5dq_102 _title_17898c"
|
||||
class="_typography_yh5dq_162 _font-heading-sm-semibold_yh5dq_102"
|
||||
>
|
||||
Device details
|
||||
</h4>
|
||||
<div
|
||||
class="_wrapper_040867"
|
||||
>
|
||||
<div
|
||||
class="_datum_040867"
|
||||
class="_separator_144s5_17"
|
||||
data-kind="section"
|
||||
data-orientation="horizontal"
|
||||
role="separator"
|
||||
/>
|
||||
</h4>
|
||||
<ul
|
||||
class="flex flex-wrap gap-x-10 gap-y-6"
|
||||
>
|
||||
<li
|
||||
class="flex flex-col min-w-0"
|
||||
>
|
||||
<h5
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40"
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40 text-secondary"
|
||||
>
|
||||
Last Active
|
||||
</h5>
|
||||
<span
|
||||
class="_datumValue_040867"
|
||||
title="Sat, 29 Jul 2023, 03:35"
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59 text-ellipsis overflow-hidden"
|
||||
>
|
||||
Inactive for 90+ days
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="_datum_040867"
|
||||
<span
|
||||
title="Sat, 29 Jul 2023, 03:35"
|
||||
>
|
||||
Inactive for 90+ days
|
||||
</span>
|
||||
</p>
|
||||
</li>
|
||||
<li
|
||||
class="flex flex-col min-w-0"
|
||||
>
|
||||
<h5
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40"
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40 text-secondary"
|
||||
>
|
||||
Signed in
|
||||
</h5>
|
||||
<time
|
||||
class="_datumValue_040867"
|
||||
datetime="2023-06-29T03:35:17Z"
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59 text-ellipsis overflow-hidden"
|
||||
>
|
||||
Thu, 29 Jun 2023, 03:35
|
||||
</time>
|
||||
</div>
|
||||
<div
|
||||
class="_datum_040867"
|
||||
<time
|
||||
datetime="2023-06-29T03:35:17Z"
|
||||
>
|
||||
Thu, 29 Jun 2023, 03:35
|
||||
</time>
|
||||
</p>
|
||||
</li>
|
||||
<li
|
||||
class="flex flex-col min-w-0"
|
||||
>
|
||||
<h5
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40"
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40 text-secondary"
|
||||
>
|
||||
Device ID
|
||||
</h5>
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59 _datumValue_040867"
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59 text-ellipsis overflow-hidden"
|
||||
>
|
||||
abcd1234
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
class="_datum_040867"
|
||||
</li>
|
||||
<li
|
||||
class="flex flex-col min-w-0"
|
||||
>
|
||||
<h5
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40"
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40 text-secondary"
|
||||
>
|
||||
IP Address
|
||||
</h5>
|
||||
<code
|
||||
class="_datumValue_040867"
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59 text-ellipsis overflow-hidden"
|
||||
>
|
||||
1.2.3.4
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_datum_040867"
|
||||
<code>
|
||||
1.2.3.4
|
||||
</code>
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
<li
|
||||
class="flex flex-col min-w-0"
|
||||
>
|
||||
<h5
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40"
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40 text-secondary"
|
||||
>
|
||||
Scopes
|
||||
</h5>
|
||||
<ul
|
||||
class="_list_7f22f8"
|
||||
class="_visual-list_4dcf8_17 mt-1"
|
||||
>
|
||||
<li
|
||||
class="_item_7f22f8"
|
||||
class="_visual-list-item_bqeu7_17"
|
||||
>
|
||||
<svg
|
||||
color="var(--cpd-color-icon-tertiary)"
|
||||
aria-hidden="true"
|
||||
class="_visual-list-item-icon_bqeu7_26"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
height="24px"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
width="24px"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
@@ -394,42 +428,36 @@ exports[`<OAuth2SessionDetail> > renders session details 1`] = `
|
||||
d="M16.23 18.792a12.47 12.47 0 0 0-1.455-.455 11.6 11.6 0 0 0-5.55 0c-.487.12-.972.271-1.455.455a8.04 8.04 0 0 1-1.729-1.454c.89-.412 1.794-.729 2.709-.95A13.76 13.76 0 0 1 12 16c1.1 0 2.183.13 3.25.387a14.78 14.78 0 0 1 2.709.95 8.042 8.042 0 0 1-1.73 1.455Z"
|
||||
/>
|
||||
</svg>
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59"
|
||||
>
|
||||
See your profile info and contact details
|
||||
</p>
|
||||
See your profile info and contact details
|
||||
</li>
|
||||
<li
|
||||
class="_item_7f22f8"
|
||||
class="_visual-list-item_bqeu7_17"
|
||||
>
|
||||
<svg
|
||||
color="var(--cpd-color-icon-tertiary)"
|
||||
aria-hidden="true"
|
||||
class="_visual-list-item-icon_bqeu7_26"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
height="24px"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
width="24px"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="m1.5 21.25 1.45-4.95a10.232 10.232 0 0 1-.712-2.1A10.167 10.167 0 0 1 2 12a9.74 9.74 0 0 1 .788-3.9 10.099 10.099 0 0 1 2.137-3.175c.9-.9 1.958-1.612 3.175-2.137A9.737 9.737 0 0 1 12 2a9.74 9.74 0 0 1 3.9.788 10.098 10.098 0 0 1 3.175 2.137c.9.9 1.613 1.958 2.137 3.175A9.738 9.738 0 0 1 22 12a9.738 9.738 0 0 1-.788 3.9 10.098 10.098 0 0 1-2.137 3.175c-.9.9-1.958 1.613-3.175 2.137A9.737 9.737 0 0 1 12 22c-.75 0-1.483-.08-2.2-.238a10.23 10.23 0 0 1-2.1-.712L2.75 22.5a.936.936 0 0 1-1-.25.936.936 0 0 1-.25-1Zm2.45-1.2 3.2-.95a.949.949 0 0 1 .275-.063c.1-.008.192-.012.275-.012.15 0 .296.013.438.038.141.024.279.07.412.137a7.435 7.435 0 0 0 1.675.6c.583.133 1.175.2 1.775.2 2.233 0 4.125-.775 5.675-2.325C19.225 16.125 20 14.233 20 12c0-2.233-.775-4.125-2.325-5.675C16.125 4.775 14.233 4 12 4c-2.233 0-4.125.775-5.675 2.325C4.775 7.875 4 9.767 4 12c0 .6.067 1.192.2 1.775s.333 1.142.6 1.675c.117.217.18.446.188.688a2.29 2.29 0 0 1-.088.712l-.95 3.2Z"
|
||||
/>
|
||||
</svg>
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59"
|
||||
>
|
||||
View your existing messages and data
|
||||
</p>
|
||||
View your existing messages and data
|
||||
</li>
|
||||
<li
|
||||
class="_item_7f22f8"
|
||||
class="_visual-list-item_bqeu7_17"
|
||||
>
|
||||
<svg
|
||||
color="var(--cpd-color-icon-tertiary)"
|
||||
aria-hidden="true"
|
||||
class="_visual-list-item-icon_bqeu7_26"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
height="24px"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
width="24px"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
@@ -438,81 +466,87 @@ exports[`<OAuth2SessionDetail> > renders session details 1`] = `
|
||||
fill-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59"
|
||||
>
|
||||
Send new messages on your behalf
|
||||
</p>
|
||||
Send new messages on your behalf
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_block_17898c"
|
||||
</li>
|
||||
</section>
|
||||
<section
|
||||
class="flex flex-col gap-6"
|
||||
>
|
||||
<h4
|
||||
class="_typography_yh5dq_162 _font-heading-sm-semibold_yh5dq_102 _title_17898c"
|
||||
>
|
||||
<a
|
||||
class="_link_ue21z_17"
|
||||
data-kind="primary"
|
||||
data-size="medium"
|
||||
href="/clients/test-id"
|
||||
rel="noreferrer noopener"
|
||||
>
|
||||
Client info
|
||||
</a>
|
||||
</h4>
|
||||
<div
|
||||
class="_wrapper_040867"
|
||||
class="_typography_yh5dq_162 _font-heading-sm-semibold_yh5dq_102"
|
||||
>
|
||||
Client info
|
||||
<div
|
||||
class="_datum_040867"
|
||||
class="_separator_144s5_17"
|
||||
data-kind="section"
|
||||
data-orientation="horizontal"
|
||||
role="separator"
|
||||
/>
|
||||
</h4>
|
||||
<ul
|
||||
class="flex flex-wrap gap-x-10 gap-y-6"
|
||||
>
|
||||
<li
|
||||
class="flex flex-col min-w-0"
|
||||
>
|
||||
<h5
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40"
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40 text-secondary"
|
||||
>
|
||||
Name
|
||||
</h5>
|
||||
Element
|
||||
</div>
|
||||
<div
|
||||
class="_datum_040867"
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59 text-ellipsis overflow-hidden"
|
||||
>
|
||||
Element
|
||||
</p>
|
||||
</li>
|
||||
<li
|
||||
class="flex flex-col min-w-0"
|
||||
>
|
||||
<h5
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40"
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40 text-secondary"
|
||||
>
|
||||
Client ID
|
||||
</h5>
|
||||
<code>
|
||||
test-client-id
|
||||
</code>
|
||||
</div>
|
||||
<div
|
||||
class="_datum_040867"
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59 text-ellipsis overflow-hidden"
|
||||
>
|
||||
<code>
|
||||
test-client-id
|
||||
</code>
|
||||
</p>
|
||||
</li>
|
||||
<li
|
||||
class="flex flex-col min-w-0"
|
||||
>
|
||||
<h5
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40"
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40 text-secondary"
|
||||
>
|
||||
Uri
|
||||
</h5>
|
||||
<a
|
||||
href="https://element.io"
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59 text-ellipsis overflow-hidden"
|
||||
>
|
||||
https://element.io
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a
|
||||
href="https://element.io"
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
https://element.io
|
||||
</a>
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
<button
|
||||
aria-controls="radix-:r0:"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="dialog"
|
||||
class="_button_i91xf_17 _has-icon_i91xf_66 _destructive_i91xf_116"
|
||||
data-kind="secondary"
|
||||
data-size="sm"
|
||||
data-size="lg"
|
||||
data-state="closed"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
@@ -527,10 +561,10 @@ exports[`<OAuth2SessionDetail> > renders session details 1`] = `
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M9 12.031c0-.283.096-.52.288-.712A.968.968 0 0 1 10 11.03h7.15l-1.875-1.875a.96.96 0 0 1-.3-.7c0-.266.108-.508.325-.725a.93.93 0 0 1 .712-.287.977.977 0 0 1 .688.287l3.6 3.6c.1.1.17.209.212.325.042.117.063.242.063.375 0 .134-.02.259-.063.375a.877.877 0 0 1-.212.325l-3.6 3.6a.93.93 0 0 1-.712.288.977.977 0 0 1-.688-.288 1.02 1.02 0 0 1-.313-.712.931.931 0 0 1 .288-.713l1.875-1.875H10a.968.968 0 0 1-.712-.287A.968.968 0 0 1 9 12.03Zm-6-7c0-.55.196-1.02.588-1.412A1.926 1.926 0 0 1 5 3.03h6a.97.97 0 0 1 .713.288.968.968 0 0 1 .287.712.97.97 0 0 1-.287.713.968.968 0 0 1-.713.287H5v14h6a.97.97 0 0 1 .713.288.968.968 0 0 1 .287.712.97.97 0 0 1-.287.713.968.968 0 0 1-.713.287H5c-.55 0-1.02-.196-1.412-.587A1.926 1.926 0 0 1 3 19.03v-14Z"
|
||||
d="M7 21c-.55 0-1.02-.196-1.412-.587A1.926 1.926 0 0 1 5 19V6a.968.968 0 0 1-.713-.287A.968.968 0 0 1 4 5c0-.283.096-.52.287-.713A.968.968 0 0 1 5 4h4a.97.97 0 0 1 .287-.712A.968.968 0 0 1 10 3h4a.97.97 0 0 1 .713.288A.968.968 0 0 1 15 4h4a.97.97 0 0 1 .712.287c.192.192.288.43.288.713s-.096.52-.288.713A.968.968 0 0 1 19 6v13c0 .55-.196 1.02-.587 1.413A1.926 1.926 0 0 1 17 21H7ZM7 6v13h10V6H7Zm2 10c0 .283.096.52.287.712.192.192.43.288.713.288s.52-.096.713-.288A.968.968 0 0 0 11 16V9a.967.967 0 0 0-.287-.713A.968.968 0 0 0 10 8a.968.968 0 0 0-.713.287A.968.968 0 0 0 9 9v7Zm4 0c0 .283.096.52.287.712.192.192.43.288.713.288s.52-.096.713-.288A.968.968 0 0 0 15 16V9a.967.967 0 0 0-.287-.713A.968.968 0 0 0 14 8a.968.968 0 0 0-.713.287A.967.967 0 0 0 13 9v7Z"
|
||||
/>
|
||||
</svg>
|
||||
Sign out
|
||||
Remove device
|
||||
</button>
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
/* Copyright 2024 New Vector Ltd.
|
||||
* Copyright 2024 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
.list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--cpd-space-scale);
|
||||
border-radius: var(--cpd-space-5x);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.item {
|
||||
background: var(--cpd-color-bg-action-secondary-hovered);
|
||||
padding: var(--cpd-space-3x) var(--cpd-space-5x);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--cpd-space-3x);
|
||||
}
|
||||
|
||||
.item svg {
|
||||
inline-size: var(--cpd-space-6x);
|
||||
block-size: var(--cpd-space-6x);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
// Copyright 2024 New Vector Ltd.
|
||||
// Copyright 2024 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
// Please see LICENSE in the repository root for full details.
|
||||
|
||||
import { Text } from "@vector-im/compound-web";
|
||||
import type {
|
||||
FC,
|
||||
ForwardRefExoticComponent,
|
||||
ReactNode,
|
||||
RefAttributes,
|
||||
SVGProps,
|
||||
} from "react";
|
||||
|
||||
import styles from "./VisualList.module.css";
|
||||
|
||||
type Props = {
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
export const VisualListItem: FC<{
|
||||
Icon: ForwardRefExoticComponent<
|
||||
Omit<SVGProps<SVGSVGElement>, "ref" | "children"> &
|
||||
RefAttributes<SVGSVGElement>
|
||||
>;
|
||||
iconColor?: string;
|
||||
label: string;
|
||||
}> = ({ Icon, iconColor, label }) => {
|
||||
return (
|
||||
<li className={styles.item}>
|
||||
<Icon color={iconColor ?? "var(--cpd-color-icon-tertiary)"} />
|
||||
<Text size="md">{label}</Text>
|
||||
</li>
|
||||
);
|
||||
};
|
||||
|
||||
export const VisualList: React.FC<Props> = ({ children }) => {
|
||||
return <ul className={styles.list}>{children}</ul>;
|
||||
};
|
||||
@@ -182,10 +182,10 @@ exports[`<CompatSession /> > renders an active session 1`] = `
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M9 12.031c0-.283.096-.52.288-.712A.968.968 0 0 1 10 11.03h7.15l-1.875-1.875a.96.96 0 0 1-.3-.7c0-.266.108-.508.325-.725a.93.93 0 0 1 .712-.287.977.977 0 0 1 .688.287l3.6 3.6c.1.1.17.209.212.325.042.117.063.242.063.375 0 .134-.02.259-.063.375a.877.877 0 0 1-.212.325l-3.6 3.6a.93.93 0 0 1-.712.288.977.977 0 0 1-.688-.288 1.02 1.02 0 0 1-.313-.712.931.931 0 0 1 .288-.713l1.875-1.875H10a.968.968 0 0 1-.712-.287A.968.968 0 0 1 9 12.03Zm-6-7c0-.55.196-1.02.588-1.412A1.926 1.926 0 0 1 5 3.03h6a.97.97 0 0 1 .713.288.968.968 0 0 1 .287.712.97.97 0 0 1-.287.713.968.968 0 0 1-.713.287H5v14h6a.97.97 0 0 1 .713.288.968.968 0 0 1 .287.712.97.97 0 0 1-.287.713.968.968 0 0 1-.713.287H5c-.55 0-1.02-.196-1.412-.587A1.926 1.926 0 0 1 3 19.03v-14Z"
|
||||
d="M7 21c-.55 0-1.02-.196-1.412-.587A1.926 1.926 0 0 1 5 19V6a.968.968 0 0 1-.713-.287A.968.968 0 0 1 4 5c0-.283.096-.52.287-.713A.968.968 0 0 1 5 4h4a.97.97 0 0 1 .287-.712A.968.968 0 0 1 10 3h4a.97.97 0 0 1 .713.288A.968.968 0 0 1 15 4h4a.97.97 0 0 1 .712.287c.192.192.288.43.288.713s-.096.52-.288.713A.968.968 0 0 1 19 6v13c0 .55-.196 1.02-.587 1.413A1.926 1.926 0 0 1 17 21H7ZM7 6v13h10V6H7Zm2 10c0 .283.096.52.287.712.192.192.43.288.713.288s.52-.096.713-.288A.968.968 0 0 0 11 16V9a.967.967 0 0 0-.287-.713A.968.968 0 0 0 10 8a.968.968 0 0 0-.713.287A.968.968 0 0 0 9 9v7Zm4 0c0 .283.096.52.287.712.192.192.43.288.713.288s.52-.096.713-.288A.968.968 0 0 0 15 16V9a.967.967 0 0 0-.287-.713A.968.968 0 0 0 14 8a.968.968 0 0 0-.713.287A.967.967 0 0 0 13 9v7Z"
|
||||
/>
|
||||
</svg>
|
||||
Sign out
|
||||
Remove device
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -176,10 +176,10 @@ exports[`<OAuth2Session /> > renders an active session 1`] = `
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M9 12.031c0-.283.096-.52.288-.712A.968.968 0 0 1 10 11.03h7.15l-1.875-1.875a.96.96 0 0 1-.3-.7c0-.266.108-.508.325-.725a.93.93 0 0 1 .712-.287.977.977 0 0 1 .688.287l3.6 3.6c.1.1.17.209.212.325.042.117.063.242.063.375 0 .134-.02.259-.063.375a.877.877 0 0 1-.212.325l-3.6 3.6a.93.93 0 0 1-.712.288.977.977 0 0 1-.688-.288 1.02 1.02 0 0 1-.313-.712.931.931 0 0 1 .288-.713l1.875-1.875H10a.968.968 0 0 1-.712-.287A.968.968 0 0 1 9 12.03Zm-6-7c0-.55.196-1.02.588-1.412A1.926 1.926 0 0 1 5 3.03h6a.97.97 0 0 1 .713.288.968.968 0 0 1 .287.712.97.97 0 0 1-.287.713.968.968 0 0 1-.713.287H5v14h6a.97.97 0 0 1 .713.288.968.968 0 0 1 .287.712.97.97 0 0 1-.287.713.968.968 0 0 1-.713.287H5c-.55 0-1.02-.196-1.412-.587A1.926 1.926 0 0 1 3 19.03v-14Z"
|
||||
d="M7 21c-.55 0-1.02-.196-1.412-.587A1.926 1.926 0 0 1 5 19V6a.968.968 0 0 1-.713-.287A.968.968 0 0 1 4 5c0-.283.096-.52.287-.713A.968.968 0 0 1 5 4h4a.97.97 0 0 1 .287-.712A.968.968 0 0 1 10 3h4a.97.97 0 0 1 .713.288A.968.968 0 0 1 15 4h4a.97.97 0 0 1 .712.287c.192.192.288.43.288.713s-.096.52-.288.713A.968.968 0 0 1 19 6v13c0 .55-.196 1.02-.587 1.413A1.926 1.926 0 0 1 17 21H7ZM7 6v13h10V6H7Zm2 10c0 .283.096.52.287.712.192.192.43.288.713.288s.52-.096.713-.288A.968.968 0 0 0 11 16V9a.967.967 0 0 0-.287-.713A.968.968 0 0 0 10 8a.968.968 0 0 0-.713.287A.968.968 0 0 0 9 9v7Zm4 0c0 .283.096.52.287.712.192.192.43.288.713.288s.52-.096.713-.288A.968.968 0 0 0 15 16V9a.967.967 0 0 0-.287-.713A.968.968 0 0 0 14 8a.968.968 0 0 0-.713.287A.967.967 0 0 0 13 9v7Z"
|
||||
/>
|
||||
</svg>
|
||||
Sign out
|
||||
Remove device
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -16,19 +16,22 @@ import * as types from './graphql';
|
||||
*/
|
||||
type Documents = {
|
||||
"\n fragment PasswordChange_siteConfig on SiteConfig {\n passwordChangeAllowed\n }\n": typeof types.PasswordChange_SiteConfigFragmentDoc,
|
||||
"\n fragment BrowserSession_session on BrowserSession {\n id\n createdAt\n finishedAt\n userAgent {\n raw\n name\n os\n model\n deviceType\n }\n lastActiveIp\n lastActiveAt\n lastAuthentication {\n id\n createdAt\n }\n }\n": typeof types.BrowserSession_SessionFragmentDoc,
|
||||
"\n mutation EndBrowserSession($id: ID!) {\n endBrowserSession(input: { browserSessionId: $id }) {\n status\n browserSession {\n id\n ...BrowserSession_session\n }\n }\n }\n": typeof types.EndBrowserSessionDocument,
|
||||
"\n fragment BrowserSession_session on BrowserSession {\n id\n createdAt\n finishedAt\n ...EndBrowserSessionButton_session\n userAgent {\n deviceType\n name\n os\n model\n }\n lastActiveAt\n }\n": typeof types.BrowserSession_SessionFragmentDoc,
|
||||
"\n fragment OAuth2Client_detail on Oauth2Client {\n id\n clientId\n clientName\n clientUri\n logoUri\n tosUri\n policyUri\n redirectUris\n }\n": typeof types.OAuth2Client_DetailFragmentDoc,
|
||||
"\n fragment CompatSession_session on CompatSession {\n id\n createdAt\n deviceId\n finishedAt\n lastActiveIp\n lastActiveAt\n userAgent {\n name\n os\n model\n deviceType\n }\n ssoLogin {\n id\n redirectUri\n }\n }\n": typeof types.CompatSession_SessionFragmentDoc,
|
||||
"\n mutation EndCompatSession($id: ID!) {\n endCompatSession(input: { compatSessionId: $id }) {\n status\n compatSession {\n id\n }\n }\n }\n": typeof types.EndCompatSessionDocument,
|
||||
"\n fragment CompatSession_session on CompatSession {\n id\n createdAt\n deviceId\n finishedAt\n lastActiveIp\n lastActiveAt\n ...EndCompatSessionButton_session\n userAgent {\n name\n os\n model\n deviceType\n }\n ssoLogin {\n id\n redirectUri\n }\n }\n": typeof types.CompatSession_SessionFragmentDoc,
|
||||
"\n fragment Footer_siteConfig on SiteConfig {\n id\n imprint\n tosUri\n policyUri\n }\n": typeof types.Footer_SiteConfigFragmentDoc,
|
||||
"\n query Footer {\n siteConfig {\n id\n ...Footer_siteConfig\n }\n }\n": typeof types.FooterDocument,
|
||||
"\n fragment OAuth2Session_session on Oauth2Session {\n id\n scope\n createdAt\n finishedAt\n lastActiveIp\n lastActiveAt\n\n userAgent {\n name\n model\n os\n deviceType\n }\n\n client {\n id\n clientId\n clientName\n applicationType\n logoUri\n }\n }\n": typeof types.OAuth2Session_SessionFragmentDoc,
|
||||
"\n mutation EndOAuth2Session($id: ID!) {\n endOauth2Session(input: { oauth2SessionId: $id }) {\n status\n oauth2Session {\n id\n }\n }\n }\n": typeof types.EndOAuth2SessionDocument,
|
||||
"\n fragment OAuth2Session_session on Oauth2Session {\n id\n scope\n createdAt\n finishedAt\n lastActiveIp\n lastActiveAt\n\n ...EndOAuth2SessionButton_session\n\n userAgent {\n name\n model\n os\n deviceType\n }\n\n client {\n id\n clientId\n clientName\n applicationType\n logoUri\n }\n }\n": typeof types.OAuth2Session_SessionFragmentDoc,
|
||||
"\n fragment PasswordCreationDoubleInput_siteConfig on SiteConfig {\n id\n minimumPasswordComplexity\n }\n": typeof types.PasswordCreationDoubleInput_SiteConfigFragmentDoc,
|
||||
"\n fragment BrowserSession_detail on BrowserSession {\n id\n createdAt\n finishedAt\n userAgent {\n name\n model\n os\n }\n lastActiveIp\n lastActiveAt\n lastAuthentication {\n id\n createdAt\n }\n user {\n id\n username\n }\n }\n": typeof types.BrowserSession_DetailFragmentDoc,
|
||||
"\n fragment CompatSession_detail on CompatSession {\n id\n createdAt\n deviceId\n finishedAt\n lastActiveIp\n lastActiveAt\n userAgent {\n name\n os\n model\n }\n ssoLogin {\n id\n redirectUri\n }\n }\n": typeof types.CompatSession_DetailFragmentDoc,
|
||||
"\n fragment OAuth2Session_detail on Oauth2Session {\n id\n scope\n createdAt\n finishedAt\n lastActiveIp\n lastActiveAt\n client {\n id\n clientId\n clientName\n clientUri\n logoUri\n }\n }\n": typeof types.OAuth2Session_DetailFragmentDoc,
|
||||
"\n fragment EndBrowserSessionButton_session on BrowserSession {\n id\n userAgent {\n name\n os\n model\n deviceType\n }\n }\n": typeof types.EndBrowserSessionButton_SessionFragmentDoc,
|
||||
"\n mutation EndBrowserSession($id: ID!) {\n endBrowserSession(input: { browserSessionId: $id }) {\n status\n browserSession {\n id\n }\n }\n }\n": typeof types.EndBrowserSessionDocument,
|
||||
"\n fragment EndCompatSessionButton_session on CompatSession {\n id\n userAgent {\n name\n os\n model\n deviceType\n }\n ssoLogin {\n id\n redirectUri\n }\n }\n": typeof types.EndCompatSessionButton_SessionFragmentDoc,
|
||||
"\n mutation EndCompatSession($id: ID!) {\n endCompatSession(input: { compatSessionId: $id }) {\n status\n compatSession {\n id\n }\n }\n }\n": typeof types.EndCompatSessionDocument,
|
||||
"\n fragment EndOAuth2SessionButton_session on Oauth2Session {\n id\n\n userAgent {\n name\n model\n os\n deviceType\n }\n\n client {\n clientId\n clientName\n applicationType\n logoUri\n }\n }\n": typeof types.EndOAuth2SessionButton_SessionFragmentDoc,
|
||||
"\n mutation EndOAuth2Session($id: ID!) {\n endOauth2Session(input: { oauth2SessionId: $id }) {\n status\n oauth2Session {\n id\n }\n }\n }\n": typeof types.EndOAuth2SessionDocument,
|
||||
"\n fragment BrowserSession_detail on BrowserSession {\n id\n createdAt\n finishedAt\n ...EndBrowserSessionButton_session\n userAgent {\n name\n model\n os\n }\n lastActiveIp\n lastActiveAt\n lastAuthentication {\n id\n createdAt\n }\n user {\n id\n username\n }\n }\n": typeof types.BrowserSession_DetailFragmentDoc,
|
||||
"\n fragment CompatSession_detail on CompatSession {\n id\n createdAt\n deviceId\n finishedAt\n lastActiveIp\n lastActiveAt\n\n ...EndCompatSessionButton_session\n\n userAgent {\n name\n os\n model\n }\n\n ssoLogin {\n id\n redirectUri\n }\n }\n": typeof types.CompatSession_DetailFragmentDoc,
|
||||
"\n fragment OAuth2Session_detail on Oauth2Session {\n id\n scope\n createdAt\n finishedAt\n lastActiveIp\n lastActiveAt\n\n ...EndOAuth2SessionButton_session\n\n userAgent {\n name\n model\n os\n }\n\n client {\n id\n clientId\n clientName\n clientUri\n logoUri\n }\n }\n": typeof types.OAuth2Session_DetailFragmentDoc,
|
||||
"\n fragment UserEmail_email on UserEmail {\n id\n email\n }\n": typeof types.UserEmail_EmailFragmentDoc,
|
||||
"\n fragment UserEmail_siteConfig on SiteConfig {\n emailChangeAllowed\n }\n": typeof types.UserEmail_SiteConfigFragmentDoc,
|
||||
"\n mutation RemoveEmail($id: ID!) {\n removeEmail(input: { userEmailId: $id }) {\n status\n\n user {\n id\n }\n }\n }\n": typeof types.RemoveEmailDocument,
|
||||
@@ -39,12 +42,11 @@ type Documents = {
|
||||
"\n query UserEmailList(\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n viewer {\n __typename\n ... on User {\n emails(first: $first, after: $after, last: $last, before: $before) {\n edges {\n cursor\n node {\n ...UserEmail_email\n }\n }\n totalCount\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n }\n": typeof types.UserEmailListDocument,
|
||||
"\n fragment UserEmailList_siteConfig on SiteConfig {\n emailChangeAllowed\n }\n": typeof types.UserEmailList_SiteConfigFragmentDoc,
|
||||
"\n fragment BrowserSessionsOverview_user on User {\n id\n\n browserSessions(first: 0, state: ACTIVE) {\n totalCount\n }\n }\n": typeof types.BrowserSessionsOverview_UserFragmentDoc,
|
||||
"\n query UserProfile {\n viewer {\n __typename\n ... on User {\n emails(first: 0) {\n totalCount\n }\n }\n }\n\n siteConfig {\n emailChangeAllowed\n passwordLoginEnabled\n ...UserEmailList_siteConfig\n ...UserEmail_siteConfig\n ...PasswordChange_siteConfig\n }\n }\n": typeof types.UserProfileDocument,
|
||||
"\n query SessionDetail($id: ID!) {\n viewerSession {\n ... on Node {\n id\n }\n }\n\n node(id: $id) {\n __typename\n id\n ...CompatSession_detail\n ...OAuth2Session_detail\n ...BrowserSession_detail\n }\n }\n": typeof types.SessionDetailDocument,
|
||||
"\n query UserProfile {\n viewerSession {\n __typename\n ... on BrowserSession {\n id\n user {\n emails(first: 0) {\n totalCount\n }\n }\n }\n }\n\n siteConfig {\n emailChangeAllowed\n passwordLoginEnabled\n ...UserEmailList_siteConfig\n ...UserEmail_siteConfig\n ...PasswordChange_siteConfig\n }\n }\n": typeof types.UserProfileDocument,
|
||||
"\n query BrowserSessionList(\n $first: Int\n $after: String\n $last: Int\n $before: String\n $lastActive: DateFilter\n ) {\n viewerSession {\n __typename\n ... on BrowserSession {\n id\n\n user {\n id\n\n browserSessions(\n first: $first\n after: $after\n last: $last\n before: $before\n lastActive: $lastActive\n state: ACTIVE\n ) {\n totalCount\n\n edges {\n cursor\n node {\n id\n ...BrowserSession_session\n }\n }\n\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n }\n }\n": typeof types.BrowserSessionListDocument,
|
||||
"\n query SessionsOverview {\n viewer {\n __typename\n\n ... on User {\n id\n ...BrowserSessionsOverview_user\n }\n }\n }\n": typeof types.SessionsOverviewDocument,
|
||||
"\n query AppSessionsList(\n $before: String\n $after: String\n $first: Int\n $last: Int\n $lastActive: DateFilter\n ) {\n viewer {\n __typename\n\n ... on User {\n id\n appSessions(\n before: $before\n after: $after\n first: $first\n last: $last\n lastActive: $lastActive\n state: ACTIVE\n ) {\n edges {\n cursor\n node {\n __typename\n ...CompatSession_session\n ...OAuth2Session_session\n }\n }\n\n totalCount\n pageInfo {\n startCursor\n endCursor\n hasNextPage\n hasPreviousPage\n }\n }\n }\n }\n }\n": typeof types.AppSessionsListDocument,
|
||||
"\n query CurrentUserGreeting {\n viewerSession {\n __typename\n\n ... on BrowserSession {\n id\n\n user {\n ...UserGreeting_user\n }\n }\n }\n\n siteConfig {\n ...UserGreeting_siteConfig\n }\n }\n": typeof types.CurrentUserGreetingDocument,
|
||||
"\n query CurrentUserGreeting {\n viewer {\n __typename\n ... on User {\n ...UserGreeting_user\n }\n }\n\n siteConfig {\n ...UserGreeting_siteConfig\n }\n }\n": typeof types.CurrentUserGreetingDocument,
|
||||
"\n query OAuth2Client($id: ID!) {\n oauth2Client(id: $id) {\n ...OAuth2Client_detail\n }\n }\n": typeof types.OAuth2ClientDocument,
|
||||
"\n query CurrentViewer {\n viewer {\n __typename\n ... on Node {\n id\n }\n }\n }\n": typeof types.CurrentViewerDocument,
|
||||
"\n query DeviceRedirect($deviceId: String!, $userId: ID!) {\n session(deviceId: $deviceId, userId: $userId) {\n __typename\n ... on Node {\n id\n }\n }\n }\n": typeof types.DeviceRedirectDocument,
|
||||
@@ -59,22 +61,26 @@ type Documents = {
|
||||
"\n fragment RecoverPassword_siteConfig on SiteConfig {\n ...PasswordCreationDoubleInput_siteConfig\n }\n": typeof types.RecoverPassword_SiteConfigFragmentDoc,
|
||||
"\n query PasswordRecovery($ticket: String!) {\n siteConfig {\n ...RecoverPassword_siteConfig\n }\n\n userRecoveryTicket(ticket: $ticket) {\n status\n ...RecoverPassword_userRecoveryTicket\n }\n }\n": typeof types.PasswordRecoveryDocument,
|
||||
"\n mutation AllowCrossSigningReset($userId: ID!) {\n allowUserCrossSigningReset(input: { userId: $userId }) {\n user {\n id\n }\n }\n }\n": typeof types.AllowCrossSigningResetDocument,
|
||||
"\n query SessionDetail($id: ID!) {\n viewerSession {\n ... on Node {\n id\n }\n }\n\n node(id: $id) {\n __typename\n id\n ...CompatSession_detail\n ...OAuth2Session_detail\n ...BrowserSession_detail\n }\n }\n": typeof types.SessionDetailDocument,
|
||||
};
|
||||
const documents: Documents = {
|
||||
"\n fragment PasswordChange_siteConfig on SiteConfig {\n passwordChangeAllowed\n }\n": types.PasswordChange_SiteConfigFragmentDoc,
|
||||
"\n fragment BrowserSession_session on BrowserSession {\n id\n createdAt\n finishedAt\n userAgent {\n raw\n name\n os\n model\n deviceType\n }\n lastActiveIp\n lastActiveAt\n lastAuthentication {\n id\n createdAt\n }\n }\n": types.BrowserSession_SessionFragmentDoc,
|
||||
"\n mutation EndBrowserSession($id: ID!) {\n endBrowserSession(input: { browserSessionId: $id }) {\n status\n browserSession {\n id\n ...BrowserSession_session\n }\n }\n }\n": types.EndBrowserSessionDocument,
|
||||
"\n fragment BrowserSession_session on BrowserSession {\n id\n createdAt\n finishedAt\n ...EndBrowserSessionButton_session\n userAgent {\n deviceType\n name\n os\n model\n }\n lastActiveAt\n }\n": types.BrowserSession_SessionFragmentDoc,
|
||||
"\n fragment OAuth2Client_detail on Oauth2Client {\n id\n clientId\n clientName\n clientUri\n logoUri\n tosUri\n policyUri\n redirectUris\n }\n": types.OAuth2Client_DetailFragmentDoc,
|
||||
"\n fragment CompatSession_session on CompatSession {\n id\n createdAt\n deviceId\n finishedAt\n lastActiveIp\n lastActiveAt\n userAgent {\n name\n os\n model\n deviceType\n }\n ssoLogin {\n id\n redirectUri\n }\n }\n": types.CompatSession_SessionFragmentDoc,
|
||||
"\n mutation EndCompatSession($id: ID!) {\n endCompatSession(input: { compatSessionId: $id }) {\n status\n compatSession {\n id\n }\n }\n }\n": types.EndCompatSessionDocument,
|
||||
"\n fragment CompatSession_session on CompatSession {\n id\n createdAt\n deviceId\n finishedAt\n lastActiveIp\n lastActiveAt\n ...EndCompatSessionButton_session\n userAgent {\n name\n os\n model\n deviceType\n }\n ssoLogin {\n id\n redirectUri\n }\n }\n": types.CompatSession_SessionFragmentDoc,
|
||||
"\n fragment Footer_siteConfig on SiteConfig {\n id\n imprint\n tosUri\n policyUri\n }\n": types.Footer_SiteConfigFragmentDoc,
|
||||
"\n query Footer {\n siteConfig {\n id\n ...Footer_siteConfig\n }\n }\n": types.FooterDocument,
|
||||
"\n fragment OAuth2Session_session on Oauth2Session {\n id\n scope\n createdAt\n finishedAt\n lastActiveIp\n lastActiveAt\n\n userAgent {\n name\n model\n os\n deviceType\n }\n\n client {\n id\n clientId\n clientName\n applicationType\n logoUri\n }\n }\n": types.OAuth2Session_SessionFragmentDoc,
|
||||
"\n mutation EndOAuth2Session($id: ID!) {\n endOauth2Session(input: { oauth2SessionId: $id }) {\n status\n oauth2Session {\n id\n }\n }\n }\n": types.EndOAuth2SessionDocument,
|
||||
"\n fragment OAuth2Session_session on Oauth2Session {\n id\n scope\n createdAt\n finishedAt\n lastActiveIp\n lastActiveAt\n\n ...EndOAuth2SessionButton_session\n\n userAgent {\n name\n model\n os\n deviceType\n }\n\n client {\n id\n clientId\n clientName\n applicationType\n logoUri\n }\n }\n": types.OAuth2Session_SessionFragmentDoc,
|
||||
"\n fragment PasswordCreationDoubleInput_siteConfig on SiteConfig {\n id\n minimumPasswordComplexity\n }\n": types.PasswordCreationDoubleInput_SiteConfigFragmentDoc,
|
||||
"\n fragment BrowserSession_detail on BrowserSession {\n id\n createdAt\n finishedAt\n userAgent {\n name\n model\n os\n }\n lastActiveIp\n lastActiveAt\n lastAuthentication {\n id\n createdAt\n }\n user {\n id\n username\n }\n }\n": types.BrowserSession_DetailFragmentDoc,
|
||||
"\n fragment CompatSession_detail on CompatSession {\n id\n createdAt\n deviceId\n finishedAt\n lastActiveIp\n lastActiveAt\n userAgent {\n name\n os\n model\n }\n ssoLogin {\n id\n redirectUri\n }\n }\n": types.CompatSession_DetailFragmentDoc,
|
||||
"\n fragment OAuth2Session_detail on Oauth2Session {\n id\n scope\n createdAt\n finishedAt\n lastActiveIp\n lastActiveAt\n client {\n id\n clientId\n clientName\n clientUri\n logoUri\n }\n }\n": types.OAuth2Session_DetailFragmentDoc,
|
||||
"\n fragment EndBrowserSessionButton_session on BrowserSession {\n id\n userAgent {\n name\n os\n model\n deviceType\n }\n }\n": types.EndBrowserSessionButton_SessionFragmentDoc,
|
||||
"\n mutation EndBrowserSession($id: ID!) {\n endBrowserSession(input: { browserSessionId: $id }) {\n status\n browserSession {\n id\n }\n }\n }\n": types.EndBrowserSessionDocument,
|
||||
"\n fragment EndCompatSessionButton_session on CompatSession {\n id\n userAgent {\n name\n os\n model\n deviceType\n }\n ssoLogin {\n id\n redirectUri\n }\n }\n": types.EndCompatSessionButton_SessionFragmentDoc,
|
||||
"\n mutation EndCompatSession($id: ID!) {\n endCompatSession(input: { compatSessionId: $id }) {\n status\n compatSession {\n id\n }\n }\n }\n": types.EndCompatSessionDocument,
|
||||
"\n fragment EndOAuth2SessionButton_session on Oauth2Session {\n id\n\n userAgent {\n name\n model\n os\n deviceType\n }\n\n client {\n clientId\n clientName\n applicationType\n logoUri\n }\n }\n": types.EndOAuth2SessionButton_SessionFragmentDoc,
|
||||
"\n mutation EndOAuth2Session($id: ID!) {\n endOauth2Session(input: { oauth2SessionId: $id }) {\n status\n oauth2Session {\n id\n }\n }\n }\n": types.EndOAuth2SessionDocument,
|
||||
"\n fragment BrowserSession_detail on BrowserSession {\n id\n createdAt\n finishedAt\n ...EndBrowserSessionButton_session\n userAgent {\n name\n model\n os\n }\n lastActiveIp\n lastActiveAt\n lastAuthentication {\n id\n createdAt\n }\n user {\n id\n username\n }\n }\n": types.BrowserSession_DetailFragmentDoc,
|
||||
"\n fragment CompatSession_detail on CompatSession {\n id\n createdAt\n deviceId\n finishedAt\n lastActiveIp\n lastActiveAt\n\n ...EndCompatSessionButton_session\n\n userAgent {\n name\n os\n model\n }\n\n ssoLogin {\n id\n redirectUri\n }\n }\n": types.CompatSession_DetailFragmentDoc,
|
||||
"\n fragment OAuth2Session_detail on Oauth2Session {\n id\n scope\n createdAt\n finishedAt\n lastActiveIp\n lastActiveAt\n\n ...EndOAuth2SessionButton_session\n\n userAgent {\n name\n model\n os\n }\n\n client {\n id\n clientId\n clientName\n clientUri\n logoUri\n }\n }\n": types.OAuth2Session_DetailFragmentDoc,
|
||||
"\n fragment UserEmail_email on UserEmail {\n id\n email\n }\n": types.UserEmail_EmailFragmentDoc,
|
||||
"\n fragment UserEmail_siteConfig on SiteConfig {\n emailChangeAllowed\n }\n": types.UserEmail_SiteConfigFragmentDoc,
|
||||
"\n mutation RemoveEmail($id: ID!) {\n removeEmail(input: { userEmailId: $id }) {\n status\n\n user {\n id\n }\n }\n }\n": types.RemoveEmailDocument,
|
||||
@@ -85,12 +91,11 @@ const documents: Documents = {
|
||||
"\n query UserEmailList(\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n viewer {\n __typename\n ... on User {\n emails(first: $first, after: $after, last: $last, before: $before) {\n edges {\n cursor\n node {\n ...UserEmail_email\n }\n }\n totalCount\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n }\n": types.UserEmailListDocument,
|
||||
"\n fragment UserEmailList_siteConfig on SiteConfig {\n emailChangeAllowed\n }\n": types.UserEmailList_SiteConfigFragmentDoc,
|
||||
"\n fragment BrowserSessionsOverview_user on User {\n id\n\n browserSessions(first: 0, state: ACTIVE) {\n totalCount\n }\n }\n": types.BrowserSessionsOverview_UserFragmentDoc,
|
||||
"\n query UserProfile {\n viewer {\n __typename\n ... on User {\n emails(first: 0) {\n totalCount\n }\n }\n }\n\n siteConfig {\n emailChangeAllowed\n passwordLoginEnabled\n ...UserEmailList_siteConfig\n ...UserEmail_siteConfig\n ...PasswordChange_siteConfig\n }\n }\n": types.UserProfileDocument,
|
||||
"\n query SessionDetail($id: ID!) {\n viewerSession {\n ... on Node {\n id\n }\n }\n\n node(id: $id) {\n __typename\n id\n ...CompatSession_detail\n ...OAuth2Session_detail\n ...BrowserSession_detail\n }\n }\n": types.SessionDetailDocument,
|
||||
"\n query UserProfile {\n viewerSession {\n __typename\n ... on BrowserSession {\n id\n user {\n emails(first: 0) {\n totalCount\n }\n }\n }\n }\n\n siteConfig {\n emailChangeAllowed\n passwordLoginEnabled\n ...UserEmailList_siteConfig\n ...UserEmail_siteConfig\n ...PasswordChange_siteConfig\n }\n }\n": types.UserProfileDocument,
|
||||
"\n query BrowserSessionList(\n $first: Int\n $after: String\n $last: Int\n $before: String\n $lastActive: DateFilter\n ) {\n viewerSession {\n __typename\n ... on BrowserSession {\n id\n\n user {\n id\n\n browserSessions(\n first: $first\n after: $after\n last: $last\n before: $before\n lastActive: $lastActive\n state: ACTIVE\n ) {\n totalCount\n\n edges {\n cursor\n node {\n id\n ...BrowserSession_session\n }\n }\n\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n }\n }\n": types.BrowserSessionListDocument,
|
||||
"\n query SessionsOverview {\n viewer {\n __typename\n\n ... on User {\n id\n ...BrowserSessionsOverview_user\n }\n }\n }\n": types.SessionsOverviewDocument,
|
||||
"\n query AppSessionsList(\n $before: String\n $after: String\n $first: Int\n $last: Int\n $lastActive: DateFilter\n ) {\n viewer {\n __typename\n\n ... on User {\n id\n appSessions(\n before: $before\n after: $after\n first: $first\n last: $last\n lastActive: $lastActive\n state: ACTIVE\n ) {\n edges {\n cursor\n node {\n __typename\n ...CompatSession_session\n ...OAuth2Session_session\n }\n }\n\n totalCount\n pageInfo {\n startCursor\n endCursor\n hasNextPage\n hasPreviousPage\n }\n }\n }\n }\n }\n": types.AppSessionsListDocument,
|
||||
"\n query CurrentUserGreeting {\n viewerSession {\n __typename\n\n ... on BrowserSession {\n id\n\n user {\n ...UserGreeting_user\n }\n }\n }\n\n siteConfig {\n ...UserGreeting_siteConfig\n }\n }\n": types.CurrentUserGreetingDocument,
|
||||
"\n query CurrentUserGreeting {\n viewer {\n __typename\n ... on User {\n ...UserGreeting_user\n }\n }\n\n siteConfig {\n ...UserGreeting_siteConfig\n }\n }\n": types.CurrentUserGreetingDocument,
|
||||
"\n query OAuth2Client($id: ID!) {\n oauth2Client(id: $id) {\n ...OAuth2Client_detail\n }\n }\n": types.OAuth2ClientDocument,
|
||||
"\n query CurrentViewer {\n viewer {\n __typename\n ... on Node {\n id\n }\n }\n }\n": types.CurrentViewerDocument,
|
||||
"\n query DeviceRedirect($deviceId: String!, $userId: ID!) {\n session(deviceId: $deviceId, userId: $userId) {\n __typename\n ... on Node {\n id\n }\n }\n }\n": types.DeviceRedirectDocument,
|
||||
@@ -105,6 +110,7 @@ const documents: Documents = {
|
||||
"\n fragment RecoverPassword_siteConfig on SiteConfig {\n ...PasswordCreationDoubleInput_siteConfig\n }\n": types.RecoverPassword_SiteConfigFragmentDoc,
|
||||
"\n query PasswordRecovery($ticket: String!) {\n siteConfig {\n ...RecoverPassword_siteConfig\n }\n\n userRecoveryTicket(ticket: $ticket) {\n status\n ...RecoverPassword_userRecoveryTicket\n }\n }\n": types.PasswordRecoveryDocument,
|
||||
"\n mutation AllowCrossSigningReset($userId: ID!) {\n allowUserCrossSigningReset(input: { userId: $userId }) {\n user {\n id\n }\n }\n }\n": types.AllowCrossSigningResetDocument,
|
||||
"\n query SessionDetail($id: ID!) {\n viewerSession {\n ... on Node {\n id\n }\n }\n\n node(id: $id) {\n __typename\n id\n ...CompatSession_detail\n ...OAuth2Session_detail\n ...BrowserSession_detail\n }\n }\n": types.SessionDetailDocument,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -114,11 +120,7 @@ export function graphql(source: "\n fragment PasswordChange_siteConfig on SiteC
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n fragment BrowserSession_session on BrowserSession {\n id\n createdAt\n finishedAt\n userAgent {\n raw\n name\n os\n model\n deviceType\n }\n lastActiveIp\n lastActiveAt\n lastAuthentication {\n id\n createdAt\n }\n }\n"): typeof import('./graphql').BrowserSession_SessionFragmentDoc;
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n mutation EndBrowserSession($id: ID!) {\n endBrowserSession(input: { browserSessionId: $id }) {\n status\n browserSession {\n id\n ...BrowserSession_session\n }\n }\n }\n"): typeof import('./graphql').EndBrowserSessionDocument;
|
||||
export function graphql(source: "\n fragment BrowserSession_session on BrowserSession {\n id\n createdAt\n finishedAt\n ...EndBrowserSessionButton_session\n userAgent {\n deviceType\n name\n os\n model\n }\n lastActiveAt\n }\n"): typeof import('./graphql').BrowserSession_SessionFragmentDoc;
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
@@ -126,11 +128,7 @@ export function graphql(source: "\n fragment OAuth2Client_detail on Oauth2Clien
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n fragment CompatSession_session on CompatSession {\n id\n createdAt\n deviceId\n finishedAt\n lastActiveIp\n lastActiveAt\n userAgent {\n name\n os\n model\n deviceType\n }\n ssoLogin {\n id\n redirectUri\n }\n }\n"): typeof import('./graphql').CompatSession_SessionFragmentDoc;
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n mutation EndCompatSession($id: ID!) {\n endCompatSession(input: { compatSessionId: $id }) {\n status\n compatSession {\n id\n }\n }\n }\n"): typeof import('./graphql').EndCompatSessionDocument;
|
||||
export function graphql(source: "\n fragment CompatSession_session on CompatSession {\n id\n createdAt\n deviceId\n finishedAt\n lastActiveIp\n lastActiveAt\n ...EndCompatSessionButton_session\n userAgent {\n name\n os\n model\n deviceType\n }\n ssoLogin {\n id\n redirectUri\n }\n }\n"): typeof import('./graphql').CompatSession_SessionFragmentDoc;
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
@@ -142,11 +140,7 @@ export function graphql(source: "\n query Footer {\n siteConfig {\n id\
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n fragment OAuth2Session_session on Oauth2Session {\n id\n scope\n createdAt\n finishedAt\n lastActiveIp\n lastActiveAt\n\n userAgent {\n name\n model\n os\n deviceType\n }\n\n client {\n id\n clientId\n clientName\n applicationType\n logoUri\n }\n }\n"): typeof import('./graphql').OAuth2Session_SessionFragmentDoc;
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n mutation EndOAuth2Session($id: ID!) {\n endOauth2Session(input: { oauth2SessionId: $id }) {\n status\n oauth2Session {\n id\n }\n }\n }\n"): typeof import('./graphql').EndOAuth2SessionDocument;
|
||||
export function graphql(source: "\n fragment OAuth2Session_session on Oauth2Session {\n id\n scope\n createdAt\n finishedAt\n lastActiveIp\n lastActiveAt\n\n ...EndOAuth2SessionButton_session\n\n userAgent {\n name\n model\n os\n deviceType\n }\n\n client {\n id\n clientId\n clientName\n applicationType\n logoUri\n }\n }\n"): typeof import('./graphql').OAuth2Session_SessionFragmentDoc;
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
@@ -154,15 +148,39 @@ export function graphql(source: "\n fragment PasswordCreationDoubleInput_siteCo
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n fragment BrowserSession_detail on BrowserSession {\n id\n createdAt\n finishedAt\n userAgent {\n name\n model\n os\n }\n lastActiveIp\n lastActiveAt\n lastAuthentication {\n id\n createdAt\n }\n user {\n id\n username\n }\n }\n"): typeof import('./graphql').BrowserSession_DetailFragmentDoc;
|
||||
export function graphql(source: "\n fragment EndBrowserSessionButton_session on BrowserSession {\n id\n userAgent {\n name\n os\n model\n deviceType\n }\n }\n"): typeof import('./graphql').EndBrowserSessionButton_SessionFragmentDoc;
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n fragment CompatSession_detail on CompatSession {\n id\n createdAt\n deviceId\n finishedAt\n lastActiveIp\n lastActiveAt\n userAgent {\n name\n os\n model\n }\n ssoLogin {\n id\n redirectUri\n }\n }\n"): typeof import('./graphql').CompatSession_DetailFragmentDoc;
|
||||
export function graphql(source: "\n mutation EndBrowserSession($id: ID!) {\n endBrowserSession(input: { browserSessionId: $id }) {\n status\n browserSession {\n id\n }\n }\n }\n"): typeof import('./graphql').EndBrowserSessionDocument;
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n fragment OAuth2Session_detail on Oauth2Session {\n id\n scope\n createdAt\n finishedAt\n lastActiveIp\n lastActiveAt\n client {\n id\n clientId\n clientName\n clientUri\n logoUri\n }\n }\n"): typeof import('./graphql').OAuth2Session_DetailFragmentDoc;
|
||||
export function graphql(source: "\n fragment EndCompatSessionButton_session on CompatSession {\n id\n userAgent {\n name\n os\n model\n deviceType\n }\n ssoLogin {\n id\n redirectUri\n }\n }\n"): typeof import('./graphql').EndCompatSessionButton_SessionFragmentDoc;
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n mutation EndCompatSession($id: ID!) {\n endCompatSession(input: { compatSessionId: $id }) {\n status\n compatSession {\n id\n }\n }\n }\n"): typeof import('./graphql').EndCompatSessionDocument;
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n fragment EndOAuth2SessionButton_session on Oauth2Session {\n id\n\n userAgent {\n name\n model\n os\n deviceType\n }\n\n client {\n clientId\n clientName\n applicationType\n logoUri\n }\n }\n"): typeof import('./graphql').EndOAuth2SessionButton_SessionFragmentDoc;
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n mutation EndOAuth2Session($id: ID!) {\n endOauth2Session(input: { oauth2SessionId: $id }) {\n status\n oauth2Session {\n id\n }\n }\n }\n"): typeof import('./graphql').EndOAuth2SessionDocument;
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n fragment BrowserSession_detail on BrowserSession {\n id\n createdAt\n finishedAt\n ...EndBrowserSessionButton_session\n userAgent {\n name\n model\n os\n }\n lastActiveIp\n lastActiveAt\n lastAuthentication {\n id\n createdAt\n }\n user {\n id\n username\n }\n }\n"): typeof import('./graphql').BrowserSession_DetailFragmentDoc;
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n fragment CompatSession_detail on CompatSession {\n id\n createdAt\n deviceId\n finishedAt\n lastActiveIp\n lastActiveAt\n\n ...EndCompatSessionButton_session\n\n userAgent {\n name\n os\n model\n }\n\n ssoLogin {\n id\n redirectUri\n }\n }\n"): typeof import('./graphql').CompatSession_DetailFragmentDoc;
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n fragment OAuth2Session_detail on Oauth2Session {\n id\n scope\n createdAt\n finishedAt\n lastActiveIp\n lastActiveAt\n\n ...EndOAuth2SessionButton_session\n\n userAgent {\n name\n model\n os\n }\n\n client {\n id\n clientId\n clientName\n clientUri\n logoUri\n }\n }\n"): typeof import('./graphql').OAuth2Session_DetailFragmentDoc;
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
@@ -206,11 +224,7 @@ export function graphql(source: "\n fragment BrowserSessionsOverview_user on Us
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n query UserProfile {\n viewer {\n __typename\n ... on User {\n emails(first: 0) {\n totalCount\n }\n }\n }\n\n siteConfig {\n emailChangeAllowed\n passwordLoginEnabled\n ...UserEmailList_siteConfig\n ...UserEmail_siteConfig\n ...PasswordChange_siteConfig\n }\n }\n"): typeof import('./graphql').UserProfileDocument;
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n query SessionDetail($id: ID!) {\n viewerSession {\n ... on Node {\n id\n }\n }\n\n node(id: $id) {\n __typename\n id\n ...CompatSession_detail\n ...OAuth2Session_detail\n ...BrowserSession_detail\n }\n }\n"): typeof import('./graphql').SessionDetailDocument;
|
||||
export function graphql(source: "\n query UserProfile {\n viewerSession {\n __typename\n ... on BrowserSession {\n id\n user {\n emails(first: 0) {\n totalCount\n }\n }\n }\n }\n\n siteConfig {\n emailChangeAllowed\n passwordLoginEnabled\n ...UserEmailList_siteConfig\n ...UserEmail_siteConfig\n ...PasswordChange_siteConfig\n }\n }\n"): typeof import('./graphql').UserProfileDocument;
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
@@ -226,7 +240,7 @@ export function graphql(source: "\n query AppSessionsList(\n $before: String
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n query CurrentUserGreeting {\n viewerSession {\n __typename\n\n ... on BrowserSession {\n id\n\n user {\n ...UserGreeting_user\n }\n }\n }\n\n siteConfig {\n ...UserGreeting_siteConfig\n }\n }\n"): typeof import('./graphql').CurrentUserGreetingDocument;
|
||||
export function graphql(source: "\n query CurrentUserGreeting {\n viewer {\n __typename\n ... on User {\n ...UserGreeting_user\n }\n }\n\n siteConfig {\n ...UserGreeting_siteConfig\n }\n }\n"): typeof import('./graphql').CurrentUserGreetingDocument;
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
@@ -283,6 +297,10 @@ export function graphql(source: "\n query PasswordRecovery($ticket: String!) {\
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n mutation AllowCrossSigningReset($userId: ID!) {\n allowUserCrossSigningReset(input: { userId: $userId }) {\n user {\n id\n }\n }\n }\n"): typeof import('./graphql').AllowCrossSigningResetDocument;
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n query SessionDetail($id: ID!) {\n viewerSession {\n ... on Node {\n id\n }\n }\n\n node(id: $id) {\n __typename\n id\n ...CompatSession_detail\n ...OAuth2Session_detail\n ...BrowserSession_detail\n }\n }\n"): typeof import('./graphql').SessionDetailDocument;
|
||||
|
||||
|
||||
export function graphql(source: string) {
|
||||
|
||||
@@ -1565,28 +1565,17 @@ export type ViewerSession = Anonymous | BrowserSession | Oauth2Session;
|
||||
|
||||
export type PasswordChange_SiteConfigFragment = { __typename?: 'SiteConfig', passwordChangeAllowed: boolean } & { ' $fragmentName'?: 'PasswordChange_SiteConfigFragment' };
|
||||
|
||||
export type BrowserSession_SessionFragment = { __typename?: 'BrowserSession', id: string, createdAt: string, finishedAt?: string | null, lastActiveIp?: string | null, lastActiveAt?: string | null, userAgent?: { __typename?: 'UserAgent', raw: string, name?: string | null, os?: string | null, model?: string | null, deviceType: DeviceType } | null, lastAuthentication?: { __typename?: 'Authentication', id: string, createdAt: string } | null } & { ' $fragmentName'?: 'BrowserSession_SessionFragment' };
|
||||
|
||||
export type EndBrowserSessionMutationVariables = Exact<{
|
||||
id: Scalars['ID']['input'];
|
||||
}>;
|
||||
|
||||
|
||||
export type EndBrowserSessionMutation = { __typename?: 'Mutation', endBrowserSession: { __typename?: 'EndBrowserSessionPayload', status: EndBrowserSessionStatus, browserSession?: (
|
||||
{ __typename?: 'BrowserSession', id: string }
|
||||
& { ' $fragmentRefs'?: { 'BrowserSession_SessionFragment': BrowserSession_SessionFragment } }
|
||||
) | null } };
|
||||
export type BrowserSession_SessionFragment = (
|
||||
{ __typename?: 'BrowserSession', id: string, createdAt: string, finishedAt?: string | null, lastActiveAt?: string | null, userAgent?: { __typename?: 'UserAgent', deviceType: DeviceType, name?: string | null, os?: string | null, model?: string | null } | null }
|
||||
& { ' $fragmentRefs'?: { 'EndBrowserSessionButton_SessionFragment': EndBrowserSessionButton_SessionFragment } }
|
||||
) & { ' $fragmentName'?: 'BrowserSession_SessionFragment' };
|
||||
|
||||
export type OAuth2Client_DetailFragment = { __typename?: 'Oauth2Client', id: string, clientId: string, clientName?: string | null, clientUri?: string | null, logoUri?: string | null, tosUri?: string | null, policyUri?: string | null, redirectUris: Array<string> } & { ' $fragmentName'?: 'OAuth2Client_DetailFragment' };
|
||||
|
||||
export type CompatSession_SessionFragment = { __typename?: 'CompatSession', id: string, createdAt: string, deviceId?: string | null, finishedAt?: string | null, lastActiveIp?: string | null, lastActiveAt?: string | null, userAgent?: { __typename?: 'UserAgent', name?: string | null, os?: string | null, model?: string | null, deviceType: DeviceType } | null, ssoLogin?: { __typename?: 'CompatSsoLogin', id: string, redirectUri: string } | null } & { ' $fragmentName'?: 'CompatSession_SessionFragment' };
|
||||
|
||||
export type EndCompatSessionMutationVariables = Exact<{
|
||||
id: Scalars['ID']['input'];
|
||||
}>;
|
||||
|
||||
|
||||
export type EndCompatSessionMutation = { __typename?: 'Mutation', endCompatSession: { __typename?: 'EndCompatSessionPayload', status: EndCompatSessionStatus, compatSession?: { __typename?: 'CompatSession', id: string } | null } };
|
||||
export type CompatSession_SessionFragment = (
|
||||
{ __typename?: 'CompatSession', id: string, createdAt: string, deviceId?: string | null, finishedAt?: string | null, lastActiveIp?: string | null, lastActiveAt?: string | null, userAgent?: { __typename?: 'UserAgent', name?: string | null, os?: string | null, model?: string | null, deviceType: DeviceType } | null, ssoLogin?: { __typename?: 'CompatSsoLogin', id: string, redirectUri: string } | null }
|
||||
& { ' $fragmentRefs'?: { 'EndCompatSessionButton_SessionFragment': EndCompatSessionButton_SessionFragment } }
|
||||
) & { ' $fragmentName'?: 'CompatSession_SessionFragment' };
|
||||
|
||||
export type Footer_SiteConfigFragment = { __typename?: 'SiteConfig', id: string, imprint?: string | null, tosUri?: string | null, policyUri?: string | null } & { ' $fragmentName'?: 'Footer_SiteConfigFragment' };
|
||||
|
||||
@@ -1598,7 +1587,32 @@ export type FooterQuery = { __typename?: 'Query', siteConfig: (
|
||||
& { ' $fragmentRefs'?: { 'Footer_SiteConfigFragment': Footer_SiteConfigFragment } }
|
||||
) };
|
||||
|
||||
export type OAuth2Session_SessionFragment = { __typename?: 'Oauth2Session', id: string, scope: string, createdAt: string, finishedAt?: string | null, lastActiveIp?: string | null, lastActiveAt?: string | null, userAgent?: { __typename?: 'UserAgent', name?: string | null, model?: string | null, os?: string | null, deviceType: DeviceType } | null, client: { __typename?: 'Oauth2Client', id: string, clientId: string, clientName?: string | null, applicationType?: Oauth2ApplicationType | null, logoUri?: string | null } } & { ' $fragmentName'?: 'OAuth2Session_SessionFragment' };
|
||||
export type OAuth2Session_SessionFragment = (
|
||||
{ __typename?: 'Oauth2Session', id: string, scope: string, createdAt: string, finishedAt?: string | null, lastActiveIp?: string | null, lastActiveAt?: string | null, userAgent?: { __typename?: 'UserAgent', name?: string | null, model?: string | null, os?: string | null, deviceType: DeviceType } | null, client: { __typename?: 'Oauth2Client', id: string, clientId: string, clientName?: string | null, applicationType?: Oauth2ApplicationType | null, logoUri?: string | null } }
|
||||
& { ' $fragmentRefs'?: { 'EndOAuth2SessionButton_SessionFragment': EndOAuth2SessionButton_SessionFragment } }
|
||||
) & { ' $fragmentName'?: 'OAuth2Session_SessionFragment' };
|
||||
|
||||
export type PasswordCreationDoubleInput_SiteConfigFragment = { __typename?: 'SiteConfig', id: string, minimumPasswordComplexity: number } & { ' $fragmentName'?: 'PasswordCreationDoubleInput_SiteConfigFragment' };
|
||||
|
||||
export type EndBrowserSessionButton_SessionFragment = { __typename?: 'BrowserSession', id: string, userAgent?: { __typename?: 'UserAgent', name?: string | null, os?: string | null, model?: string | null, deviceType: DeviceType } | null } & { ' $fragmentName'?: 'EndBrowserSessionButton_SessionFragment' };
|
||||
|
||||
export type EndBrowserSessionMutationVariables = Exact<{
|
||||
id: Scalars['ID']['input'];
|
||||
}>;
|
||||
|
||||
|
||||
export type EndBrowserSessionMutation = { __typename?: 'Mutation', endBrowserSession: { __typename?: 'EndBrowserSessionPayload', status: EndBrowserSessionStatus, browserSession?: { __typename?: 'BrowserSession', id: string } | null } };
|
||||
|
||||
export type EndCompatSessionButton_SessionFragment = { __typename?: 'CompatSession', id: string, userAgent?: { __typename?: 'UserAgent', name?: string | null, os?: string | null, model?: string | null, deviceType: DeviceType } | null, ssoLogin?: { __typename?: 'CompatSsoLogin', id: string, redirectUri: string } | null } & { ' $fragmentName'?: 'EndCompatSessionButton_SessionFragment' };
|
||||
|
||||
export type EndCompatSessionMutationVariables = Exact<{
|
||||
id: Scalars['ID']['input'];
|
||||
}>;
|
||||
|
||||
|
||||
export type EndCompatSessionMutation = { __typename?: 'Mutation', endCompatSession: { __typename?: 'EndCompatSessionPayload', status: EndCompatSessionStatus, compatSession?: { __typename?: 'CompatSession', id: string } | null } };
|
||||
|
||||
export type EndOAuth2SessionButton_SessionFragment = { __typename?: 'Oauth2Session', id: string, userAgent?: { __typename?: 'UserAgent', name?: string | null, model?: string | null, os?: string | null, deviceType: DeviceType } | null, client: { __typename?: 'Oauth2Client', clientId: string, clientName?: string | null, applicationType?: Oauth2ApplicationType | null, logoUri?: string | null } } & { ' $fragmentName'?: 'EndOAuth2SessionButton_SessionFragment' };
|
||||
|
||||
export type EndOAuth2SessionMutationVariables = Exact<{
|
||||
id: Scalars['ID']['input'];
|
||||
@@ -1607,13 +1621,20 @@ export type EndOAuth2SessionMutationVariables = Exact<{
|
||||
|
||||
export type EndOAuth2SessionMutation = { __typename?: 'Mutation', endOauth2Session: { __typename?: 'EndOAuth2SessionPayload', status: EndOAuth2SessionStatus, oauth2Session?: { __typename?: 'Oauth2Session', id: string } | null } };
|
||||
|
||||
export type PasswordCreationDoubleInput_SiteConfigFragment = { __typename?: 'SiteConfig', id: string, minimumPasswordComplexity: number } & { ' $fragmentName'?: 'PasswordCreationDoubleInput_SiteConfigFragment' };
|
||||
export type BrowserSession_DetailFragment = (
|
||||
{ __typename?: 'BrowserSession', id: string, createdAt: string, finishedAt?: string | null, lastActiveIp?: string | null, lastActiveAt?: string | null, userAgent?: { __typename?: 'UserAgent', name?: string | null, model?: string | null, os?: string | null } | null, lastAuthentication?: { __typename?: 'Authentication', id: string, createdAt: string } | null, user: { __typename?: 'User', id: string, username: string } }
|
||||
& { ' $fragmentRefs'?: { 'EndBrowserSessionButton_SessionFragment': EndBrowserSessionButton_SessionFragment } }
|
||||
) & { ' $fragmentName'?: 'BrowserSession_DetailFragment' };
|
||||
|
||||
export type BrowserSession_DetailFragment = { __typename?: 'BrowserSession', id: string, createdAt: string, finishedAt?: string | null, lastActiveIp?: string | null, lastActiveAt?: string | null, userAgent?: { __typename?: 'UserAgent', name?: string | null, model?: string | null, os?: string | null } | null, lastAuthentication?: { __typename?: 'Authentication', id: string, createdAt: string } | null, user: { __typename?: 'User', id: string, username: string } } & { ' $fragmentName'?: 'BrowserSession_DetailFragment' };
|
||||
export type CompatSession_DetailFragment = (
|
||||
{ __typename?: 'CompatSession', id: string, createdAt: string, deviceId?: string | null, finishedAt?: string | null, lastActiveIp?: string | null, lastActiveAt?: string | null, userAgent?: { __typename?: 'UserAgent', name?: string | null, os?: string | null, model?: string | null } | null, ssoLogin?: { __typename?: 'CompatSsoLogin', id: string, redirectUri: string } | null }
|
||||
& { ' $fragmentRefs'?: { 'EndCompatSessionButton_SessionFragment': EndCompatSessionButton_SessionFragment } }
|
||||
) & { ' $fragmentName'?: 'CompatSession_DetailFragment' };
|
||||
|
||||
export type CompatSession_DetailFragment = { __typename?: 'CompatSession', id: string, createdAt: string, deviceId?: string | null, finishedAt?: string | null, lastActiveIp?: string | null, lastActiveAt?: string | null, userAgent?: { __typename?: 'UserAgent', name?: string | null, os?: string | null, model?: string | null } | null, ssoLogin?: { __typename?: 'CompatSsoLogin', id: string, redirectUri: string } | null } & { ' $fragmentName'?: 'CompatSession_DetailFragment' };
|
||||
|
||||
export type OAuth2Session_DetailFragment = { __typename?: 'Oauth2Session', id: string, scope: string, createdAt: string, finishedAt?: string | null, lastActiveIp?: string | null, lastActiveAt?: string | null, client: { __typename?: 'Oauth2Client', id: string, clientId: string, clientName?: string | null, clientUri?: string | null, logoUri?: string | null } } & { ' $fragmentName'?: 'OAuth2Session_DetailFragment' };
|
||||
export type OAuth2Session_DetailFragment = (
|
||||
{ __typename?: 'Oauth2Session', id: string, scope: string, createdAt: string, finishedAt?: string | null, lastActiveIp?: string | null, lastActiveAt?: string | null, userAgent?: { __typename?: 'UserAgent', name?: string | null, model?: string | null, os?: string | null } | null, client: { __typename?: 'Oauth2Client', id: string, clientId: string, clientName?: string | null, clientUri?: string | null, logoUri?: string | null } }
|
||||
& { ' $fragmentRefs'?: { 'EndOAuth2SessionButton_SessionFragment': EndOAuth2SessionButton_SessionFragment } }
|
||||
) & { ' $fragmentName'?: 'OAuth2Session_DetailFragment' };
|
||||
|
||||
export type UserEmail_EmailFragment = { __typename?: 'UserEmail', id: string, email: string } & { ' $fragmentName'?: 'UserEmail_EmailFragment' };
|
||||
|
||||
@@ -1666,27 +1687,11 @@ export type BrowserSessionsOverview_UserFragment = { __typename?: 'User', id: st
|
||||
export type UserProfileQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type UserProfileQuery = { __typename?: 'Query', viewer: { __typename: 'Anonymous' } | { __typename: 'User', emails: { __typename?: 'UserEmailConnection', totalCount: number } }, siteConfig: (
|
||||
export type UserProfileQuery = { __typename?: 'Query', viewerSession: { __typename: 'Anonymous' } | { __typename: 'BrowserSession', id: string, user: { __typename?: 'User', emails: { __typename?: 'UserEmailConnection', totalCount: number } } } | { __typename: 'Oauth2Session' }, siteConfig: (
|
||||
{ __typename?: 'SiteConfig', emailChangeAllowed: boolean, passwordLoginEnabled: boolean }
|
||||
& { ' $fragmentRefs'?: { 'UserEmailList_SiteConfigFragment': UserEmailList_SiteConfigFragment;'UserEmail_SiteConfigFragment': UserEmail_SiteConfigFragment;'PasswordChange_SiteConfigFragment': PasswordChange_SiteConfigFragment } }
|
||||
) };
|
||||
|
||||
export type SessionDetailQueryVariables = Exact<{
|
||||
id: Scalars['ID']['input'];
|
||||
}>;
|
||||
|
||||
|
||||
export type SessionDetailQuery = { __typename?: 'Query', viewerSession: { __typename?: 'Anonymous', id: string } | { __typename?: 'BrowserSession', id: string } | { __typename?: 'Oauth2Session', id: string }, node?: { __typename: 'Anonymous', id: string } | { __typename: 'Authentication', id: string } | (
|
||||
{ __typename: 'BrowserSession', id: string }
|
||||
& { ' $fragmentRefs'?: { 'BrowserSession_DetailFragment': BrowserSession_DetailFragment } }
|
||||
) | (
|
||||
{ __typename: 'CompatSession', id: string }
|
||||
& { ' $fragmentRefs'?: { 'CompatSession_DetailFragment': CompatSession_DetailFragment } }
|
||||
) | { __typename: 'CompatSsoLogin', id: string } | { __typename: 'Oauth2Client', id: string } | (
|
||||
{ __typename: 'Oauth2Session', id: string }
|
||||
& { ' $fragmentRefs'?: { 'OAuth2Session_DetailFragment': OAuth2Session_DetailFragment } }
|
||||
) | { __typename: 'SiteConfig', id: string } | { __typename: 'UpstreamOAuth2Link', id: string } | { __typename: 'UpstreamOAuth2Provider', id: string } | { __typename: 'User', id: string } | { __typename: 'UserEmail', id: string } | { __typename: 'UserEmailAuthentication', id: string } | { __typename: 'UserRecoveryTicket', id: string } | null };
|
||||
|
||||
export type BrowserSessionListQueryVariables = Exact<{
|
||||
first?: InputMaybe<Scalars['Int']['input']>;
|
||||
after?: InputMaybe<Scalars['String']['input']>;
|
||||
@@ -1729,10 +1734,10 @@ export type AppSessionsListQuery = { __typename?: 'Query', viewer: { __typename:
|
||||
export type CurrentUserGreetingQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type CurrentUserGreetingQuery = { __typename?: 'Query', viewerSession: { __typename: 'Anonymous' } | { __typename: 'BrowserSession', id: string, user: (
|
||||
{ __typename?: 'User' }
|
||||
& { ' $fragmentRefs'?: { 'UserGreeting_UserFragment': UserGreeting_UserFragment } }
|
||||
) } | { __typename: 'Oauth2Session' }, siteConfig: (
|
||||
export type CurrentUserGreetingQuery = { __typename?: 'Query', viewer: { __typename: 'Anonymous' } | (
|
||||
{ __typename: 'User' }
|
||||
& { ' $fragmentRefs'?: { 'UserGreeting_UserFragment': UserGreeting_UserFragment } }
|
||||
), siteConfig: (
|
||||
{ __typename?: 'SiteConfig' }
|
||||
& { ' $fragmentRefs'?: { 'UserGreeting_SiteConfigFragment': UserGreeting_SiteConfigFragment } }
|
||||
) };
|
||||
@@ -1842,6 +1847,22 @@ export type AllowCrossSigningResetMutationVariables = Exact<{
|
||||
|
||||
export type AllowCrossSigningResetMutation = { __typename?: 'Mutation', allowUserCrossSigningReset: { __typename?: 'AllowUserCrossSigningResetPayload', user?: { __typename?: 'User', id: string } | null } };
|
||||
|
||||
export type SessionDetailQueryVariables = Exact<{
|
||||
id: Scalars['ID']['input'];
|
||||
}>;
|
||||
|
||||
|
||||
export type SessionDetailQuery = { __typename?: 'Query', viewerSession: { __typename?: 'Anonymous', id: string } | { __typename?: 'BrowserSession', id: string } | { __typename?: 'Oauth2Session', id: string }, node?: { __typename: 'Anonymous', id: string } | { __typename: 'Authentication', id: string } | (
|
||||
{ __typename: 'BrowserSession', id: string }
|
||||
& { ' $fragmentRefs'?: { 'BrowserSession_DetailFragment': BrowserSession_DetailFragment } }
|
||||
) | (
|
||||
{ __typename: 'CompatSession', id: string }
|
||||
& { ' $fragmentRefs'?: { 'CompatSession_DetailFragment': CompatSession_DetailFragment } }
|
||||
) | { __typename: 'CompatSsoLogin', id: string } | { __typename: 'Oauth2Client', id: string } | (
|
||||
{ __typename: 'Oauth2Session', id: string }
|
||||
& { ' $fragmentRefs'?: { 'OAuth2Session_DetailFragment': OAuth2Session_DetailFragment } }
|
||||
) | { __typename: 'SiteConfig', id: string } | { __typename: 'UpstreamOAuth2Link', id: string } | { __typename: 'UpstreamOAuth2Provider', id: string } | { __typename: 'User', id: string } | { __typename: 'UserEmail', id: string } | { __typename: 'UserEmailAuthentication', id: string } | { __typename: 'UserRecoveryTicket', id: string } | null };
|
||||
|
||||
export class TypedDocumentString<TResult, TVariables>
|
||||
extends String
|
||||
implements DocumentTypeDecoration<TResult, TVariables>
|
||||
@@ -1861,26 +1882,40 @@ export const PasswordChange_SiteConfigFragmentDoc = new TypedDocumentString(`
|
||||
passwordChangeAllowed
|
||||
}
|
||||
`, {"fragmentName":"PasswordChange_siteConfig"}) as unknown as TypedDocumentString<PasswordChange_SiteConfigFragment, unknown>;
|
||||
export const BrowserSession_SessionFragmentDoc = new TypedDocumentString(`
|
||||
fragment BrowserSession_session on BrowserSession {
|
||||
export const EndBrowserSessionButton_SessionFragmentDoc = new TypedDocumentString(`
|
||||
fragment EndBrowserSessionButton_session on BrowserSession {
|
||||
id
|
||||
createdAt
|
||||
finishedAt
|
||||
userAgent {
|
||||
raw
|
||||
name
|
||||
os
|
||||
model
|
||||
deviceType
|
||||
}
|
||||
lastActiveIp
|
||||
lastActiveAt
|
||||
lastAuthentication {
|
||||
id
|
||||
createdAt
|
||||
}
|
||||
}
|
||||
`, {"fragmentName":"BrowserSession_session"}) as unknown as TypedDocumentString<BrowserSession_SessionFragment, unknown>;
|
||||
`, {"fragmentName":"EndBrowserSessionButton_session"}) as unknown as TypedDocumentString<EndBrowserSessionButton_SessionFragment, unknown>;
|
||||
export const BrowserSession_SessionFragmentDoc = new TypedDocumentString(`
|
||||
fragment BrowserSession_session on BrowserSession {
|
||||
id
|
||||
createdAt
|
||||
finishedAt
|
||||
...EndBrowserSessionButton_session
|
||||
userAgent {
|
||||
deviceType
|
||||
name
|
||||
os
|
||||
model
|
||||
}
|
||||
lastActiveAt
|
||||
}
|
||||
fragment EndBrowserSessionButton_session on BrowserSession {
|
||||
id
|
||||
userAgent {
|
||||
name
|
||||
os
|
||||
model
|
||||
deviceType
|
||||
}
|
||||
}`, {"fragmentName":"BrowserSession_session"}) as unknown as TypedDocumentString<BrowserSession_SessionFragment, unknown>;
|
||||
export const OAuth2Client_DetailFragmentDoc = new TypedDocumentString(`
|
||||
fragment OAuth2Client_detail on Oauth2Client {
|
||||
id
|
||||
@@ -1893,14 +1928,9 @@ export const OAuth2Client_DetailFragmentDoc = new TypedDocumentString(`
|
||||
redirectUris
|
||||
}
|
||||
`, {"fragmentName":"OAuth2Client_detail"}) as unknown as TypedDocumentString<OAuth2Client_DetailFragment, unknown>;
|
||||
export const CompatSession_SessionFragmentDoc = new TypedDocumentString(`
|
||||
fragment CompatSession_session on CompatSession {
|
||||
export const EndCompatSessionButton_SessionFragmentDoc = new TypedDocumentString(`
|
||||
fragment EndCompatSessionButton_session on CompatSession {
|
||||
id
|
||||
createdAt
|
||||
deviceId
|
||||
finishedAt
|
||||
lastActiveIp
|
||||
lastActiveAt
|
||||
userAgent {
|
||||
name
|
||||
os
|
||||
@@ -1912,7 +1942,40 @@ export const CompatSession_SessionFragmentDoc = new TypedDocumentString(`
|
||||
redirectUri
|
||||
}
|
||||
}
|
||||
`, {"fragmentName":"CompatSession_session"}) as unknown as TypedDocumentString<CompatSession_SessionFragment, unknown>;
|
||||
`, {"fragmentName":"EndCompatSessionButton_session"}) as unknown as TypedDocumentString<EndCompatSessionButton_SessionFragment, unknown>;
|
||||
export const CompatSession_SessionFragmentDoc = new TypedDocumentString(`
|
||||
fragment CompatSession_session on CompatSession {
|
||||
id
|
||||
createdAt
|
||||
deviceId
|
||||
finishedAt
|
||||
lastActiveIp
|
||||
lastActiveAt
|
||||
...EndCompatSessionButton_session
|
||||
userAgent {
|
||||
name
|
||||
os
|
||||
model
|
||||
deviceType
|
||||
}
|
||||
ssoLogin {
|
||||
id
|
||||
redirectUri
|
||||
}
|
||||
}
|
||||
fragment EndCompatSessionButton_session on CompatSession {
|
||||
id
|
||||
userAgent {
|
||||
name
|
||||
os
|
||||
model
|
||||
deviceType
|
||||
}
|
||||
ssoLogin {
|
||||
id
|
||||
redirectUri
|
||||
}
|
||||
}`, {"fragmentName":"CompatSession_session"}) as unknown as TypedDocumentString<CompatSession_SessionFragment, unknown>;
|
||||
export const Footer_SiteConfigFragmentDoc = new TypedDocumentString(`
|
||||
fragment Footer_siteConfig on SiteConfig {
|
||||
id
|
||||
@@ -1921,6 +1984,23 @@ export const Footer_SiteConfigFragmentDoc = new TypedDocumentString(`
|
||||
policyUri
|
||||
}
|
||||
`, {"fragmentName":"Footer_siteConfig"}) as unknown as TypedDocumentString<Footer_SiteConfigFragment, unknown>;
|
||||
export const EndOAuth2SessionButton_SessionFragmentDoc = new TypedDocumentString(`
|
||||
fragment EndOAuth2SessionButton_session on Oauth2Session {
|
||||
id
|
||||
userAgent {
|
||||
name
|
||||
model
|
||||
os
|
||||
deviceType
|
||||
}
|
||||
client {
|
||||
clientId
|
||||
clientName
|
||||
applicationType
|
||||
logoUri
|
||||
}
|
||||
}
|
||||
`, {"fragmentName":"EndOAuth2SessionButton_session"}) as unknown as TypedDocumentString<EndOAuth2SessionButton_SessionFragment, unknown>;
|
||||
export const OAuth2Session_SessionFragmentDoc = new TypedDocumentString(`
|
||||
fragment OAuth2Session_session on Oauth2Session {
|
||||
id
|
||||
@@ -1929,6 +2009,7 @@ export const OAuth2Session_SessionFragmentDoc = new TypedDocumentString(`
|
||||
finishedAt
|
||||
lastActiveIp
|
||||
lastActiveAt
|
||||
...EndOAuth2SessionButton_session
|
||||
userAgent {
|
||||
name
|
||||
model
|
||||
@@ -1943,12 +2024,27 @@ export const OAuth2Session_SessionFragmentDoc = new TypedDocumentString(`
|
||||
logoUri
|
||||
}
|
||||
}
|
||||
`, {"fragmentName":"OAuth2Session_session"}) as unknown as TypedDocumentString<OAuth2Session_SessionFragment, unknown>;
|
||||
fragment EndOAuth2SessionButton_session on Oauth2Session {
|
||||
id
|
||||
userAgent {
|
||||
name
|
||||
model
|
||||
os
|
||||
deviceType
|
||||
}
|
||||
client {
|
||||
clientId
|
||||
clientName
|
||||
applicationType
|
||||
logoUri
|
||||
}
|
||||
}`, {"fragmentName":"OAuth2Session_session"}) as unknown as TypedDocumentString<OAuth2Session_SessionFragment, unknown>;
|
||||
export const BrowserSession_DetailFragmentDoc = new TypedDocumentString(`
|
||||
fragment BrowserSession_detail on BrowserSession {
|
||||
id
|
||||
createdAt
|
||||
finishedAt
|
||||
...EndBrowserSessionButton_session
|
||||
userAgent {
|
||||
name
|
||||
model
|
||||
@@ -1965,7 +2061,15 @@ export const BrowserSession_DetailFragmentDoc = new TypedDocumentString(`
|
||||
username
|
||||
}
|
||||
}
|
||||
`, {"fragmentName":"BrowserSession_detail"}) as unknown as TypedDocumentString<BrowserSession_DetailFragment, unknown>;
|
||||
fragment EndBrowserSessionButton_session on BrowserSession {
|
||||
id
|
||||
userAgent {
|
||||
name
|
||||
os
|
||||
model
|
||||
deviceType
|
||||
}
|
||||
}`, {"fragmentName":"BrowserSession_detail"}) as unknown as TypedDocumentString<BrowserSession_DetailFragment, unknown>;
|
||||
export const CompatSession_DetailFragmentDoc = new TypedDocumentString(`
|
||||
fragment CompatSession_detail on CompatSession {
|
||||
id
|
||||
@@ -1974,6 +2078,7 @@ export const CompatSession_DetailFragmentDoc = new TypedDocumentString(`
|
||||
finishedAt
|
||||
lastActiveIp
|
||||
lastActiveAt
|
||||
...EndCompatSessionButton_session
|
||||
userAgent {
|
||||
name
|
||||
os
|
||||
@@ -1984,7 +2089,19 @@ export const CompatSession_DetailFragmentDoc = new TypedDocumentString(`
|
||||
redirectUri
|
||||
}
|
||||
}
|
||||
`, {"fragmentName":"CompatSession_detail"}) as unknown as TypedDocumentString<CompatSession_DetailFragment, unknown>;
|
||||
fragment EndCompatSessionButton_session on CompatSession {
|
||||
id
|
||||
userAgent {
|
||||
name
|
||||
os
|
||||
model
|
||||
deviceType
|
||||
}
|
||||
ssoLogin {
|
||||
id
|
||||
redirectUri
|
||||
}
|
||||
}`, {"fragmentName":"CompatSession_detail"}) as unknown as TypedDocumentString<CompatSession_DetailFragment, unknown>;
|
||||
export const OAuth2Session_DetailFragmentDoc = new TypedDocumentString(`
|
||||
fragment OAuth2Session_detail on Oauth2Session {
|
||||
id
|
||||
@@ -1993,6 +2110,12 @@ export const OAuth2Session_DetailFragmentDoc = new TypedDocumentString(`
|
||||
finishedAt
|
||||
lastActiveIp
|
||||
lastActiveAt
|
||||
...EndOAuth2SessionButton_session
|
||||
userAgent {
|
||||
name
|
||||
model
|
||||
os
|
||||
}
|
||||
client {
|
||||
id
|
||||
clientId
|
||||
@@ -2001,7 +2124,21 @@ export const OAuth2Session_DetailFragmentDoc = new TypedDocumentString(`
|
||||
logoUri
|
||||
}
|
||||
}
|
||||
`, {"fragmentName":"OAuth2Session_detail"}) as unknown as TypedDocumentString<OAuth2Session_DetailFragment, unknown>;
|
||||
fragment EndOAuth2SessionButton_session on Oauth2Session {
|
||||
id
|
||||
userAgent {
|
||||
name
|
||||
model
|
||||
os
|
||||
deviceType
|
||||
}
|
||||
client {
|
||||
clientId
|
||||
clientName
|
||||
applicationType
|
||||
logoUri
|
||||
}
|
||||
}`, {"fragmentName":"OAuth2Session_detail"}) as unknown as TypedDocumentString<OAuth2Session_DetailFragment, unknown>;
|
||||
export const UserEmail_EmailFragmentDoc = new TypedDocumentString(`
|
||||
fragment UserEmail_email on UserEmail {
|
||||
id
|
||||
@@ -2060,44 +2197,6 @@ export const RecoverPassword_SiteConfigFragmentDoc = new TypedDocumentString(`
|
||||
id
|
||||
minimumPasswordComplexity
|
||||
}`, {"fragmentName":"RecoverPassword_siteConfig"}) as unknown as TypedDocumentString<RecoverPassword_SiteConfigFragment, unknown>;
|
||||
export const EndBrowserSessionDocument = new TypedDocumentString(`
|
||||
mutation EndBrowserSession($id: ID!) {
|
||||
endBrowserSession(input: {browserSessionId: $id}) {
|
||||
status
|
||||
browserSession {
|
||||
id
|
||||
...BrowserSession_session
|
||||
}
|
||||
}
|
||||
}
|
||||
fragment BrowserSession_session on BrowserSession {
|
||||
id
|
||||
createdAt
|
||||
finishedAt
|
||||
userAgent {
|
||||
raw
|
||||
name
|
||||
os
|
||||
model
|
||||
deviceType
|
||||
}
|
||||
lastActiveIp
|
||||
lastActiveAt
|
||||
lastAuthentication {
|
||||
id
|
||||
createdAt
|
||||
}
|
||||
}`) as unknown as TypedDocumentString<EndBrowserSessionMutation, EndBrowserSessionMutationVariables>;
|
||||
export const EndCompatSessionDocument = new TypedDocumentString(`
|
||||
mutation EndCompatSession($id: ID!) {
|
||||
endCompatSession(input: {compatSessionId: $id}) {
|
||||
status
|
||||
compatSession {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
`) as unknown as TypedDocumentString<EndCompatSessionMutation, EndCompatSessionMutationVariables>;
|
||||
export const FooterDocument = new TypedDocumentString(`
|
||||
query Footer {
|
||||
siteConfig {
|
||||
@@ -2111,6 +2210,26 @@ export const FooterDocument = new TypedDocumentString(`
|
||||
tosUri
|
||||
policyUri
|
||||
}`) as unknown as TypedDocumentString<FooterQuery, FooterQueryVariables>;
|
||||
export const EndBrowserSessionDocument = new TypedDocumentString(`
|
||||
mutation EndBrowserSession($id: ID!) {
|
||||
endBrowserSession(input: {browserSessionId: $id}) {
|
||||
status
|
||||
browserSession {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
`) as unknown as TypedDocumentString<EndBrowserSessionMutation, EndBrowserSessionMutationVariables>;
|
||||
export const EndCompatSessionDocument = new TypedDocumentString(`
|
||||
mutation EndCompatSession($id: ID!) {
|
||||
endCompatSession(input: {compatSessionId: $id}) {
|
||||
status
|
||||
compatSession {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
`) as unknown as TypedDocumentString<EndCompatSessionMutation, EndCompatSessionMutationVariables>;
|
||||
export const EndOAuth2SessionDocument = new TypedDocumentString(`
|
||||
mutation EndOAuth2Session($id: ID!) {
|
||||
endOauth2Session(input: {oauth2SessionId: $id}) {
|
||||
@@ -2178,11 +2297,14 @@ export const UserEmailListDocument = new TypedDocumentString(`
|
||||
}`) as unknown as TypedDocumentString<UserEmailListQuery, UserEmailListQueryVariables>;
|
||||
export const UserProfileDocument = new TypedDocumentString(`
|
||||
query UserProfile {
|
||||
viewer {
|
||||
viewerSession {
|
||||
__typename
|
||||
... on User {
|
||||
emails(first: 0) {
|
||||
totalCount
|
||||
... on BrowserSession {
|
||||
id
|
||||
user {
|
||||
emails(first: 0) {
|
||||
totalCount
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2203,73 +2325,6 @@ fragment UserEmail_siteConfig on SiteConfig {
|
||||
fragment UserEmailList_siteConfig on SiteConfig {
|
||||
emailChangeAllowed
|
||||
}`) as unknown as TypedDocumentString<UserProfileQuery, UserProfileQueryVariables>;
|
||||
export const SessionDetailDocument = new TypedDocumentString(`
|
||||
query SessionDetail($id: ID!) {
|
||||
viewerSession {
|
||||
... on Node {
|
||||
id
|
||||
}
|
||||
}
|
||||
node(id: $id) {
|
||||
__typename
|
||||
id
|
||||
...CompatSession_detail
|
||||
...OAuth2Session_detail
|
||||
...BrowserSession_detail
|
||||
}
|
||||
}
|
||||
fragment BrowserSession_detail on BrowserSession {
|
||||
id
|
||||
createdAt
|
||||
finishedAt
|
||||
userAgent {
|
||||
name
|
||||
model
|
||||
os
|
||||
}
|
||||
lastActiveIp
|
||||
lastActiveAt
|
||||
lastAuthentication {
|
||||
id
|
||||
createdAt
|
||||
}
|
||||
user {
|
||||
id
|
||||
username
|
||||
}
|
||||
}
|
||||
fragment CompatSession_detail on CompatSession {
|
||||
id
|
||||
createdAt
|
||||
deviceId
|
||||
finishedAt
|
||||
lastActiveIp
|
||||
lastActiveAt
|
||||
userAgent {
|
||||
name
|
||||
os
|
||||
model
|
||||
}
|
||||
ssoLogin {
|
||||
id
|
||||
redirectUri
|
||||
}
|
||||
}
|
||||
fragment OAuth2Session_detail on Oauth2Session {
|
||||
id
|
||||
scope
|
||||
createdAt
|
||||
finishedAt
|
||||
lastActiveIp
|
||||
lastActiveAt
|
||||
client {
|
||||
id
|
||||
clientId
|
||||
clientName
|
||||
clientUri
|
||||
logoUri
|
||||
}
|
||||
}`) as unknown as TypedDocumentString<SessionDetailQuery, SessionDetailQueryVariables>;
|
||||
export const BrowserSessionListDocument = new TypedDocumentString(`
|
||||
query BrowserSessionList($first: Int, $after: String, $last: Int, $before: String, $lastActive: DateFilter) {
|
||||
viewerSession {
|
||||
@@ -2309,19 +2364,23 @@ export const BrowserSessionListDocument = new TypedDocumentString(`
|
||||
id
|
||||
createdAt
|
||||
finishedAt
|
||||
...EndBrowserSessionButton_session
|
||||
userAgent {
|
||||
deviceType
|
||||
name
|
||||
os
|
||||
model
|
||||
}
|
||||
lastActiveAt
|
||||
}
|
||||
fragment EndBrowserSessionButton_session on BrowserSession {
|
||||
id
|
||||
userAgent {
|
||||
raw
|
||||
name
|
||||
os
|
||||
model
|
||||
deviceType
|
||||
}
|
||||
lastActiveIp
|
||||
lastActiveAt
|
||||
lastAuthentication {
|
||||
id
|
||||
createdAt
|
||||
}
|
||||
}`) as unknown as TypedDocumentString<BrowserSessionListQuery, BrowserSessionListQueryVariables>;
|
||||
export const SessionsOverviewDocument = new TypedDocumentString(`
|
||||
query SessionsOverview {
|
||||
@@ -2379,6 +2438,7 @@ export const AppSessionsListDocument = new TypedDocumentString(`
|
||||
finishedAt
|
||||
lastActiveIp
|
||||
lastActiveAt
|
||||
...EndCompatSessionButton_session
|
||||
userAgent {
|
||||
name
|
||||
os
|
||||
@@ -2397,6 +2457,7 @@ fragment OAuth2Session_session on Oauth2Session {
|
||||
finishedAt
|
||||
lastActiveIp
|
||||
lastActiveAt
|
||||
...EndOAuth2SessionButton_session
|
||||
userAgent {
|
||||
name
|
||||
model
|
||||
@@ -2410,16 +2471,41 @@ fragment OAuth2Session_session on Oauth2Session {
|
||||
applicationType
|
||||
logoUri
|
||||
}
|
||||
}
|
||||
fragment EndCompatSessionButton_session on CompatSession {
|
||||
id
|
||||
userAgent {
|
||||
name
|
||||
os
|
||||
model
|
||||
deviceType
|
||||
}
|
||||
ssoLogin {
|
||||
id
|
||||
redirectUri
|
||||
}
|
||||
}
|
||||
fragment EndOAuth2SessionButton_session on Oauth2Session {
|
||||
id
|
||||
userAgent {
|
||||
name
|
||||
model
|
||||
os
|
||||
deviceType
|
||||
}
|
||||
client {
|
||||
clientId
|
||||
clientName
|
||||
applicationType
|
||||
logoUri
|
||||
}
|
||||
}`) as unknown as TypedDocumentString<AppSessionsListQuery, AppSessionsListQueryVariables>;
|
||||
export const CurrentUserGreetingDocument = new TypedDocumentString(`
|
||||
query CurrentUserGreeting {
|
||||
viewerSession {
|
||||
viewer {
|
||||
__typename
|
||||
... on BrowserSession {
|
||||
id
|
||||
user {
|
||||
...UserGreeting_user
|
||||
}
|
||||
... on User {
|
||||
...UserGreeting_user
|
||||
}
|
||||
}
|
||||
siteConfig {
|
||||
@@ -2565,6 +2651,139 @@ export const AllowCrossSigningResetDocument = new TypedDocumentString(`
|
||||
}
|
||||
}
|
||||
`) as unknown as TypedDocumentString<AllowCrossSigningResetMutation, AllowCrossSigningResetMutationVariables>;
|
||||
export const SessionDetailDocument = new TypedDocumentString(`
|
||||
query SessionDetail($id: ID!) {
|
||||
viewerSession {
|
||||
... on Node {
|
||||
id
|
||||
}
|
||||
}
|
||||
node(id: $id) {
|
||||
__typename
|
||||
id
|
||||
...CompatSession_detail
|
||||
...OAuth2Session_detail
|
||||
...BrowserSession_detail
|
||||
}
|
||||
}
|
||||
fragment EndBrowserSessionButton_session on BrowserSession {
|
||||
id
|
||||
userAgent {
|
||||
name
|
||||
os
|
||||
model
|
||||
deviceType
|
||||
}
|
||||
}
|
||||
fragment EndCompatSessionButton_session on CompatSession {
|
||||
id
|
||||
userAgent {
|
||||
name
|
||||
os
|
||||
model
|
||||
deviceType
|
||||
}
|
||||
ssoLogin {
|
||||
id
|
||||
redirectUri
|
||||
}
|
||||
}
|
||||
fragment EndOAuth2SessionButton_session on Oauth2Session {
|
||||
id
|
||||
userAgent {
|
||||
name
|
||||
model
|
||||
os
|
||||
deviceType
|
||||
}
|
||||
client {
|
||||
clientId
|
||||
clientName
|
||||
applicationType
|
||||
logoUri
|
||||
}
|
||||
}
|
||||
fragment BrowserSession_detail on BrowserSession {
|
||||
id
|
||||
createdAt
|
||||
finishedAt
|
||||
...EndBrowserSessionButton_session
|
||||
userAgent {
|
||||
name
|
||||
model
|
||||
os
|
||||
}
|
||||
lastActiveIp
|
||||
lastActiveAt
|
||||
lastAuthentication {
|
||||
id
|
||||
createdAt
|
||||
}
|
||||
user {
|
||||
id
|
||||
username
|
||||
}
|
||||
}
|
||||
fragment CompatSession_detail on CompatSession {
|
||||
id
|
||||
createdAt
|
||||
deviceId
|
||||
finishedAt
|
||||
lastActiveIp
|
||||
lastActiveAt
|
||||
...EndCompatSessionButton_session
|
||||
userAgent {
|
||||
name
|
||||
os
|
||||
model
|
||||
}
|
||||
ssoLogin {
|
||||
id
|
||||
redirectUri
|
||||
}
|
||||
}
|
||||
fragment OAuth2Session_detail on Oauth2Session {
|
||||
id
|
||||
scope
|
||||
createdAt
|
||||
finishedAt
|
||||
lastActiveIp
|
||||
lastActiveAt
|
||||
...EndOAuth2SessionButton_session
|
||||
userAgent {
|
||||
name
|
||||
model
|
||||
os
|
||||
}
|
||||
client {
|
||||
id
|
||||
clientId
|
||||
clientName
|
||||
clientUri
|
||||
logoUri
|
||||
}
|
||||
}`) as unknown as TypedDocumentString<SessionDetailQuery, SessionDetailQueryVariables>;
|
||||
|
||||
/**
|
||||
* @param resolver A function that accepts [resolver arguments](https://mswjs.io/docs/api/graphql#resolver-argument) and must always return the instruction on what to do with the intercepted request. ([see more](https://mswjs.io/docs/concepts/response-resolver#resolver-instructions))
|
||||
* @param options Options object to customize the behavior of the mock. ([see more](https://mswjs.io/docs/api/graphql#handler-options))
|
||||
* @see https://mswjs.io/docs/basics/response-resolver
|
||||
* @example
|
||||
* mockFooterQuery(
|
||||
* ({ query, variables }) => {
|
||||
* return HttpResponse.json({
|
||||
* data: { siteConfig }
|
||||
* })
|
||||
* },
|
||||
* requestOptions
|
||||
* )
|
||||
*/
|
||||
export const mockFooterQuery = (resolver: GraphQLResponseResolver<FooterQuery, FooterQueryVariables>, options?: RequestHandlerOptions) =>
|
||||
graphql.query<FooterQuery, FooterQueryVariables>(
|
||||
'Footer',
|
||||
resolver,
|
||||
options
|
||||
)
|
||||
|
||||
/**
|
||||
* @param resolver A function that accepts [resolver arguments](https://mswjs.io/docs/api/graphql#resolver-argument) and must always return the instruction on what to do with the intercepted request. ([see more](https://mswjs.io/docs/concepts/response-resolver#resolver-instructions))
|
||||
@@ -2610,27 +2829,6 @@ export const mockEndCompatSessionMutation = (resolver: GraphQLResponseResolver<E
|
||||
options
|
||||
)
|
||||
|
||||
/**
|
||||
* @param resolver A function that accepts [resolver arguments](https://mswjs.io/docs/api/graphql#resolver-argument) and must always return the instruction on what to do with the intercepted request. ([see more](https://mswjs.io/docs/concepts/response-resolver#resolver-instructions))
|
||||
* @param options Options object to customize the behavior of the mock. ([see more](https://mswjs.io/docs/api/graphql#handler-options))
|
||||
* @see https://mswjs.io/docs/basics/response-resolver
|
||||
* @example
|
||||
* mockFooterQuery(
|
||||
* ({ query, variables }) => {
|
||||
* return HttpResponse.json({
|
||||
* data: { siteConfig }
|
||||
* })
|
||||
* },
|
||||
* requestOptions
|
||||
* )
|
||||
*/
|
||||
export const mockFooterQuery = (resolver: GraphQLResponseResolver<FooterQuery, FooterQueryVariables>, options?: RequestHandlerOptions) =>
|
||||
graphql.query<FooterQuery, FooterQueryVariables>(
|
||||
'Footer',
|
||||
resolver,
|
||||
options
|
||||
)
|
||||
|
||||
/**
|
||||
* @param resolver A function that accepts [resolver arguments](https://mswjs.io/docs/api/graphql#resolver-argument) and must always return the instruction on what to do with the intercepted request. ([see more](https://mswjs.io/docs/concepts/response-resolver#resolver-instructions))
|
||||
* @param options Options object to customize the behavior of the mock. ([see more](https://mswjs.io/docs/api/graphql#handler-options))
|
||||
@@ -2749,7 +2947,7 @@ export const mockUserEmailListQuery = (resolver: GraphQLResponseResolver<UserEma
|
||||
* mockUserProfileQuery(
|
||||
* ({ query, variables }) => {
|
||||
* return HttpResponse.json({
|
||||
* data: { viewer, siteConfig }
|
||||
* data: { viewerSession, siteConfig }
|
||||
* })
|
||||
* },
|
||||
* requestOptions
|
||||
@@ -2762,28 +2960,6 @@ export const mockUserProfileQuery = (resolver: GraphQLResponseResolver<UserProfi
|
||||
options
|
||||
)
|
||||
|
||||
/**
|
||||
* @param resolver A function that accepts [resolver arguments](https://mswjs.io/docs/api/graphql#resolver-argument) and must always return the instruction on what to do with the intercepted request. ([see more](https://mswjs.io/docs/concepts/response-resolver#resolver-instructions))
|
||||
* @param options Options object to customize the behavior of the mock. ([see more](https://mswjs.io/docs/api/graphql#handler-options))
|
||||
* @see https://mswjs.io/docs/basics/response-resolver
|
||||
* @example
|
||||
* mockSessionDetailQuery(
|
||||
* ({ query, variables }) => {
|
||||
* const { id } = variables;
|
||||
* return HttpResponse.json({
|
||||
* data: { viewerSession, node }
|
||||
* })
|
||||
* },
|
||||
* requestOptions
|
||||
* )
|
||||
*/
|
||||
export const mockSessionDetailQuery = (resolver: GraphQLResponseResolver<SessionDetailQuery, SessionDetailQueryVariables>, options?: RequestHandlerOptions) =>
|
||||
graphql.query<SessionDetailQuery, SessionDetailQueryVariables>(
|
||||
'SessionDetail',
|
||||
resolver,
|
||||
options
|
||||
)
|
||||
|
||||
/**
|
||||
* @param resolver A function that accepts [resolver arguments](https://mswjs.io/docs/api/graphql#resolver-argument) and must always return the instruction on what to do with the intercepted request. ([see more](https://mswjs.io/docs/concepts/response-resolver#resolver-instructions))
|
||||
* @param options Options object to customize the behavior of the mock. ([see more](https://mswjs.io/docs/api/graphql#handler-options))
|
||||
@@ -2857,7 +3033,7 @@ export const mockAppSessionsListQuery = (resolver: GraphQLResponseResolver<AppSe
|
||||
* mockCurrentUserGreetingQuery(
|
||||
* ({ query, variables }) => {
|
||||
* return HttpResponse.json({
|
||||
* data: { viewerSession, siteConfig }
|
||||
* data: { viewer, siteConfig }
|
||||
* })
|
||||
* },
|
||||
* requestOptions
|
||||
@@ -3131,3 +3307,25 @@ export const mockAllowCrossSigningResetMutation = (resolver: GraphQLResponseReso
|
||||
resolver,
|
||||
options
|
||||
)
|
||||
|
||||
/**
|
||||
* @param resolver A function that accepts [resolver arguments](https://mswjs.io/docs/api/graphql#resolver-argument) and must always return the instruction on what to do with the intercepted request. ([see more](https://mswjs.io/docs/concepts/response-resolver#resolver-instructions))
|
||||
* @param options Options object to customize the behavior of the mock. ([see more](https://mswjs.io/docs/api/graphql#handler-options))
|
||||
* @see https://mswjs.io/docs/basics/response-resolver
|
||||
* @example
|
||||
* mockSessionDetailQuery(
|
||||
* ({ query, variables }) => {
|
||||
* const { id } = variables;
|
||||
* return HttpResponse.json({
|
||||
* data: { viewerSession, node }
|
||||
* })
|
||||
* },
|
||||
* requestOptions
|
||||
* )
|
||||
*/
|
||||
export const mockSessionDetailQuery = (resolver: GraphQLResponseResolver<SessionDetailQuery, SessionDetailQueryVariables>, options?: RequestHandlerOptions) =>
|
||||
graphql.query<SessionDetailQuery, SessionDetailQueryVariables>(
|
||||
'SessionDetail',
|
||||
resolver,
|
||||
options
|
||||
)
|
||||
|
||||
@@ -17,6 +17,7 @@ import { Route as ResetCrossSigningImport } from './routes/reset-cross-signing'
|
||||
import { Route as AccountImport } from './routes/_account'
|
||||
import { Route as ResetCrossSigningIndexImport } from './routes/reset-cross-signing.index'
|
||||
import { Route as AccountIndexImport } from './routes/_account.index'
|
||||
import { Route as SessionsIdImport } from './routes/sessions.$id'
|
||||
import { Route as ResetCrossSigningSuccessImport } from './routes/reset-cross-signing.success'
|
||||
import { Route as ResetCrossSigningCancelledImport } from './routes/reset-cross-signing.cancelled'
|
||||
import { Route as DevicesSplatImport } from './routes/devices.$'
|
||||
@@ -27,7 +28,6 @@ import { Route as AccountSessionsIndexImport } from './routes/_account.sessions.
|
||||
import { Route as EmailsIdVerifyImport } from './routes/emails.$id.verify'
|
||||
import { Route as EmailsIdInUseImport } from './routes/emails.$id.in-use'
|
||||
import { Route as AccountSessionsBrowsersImport } from './routes/_account.sessions.browsers'
|
||||
import { Route as AccountSessionsIdImport } from './routes/_account.sessions.$id'
|
||||
|
||||
// Create Virtual Routes
|
||||
|
||||
@@ -62,6 +62,12 @@ const AccountIndexRoute = AccountIndexImport.update({
|
||||
import('./routes/_account.index.lazy').then((d) => d.Route),
|
||||
)
|
||||
|
||||
const SessionsIdRoute = SessionsIdImport.update({
|
||||
id: '/sessions/$id',
|
||||
path: '/sessions/$id',
|
||||
getParentRoute: () => rootRoute,
|
||||
} as any).lazy(() => import('./routes/sessions.$id.lazy').then((d) => d.Route))
|
||||
|
||||
const ResetCrossSigningSuccessRoute = ResetCrossSigningSuccessImport.update({
|
||||
id: '/success',
|
||||
path: '/success',
|
||||
@@ -142,14 +148,6 @@ const AccountSessionsBrowsersRoute = AccountSessionsBrowsersImport.update({
|
||||
import('./routes/_account.sessions.browsers.lazy').then((d) => d.Route),
|
||||
)
|
||||
|
||||
const AccountSessionsIdRoute = AccountSessionsIdImport.update({
|
||||
id: '/sessions/$id',
|
||||
path: '/sessions/$id',
|
||||
getParentRoute: () => AccountRoute,
|
||||
} as any).lazy(() =>
|
||||
import('./routes/_account.sessions.$id.lazy').then((d) => d.Route),
|
||||
)
|
||||
|
||||
// Populate the FileRoutesByPath interface
|
||||
|
||||
declare module '@tanstack/react-router' {
|
||||
@@ -196,6 +194,13 @@ declare module '@tanstack/react-router' {
|
||||
preLoaderRoute: typeof ResetCrossSigningSuccessImport
|
||||
parentRoute: typeof ResetCrossSigningImport
|
||||
}
|
||||
'/sessions/$id': {
|
||||
id: '/sessions/$id'
|
||||
path: '/sessions/$id'
|
||||
fullPath: '/sessions/$id'
|
||||
preLoaderRoute: typeof SessionsIdImport
|
||||
parentRoute: typeof rootRoute
|
||||
}
|
||||
'/_account/': {
|
||||
id: '/_account/'
|
||||
path: '/'
|
||||
@@ -210,13 +215,6 @@ declare module '@tanstack/react-router' {
|
||||
preLoaderRoute: typeof ResetCrossSigningIndexImport
|
||||
parentRoute: typeof ResetCrossSigningImport
|
||||
}
|
||||
'/_account/sessions/$id': {
|
||||
id: '/_account/sessions/$id'
|
||||
path: '/sessions/$id'
|
||||
fullPath: '/sessions/$id'
|
||||
preLoaderRoute: typeof AccountSessionsIdImport
|
||||
parentRoute: typeof AccountImport
|
||||
}
|
||||
'/_account/sessions/browsers': {
|
||||
id: '/_account/sessions/browsers'
|
||||
path: '/sessions/browsers'
|
||||
@@ -273,14 +271,12 @@ declare module '@tanstack/react-router' {
|
||||
|
||||
interface AccountRouteChildren {
|
||||
AccountIndexRoute: typeof AccountIndexRoute
|
||||
AccountSessionsIdRoute: typeof AccountSessionsIdRoute
|
||||
AccountSessionsBrowsersRoute: typeof AccountSessionsBrowsersRoute
|
||||
AccountSessionsIndexRoute: typeof AccountSessionsIndexRoute
|
||||
}
|
||||
|
||||
const AccountRouteChildren: AccountRouteChildren = {
|
||||
AccountIndexRoute: AccountIndexRoute,
|
||||
AccountSessionsIdRoute: AccountSessionsIdRoute,
|
||||
AccountSessionsBrowsersRoute: AccountSessionsBrowsersRoute,
|
||||
AccountSessionsIndexRoute: AccountSessionsIndexRoute,
|
||||
}
|
||||
@@ -310,9 +306,9 @@ export interface FileRoutesByFullPath {
|
||||
'/devices/$': typeof DevicesSplatRoute
|
||||
'/reset-cross-signing/cancelled': typeof ResetCrossSigningCancelledRoute
|
||||
'/reset-cross-signing/success': typeof ResetCrossSigningSuccessRoute
|
||||
'/sessions/$id': typeof SessionsIdRoute
|
||||
'/': typeof AccountIndexRoute
|
||||
'/reset-cross-signing/': typeof ResetCrossSigningIndexRoute
|
||||
'/sessions/$id': typeof AccountSessionsIdRoute
|
||||
'/sessions/browsers': typeof AccountSessionsBrowsersRoute
|
||||
'/emails/$id/in-use': typeof EmailsIdInUseRoute
|
||||
'/emails/$id/verify': typeof EmailsIdVerifyRoute
|
||||
@@ -327,9 +323,9 @@ export interface FileRoutesByTo {
|
||||
'/devices/$': typeof DevicesSplatRoute
|
||||
'/reset-cross-signing/cancelled': typeof ResetCrossSigningCancelledRoute
|
||||
'/reset-cross-signing/success': typeof ResetCrossSigningSuccessRoute
|
||||
'/sessions/$id': typeof SessionsIdRoute
|
||||
'/': typeof AccountIndexRoute
|
||||
'/reset-cross-signing': typeof ResetCrossSigningIndexRoute
|
||||
'/sessions/$id': typeof AccountSessionsIdRoute
|
||||
'/sessions/browsers': typeof AccountSessionsBrowsersRoute
|
||||
'/emails/$id/in-use': typeof EmailsIdInUseRoute
|
||||
'/emails/$id/verify': typeof EmailsIdVerifyRoute
|
||||
@@ -347,9 +343,9 @@ export interface FileRoutesById {
|
||||
'/devices/$': typeof DevicesSplatRoute
|
||||
'/reset-cross-signing/cancelled': typeof ResetCrossSigningCancelledRoute
|
||||
'/reset-cross-signing/success': typeof ResetCrossSigningSuccessRoute
|
||||
'/sessions/$id': typeof SessionsIdRoute
|
||||
'/_account/': typeof AccountIndexRoute
|
||||
'/reset-cross-signing/': typeof ResetCrossSigningIndexRoute
|
||||
'/_account/sessions/$id': typeof AccountSessionsIdRoute
|
||||
'/_account/sessions/browsers': typeof AccountSessionsBrowsersRoute
|
||||
'/emails/$id/in-use': typeof EmailsIdInUseRoute
|
||||
'/emails/$id/verify': typeof EmailsIdVerifyRoute
|
||||
@@ -368,9 +364,9 @@ export interface FileRouteTypes {
|
||||
| '/devices/$'
|
||||
| '/reset-cross-signing/cancelled'
|
||||
| '/reset-cross-signing/success'
|
||||
| '/sessions/$id'
|
||||
| '/'
|
||||
| '/reset-cross-signing/'
|
||||
| '/sessions/$id'
|
||||
| '/sessions/browsers'
|
||||
| '/emails/$id/in-use'
|
||||
| '/emails/$id/verify'
|
||||
@@ -384,9 +380,9 @@ export interface FileRouteTypes {
|
||||
| '/devices/$'
|
||||
| '/reset-cross-signing/cancelled'
|
||||
| '/reset-cross-signing/success'
|
||||
| '/sessions/$id'
|
||||
| '/'
|
||||
| '/reset-cross-signing'
|
||||
| '/sessions/$id'
|
||||
| '/sessions/browsers'
|
||||
| '/emails/$id/in-use'
|
||||
| '/emails/$id/verify'
|
||||
@@ -402,9 +398,9 @@ export interface FileRouteTypes {
|
||||
| '/devices/$'
|
||||
| '/reset-cross-signing/cancelled'
|
||||
| '/reset-cross-signing/success'
|
||||
| '/sessions/$id'
|
||||
| '/_account/'
|
||||
| '/reset-cross-signing/'
|
||||
| '/_account/sessions/$id'
|
||||
| '/_account/sessions/browsers'
|
||||
| '/emails/$id/in-use'
|
||||
| '/emails/$id/verify'
|
||||
@@ -420,6 +416,7 @@ export interface RootRouteChildren {
|
||||
ResetCrossSigningRoute: typeof ResetCrossSigningRouteWithChildren
|
||||
ClientsIdRoute: typeof ClientsIdRoute
|
||||
DevicesSplatRoute: typeof DevicesSplatRoute
|
||||
SessionsIdRoute: typeof SessionsIdRoute
|
||||
EmailsIdInUseRoute: typeof EmailsIdInUseRoute
|
||||
EmailsIdVerifyRoute: typeof EmailsIdVerifyRoute
|
||||
PasswordChangeSuccessLazyRoute: typeof PasswordChangeSuccessLazyRoute
|
||||
@@ -432,6 +429,7 @@ const rootRouteChildren: RootRouteChildren = {
|
||||
ResetCrossSigningRoute: ResetCrossSigningRouteWithChildren,
|
||||
ClientsIdRoute: ClientsIdRoute,
|
||||
DevicesSplatRoute: DevicesSplatRoute,
|
||||
SessionsIdRoute: SessionsIdRoute,
|
||||
EmailsIdInUseRoute: EmailsIdInUseRoute,
|
||||
EmailsIdVerifyRoute: EmailsIdVerifyRoute,
|
||||
PasswordChangeSuccessLazyRoute: PasswordChangeSuccessLazyRoute,
|
||||
@@ -453,6 +451,7 @@ export const routeTree = rootRoute
|
||||
"/reset-cross-signing",
|
||||
"/clients/$id",
|
||||
"/devices/$",
|
||||
"/sessions/$id",
|
||||
"/emails/$id/in-use",
|
||||
"/emails/$id/verify",
|
||||
"/password/change/success",
|
||||
@@ -464,7 +463,6 @@ export const routeTree = rootRoute
|
||||
"filePath": "_account.tsx",
|
||||
"children": [
|
||||
"/_account/",
|
||||
"/_account/sessions/$id",
|
||||
"/_account/sessions/browsers",
|
||||
"/_account/sessions/"
|
||||
]
|
||||
@@ -491,6 +489,9 @@ export const routeTree = rootRoute
|
||||
"filePath": "reset-cross-signing.success.tsx",
|
||||
"parent": "/reset-cross-signing"
|
||||
},
|
||||
"/sessions/$id": {
|
||||
"filePath": "sessions.$id.tsx"
|
||||
},
|
||||
"/_account/": {
|
||||
"filePath": "_account.index.tsx",
|
||||
"parent": "/_account"
|
||||
@@ -499,10 +500,6 @@ export const routeTree = rootRoute
|
||||
"filePath": "reset-cross-signing.index.tsx",
|
||||
"parent": "/reset-cross-signing"
|
||||
},
|
||||
"/_account/sessions/$id": {
|
||||
"filePath": "_account.sessions.$id.tsx",
|
||||
"parent": "/_account"
|
||||
},
|
||||
"/_account/sessions/browsers": {
|
||||
"filePath": "_account.sessions.browsers.tsx",
|
||||
"parent": "/_account"
|
||||
|
||||
@@ -10,28 +10,63 @@ import {
|
||||
notFound,
|
||||
useNavigate,
|
||||
} from "@tanstack/react-router";
|
||||
import { Separator, Text } from "@vector-im/compound-web";
|
||||
import IconSignOut from "@vector-im/compound-design-tokens/assets/web/icons/sign-out";
|
||||
import { Button, Separator, Text } from "@vector-im/compound-web";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import AccountManagementPasswordPreview from "../components/AccountManagementPasswordPreview";
|
||||
import { ButtonLink } from "../components/ButtonLink";
|
||||
import * as Collapsible from "../components/Collapsible";
|
||||
import * as Dialog from "../components/Dialog";
|
||||
import LoadingSpinner from "../components/LoadingSpinner";
|
||||
import { useEndBrowserSession } from "../components/Session/EndBrowserSessionButton";
|
||||
import AddEmailForm from "../components/UserProfile/AddEmailForm";
|
||||
import UserEmailList from "../components/UserProfile/UserEmailList";
|
||||
|
||||
import { query } from "./_account.index";
|
||||
|
||||
export const Route = createLazyFileRoute("/_account/")({
|
||||
component: Index,
|
||||
});
|
||||
|
||||
const SignOutButton: React.FC<{ id: string }> = ({ id }) => {
|
||||
const { t } = useTranslation();
|
||||
const mutation = useEndBrowserSession(id, true);
|
||||
|
||||
return (
|
||||
<Dialog.Dialog
|
||||
trigger={
|
||||
<Button kind="primary" destructive size="lg" Icon={IconSignOut}>
|
||||
Sign out of account
|
||||
</Button>
|
||||
}
|
||||
>
|
||||
<Dialog.Title>Sign out of your account?</Dialog.Title>
|
||||
|
||||
<Button
|
||||
type="button"
|
||||
kind="primary"
|
||||
destructive
|
||||
onClick={() => mutation.mutate()}
|
||||
disabled={mutation.isPending}
|
||||
Icon={mutation.isPending ? undefined : IconSignOut}
|
||||
>
|
||||
{mutation.isPending && <LoadingSpinner inline />}
|
||||
{t("action.sign_out")}
|
||||
</Button>
|
||||
|
||||
<Dialog.Close asChild>
|
||||
<Button kind="tertiary">{t("action.cancel")}</Button>
|
||||
</Dialog.Close>
|
||||
</Dialog.Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
function Index(): React.ReactElement {
|
||||
const navigate = useNavigate();
|
||||
const { t } = useTranslation();
|
||||
const {
|
||||
data: { viewer, siteConfig },
|
||||
data: { viewerSession, siteConfig },
|
||||
} = useSuspenseQuery(query);
|
||||
if (viewer?.__typename !== "User") throw notFound();
|
||||
if (viewerSession?.__typename !== "BrowserSession") throw notFound();
|
||||
|
||||
// When adding an email, we want to go to the email verification form
|
||||
const onAdd = async (id: string): Promise<void> => {
|
||||
@@ -39,45 +74,52 @@ function Index(): React.ReactElement {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-4 mb-4">
|
||||
{/* Only display this section if the user can add email addresses to their
|
||||
<>
|
||||
<div className="flex flex-col gap-4">
|
||||
{/* Only display this section if the user can add email addresses to their
|
||||
account *or* if they have any existing email addresses */}
|
||||
{(siteConfig.emailChangeAllowed || viewer.emails.totalCount > 0) && (
|
||||
<>
|
||||
<Collapsible.Section
|
||||
defaultOpen
|
||||
title={t("frontend.account.contact_info")}
|
||||
>
|
||||
<UserEmailList siteConfig={siteConfig} />
|
||||
{(siteConfig.emailChangeAllowed ||
|
||||
viewerSession.user.emails.totalCount > 0) && (
|
||||
<>
|
||||
<Collapsible.Section
|
||||
defaultOpen
|
||||
title={t("frontend.account.contact_info")}
|
||||
>
|
||||
<UserEmailList siteConfig={siteConfig} />
|
||||
|
||||
{siteConfig.emailChangeAllowed && <AddEmailForm onAdd={onAdd} />}
|
||||
</Collapsible.Section>
|
||||
{siteConfig.emailChangeAllowed && <AddEmailForm onAdd={onAdd} />}
|
||||
</Collapsible.Section>
|
||||
|
||||
<Separator kind="section" />
|
||||
</>
|
||||
)}
|
||||
<Separator kind="section" />
|
||||
</>
|
||||
)}
|
||||
|
||||
{siteConfig.passwordLoginEnabled && (
|
||||
<>
|
||||
<Collapsible.Section
|
||||
defaultOpen
|
||||
title={t("frontend.account.account_password")}
|
||||
>
|
||||
<AccountManagementPasswordPreview siteConfig={siteConfig} />
|
||||
</Collapsible.Section>
|
||||
{siteConfig.passwordLoginEnabled && (
|
||||
<>
|
||||
<Collapsible.Section
|
||||
defaultOpen
|
||||
title={t("frontend.account.account_password")}
|
||||
>
|
||||
<AccountManagementPasswordPreview siteConfig={siteConfig} />
|
||||
</Collapsible.Section>
|
||||
|
||||
<Separator kind="section" />
|
||||
</>
|
||||
)}
|
||||
<Separator kind="section" />
|
||||
</>
|
||||
)}
|
||||
|
||||
<Collapsible.Section title={t("common.e2ee")}>
|
||||
<Text className="text-secondary" size="md">
|
||||
{t("frontend.reset_cross_signing.description")}
|
||||
</Text>
|
||||
<ButtonLink to="/reset-cross-signing" kind="secondary" destructive>
|
||||
{t("frontend.reset_cross_signing.start_reset")}
|
||||
</ButtonLink>
|
||||
</Collapsible.Section>
|
||||
</div>
|
||||
<Collapsible.Section title={t("common.e2ee")}>
|
||||
<Text className="text-secondary" size="md">
|
||||
{t("frontend.reset_cross_signing.description")}
|
||||
</Text>
|
||||
<ButtonLink to="/reset-cross-signing" kind="secondary" destructive>
|
||||
{t("frontend.reset_cross_signing.start_reset")}
|
||||
</ButtonLink>
|
||||
</Collapsible.Section>
|
||||
|
||||
<Separator kind="section" />
|
||||
</div>
|
||||
|
||||
<SignOutButton id={viewerSession.id} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -13,11 +13,14 @@ import { graphqlRequest } from "../graphql";
|
||||
|
||||
const QUERY = graphql(/* GraphQL */ `
|
||||
query UserProfile {
|
||||
viewer {
|
||||
viewerSession {
|
||||
__typename
|
||||
... on User {
|
||||
emails(first: 0) {
|
||||
totalCount
|
||||
... on BrowserSession {
|
||||
id
|
||||
user {
|
||||
emails(first: 0) {
|
||||
totalCount
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2024 New Vector Ltd.
|
||||
// Copyright 2024, 2025 New Vector Ltd.
|
||||
// Copyright 2024 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
@@ -7,12 +7,9 @@
|
||||
import { Outlet, createLazyFileRoute, notFound } from "@tanstack/react-router";
|
||||
import { Heading } from "@vector-im/compound-web";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { useEndBrowserSession } from "../components/BrowserSession";
|
||||
import Layout from "../components/Layout";
|
||||
import NavBar from "../components/NavBar";
|
||||
import NavItem from "../components/NavItem";
|
||||
import EndSessionButton from "../components/Session/EndSessionButton";
|
||||
import UserGreeting from "../components/UserGreeting";
|
||||
|
||||
import { useSuspenseQuery } from "@tanstack/react-query";
|
||||
@@ -25,10 +22,9 @@ export const Route = createLazyFileRoute("/_account")({
|
||||
function Account(): React.ReactElement {
|
||||
const { t } = useTranslation();
|
||||
const result = useSuspenseQuery(query);
|
||||
const session = result.data.viewerSession;
|
||||
if (session?.__typename !== "BrowserSession") throw notFound();
|
||||
const viewer = result.data.viewer;
|
||||
if (viewer?.__typename !== "User") throw notFound();
|
||||
const siteConfig = result.data.siteConfig;
|
||||
const onSessionEnd = useEndBrowserSession(session.id, true);
|
||||
|
||||
return (
|
||||
<Layout wide>
|
||||
@@ -37,12 +33,10 @@ function Account(): React.ReactElement {
|
||||
<Heading size="md" weight="semibold">
|
||||
{t("frontend.account.title")}
|
||||
</Heading>
|
||||
|
||||
<EndSessionButton endSession={onSessionEnd} />
|
||||
</header>
|
||||
|
||||
<div className="flex flex-col gap-4">
|
||||
<UserGreeting user={session.user} siteConfig={siteConfig} />
|
||||
<UserGreeting user={viewer} siteConfig={siteConfig} />
|
||||
|
||||
<NavBar>
|
||||
<NavItem to="/">{t("frontend.nav.settings")}</NavItem>
|
||||
|
||||
@@ -8,7 +8,6 @@ import { createLazyFileRoute, notFound } from "@tanstack/react-router";
|
||||
import { H5 } from "@vector-im/compound-web";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import BlockList from "../components/BlockList";
|
||||
import BrowserSession from "../components/BrowserSession";
|
||||
import { ButtonLink } from "../components/ButtonLink";
|
||||
import EmptyState from "../components/EmptyState";
|
||||
@@ -42,7 +41,7 @@ function BrowserSessions(): React.ReactElement {
|
||||
// We reverse the list as we are paginating backwards
|
||||
const edges = [...viewerSession.user.browserSessions.edges].reverse();
|
||||
return (
|
||||
<BlockList>
|
||||
<div className="flex flex-col gap-10">
|
||||
<H5>{t("frontend.browser_sessions_overview.heading")}</H5>
|
||||
|
||||
<div className="flex gap-2 items-start">
|
||||
@@ -104,6 +103,6 @@ function BrowserSessions(): React.ReactElement {
|
||||
</ButtonLink>
|
||||
</div>
|
||||
)}
|
||||
</BlockList>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import { createLazyFileRoute, notFound } from "@tanstack/react-router";
|
||||
import { H3, Separator } from "@vector-im/compound-web";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import BlockList from "../components/BlockList";
|
||||
import { ButtonLink } from "../components/ButtonLink";
|
||||
import CompatSession from "../components/CompatSession";
|
||||
import EmptyState from "../components/EmptyState";
|
||||
@@ -53,7 +52,7 @@ function Sessions(): React.ReactElement {
|
||||
const edges = [...appSessions.edges].reverse();
|
||||
|
||||
return (
|
||||
<BlockList>
|
||||
<div className="flex flex-col gap-10">
|
||||
<H3>{t("frontend.user_sessions_overview.heading")}</H3>
|
||||
<BrowserSessionsOverview user={viewer} />
|
||||
<Separator />
|
||||
@@ -121,6 +120,6 @@ function Sessions(): React.ReactElement {
|
||||
</ButtonLink>
|
||||
</div>
|
||||
)}
|
||||
</BlockList>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -11,15 +11,10 @@ import { graphqlRequest } from "../graphql";
|
||||
|
||||
const QUERY = graphql(/* GraphQL */ `
|
||||
query CurrentUserGreeting {
|
||||
viewerSession {
|
||||
viewer {
|
||||
__typename
|
||||
|
||||
... on BrowserSession {
|
||||
id
|
||||
|
||||
user {
|
||||
...UserGreeting_user
|
||||
}
|
||||
... on User {
|
||||
...UserGreeting_user
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@ import { Alert, Form, Separator } from "@vector-im/compound-web";
|
||||
import { type FormEvent, useRef } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import BlockList from "../components/BlockList";
|
||||
import { ButtonLink } from "../components/ButtonLink";
|
||||
import Layout from "../components/Layout";
|
||||
import LoadingSpinner from "../components/LoadingSpinner";
|
||||
@@ -103,7 +102,7 @@ function ChangePassword(): React.ReactNode {
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<BlockList>
|
||||
<div className="flex flex-col gap-10">
|
||||
<PageHeading
|
||||
Icon={IconLockSolid}
|
||||
title={t("frontend.password_change.title")}
|
||||
@@ -181,7 +180,7 @@ function ChangePassword(): React.ReactNode {
|
||||
{t("action.cancel")}
|
||||
</ButtonLink>
|
||||
</Form.Root>
|
||||
</BlockList>
|
||||
</div>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -7,8 +7,6 @@
|
||||
import { createLazyFileRoute } from "@tanstack/react-router";
|
||||
import IconCheckCircle from "@vector-im/compound-design-tokens/assets/web/icons/check-circle-solid";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import BlockList from "../components/BlockList";
|
||||
import { ButtonLink } from "../components/ButtonLink";
|
||||
import Layout from "../components/Layout";
|
||||
import PageHeading from "../components/PageHeading";
|
||||
@@ -22,7 +20,7 @@ function ChangePasswordSuccess(): React.ReactNode {
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<BlockList>
|
||||
<div className="flex flex-col gap-10">
|
||||
<PageHeading
|
||||
Icon={IconCheckCircle}
|
||||
title={t("frontend.password_change.success.title")}
|
||||
@@ -33,7 +31,7 @@ function ChangePasswordSuccess(): React.ReactNode {
|
||||
<ButtonLink to="/" kind="tertiary">
|
||||
{t("action.back")}
|
||||
</ButtonLink>
|
||||
</BlockList>
|
||||
</div>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -16,8 +16,6 @@ import IconLockSolid from "@vector-im/compound-design-tokens/assets/web/icons/lo
|
||||
import { Alert, Button, Form } from "@vector-im/compound-web";
|
||||
import type { FormEvent } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import BlockList from "../components/BlockList";
|
||||
import { ButtonLink } from "../components/ButtonLink";
|
||||
import Layout from "../components/Layout";
|
||||
import LoadingSpinner from "../components/LoadingSpinner";
|
||||
@@ -206,7 +204,7 @@ const EmailRecovery: React.FC<{
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<BlockList>
|
||||
<div className="flex flex-col gap-10">
|
||||
<PageHeading
|
||||
Icon={IconLockSolid}
|
||||
title={t("frontend.password_reset.title")}
|
||||
@@ -256,7 +254,7 @@ const EmailRecovery: React.FC<{
|
||||
{t("action.save_and_continue")}
|
||||
</Form.Submit>
|
||||
</Form.Root>
|
||||
</BlockList>
|
||||
</div>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -13,15 +13,16 @@ import { createFileRoute, notFound } from "@tanstack/react-router";
|
||||
import IconCheck from "@vector-im/compound-design-tokens/assets/web/icons/check";
|
||||
import IconError from "@vector-im/compound-design-tokens/assets/web/icons/error";
|
||||
import IconInfo from "@vector-im/compound-design-tokens/assets/web/icons/info";
|
||||
import { Button, Text } from "@vector-im/compound-web";
|
||||
import {
|
||||
Button,
|
||||
Text,
|
||||
VisualList,
|
||||
VisualListItem,
|
||||
} from "@vector-im/compound-web";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { ButtonLink } from "../components/ButtonLink";
|
||||
import LoadingSpinner from "../components/LoadingSpinner";
|
||||
import PageHeading from "../components/PageHeading";
|
||||
import {
|
||||
VisualList,
|
||||
VisualListItem,
|
||||
} from "../components/VisualList/VisualList";
|
||||
import { graphql } from "../gql";
|
||||
import { graphqlRequest } from "../graphql";
|
||||
|
||||
@@ -123,19 +124,15 @@ function ResetCrossSigning(): React.ReactNode {
|
||||
</Text>
|
||||
|
||||
<VisualList>
|
||||
<VisualListItem
|
||||
Icon={IconCheck}
|
||||
iconColor="var(--cpd-color-icon-success-primary)"
|
||||
label={t("frontend.reset_cross_signing.effect_list.positive_1")}
|
||||
/>
|
||||
<VisualListItem
|
||||
Icon={IconInfo}
|
||||
label={t("frontend.reset_cross_signing.effect_list.neutral_1")}
|
||||
/>
|
||||
<VisualListItem
|
||||
Icon={IconInfo}
|
||||
label={t("frontend.reset_cross_signing.effect_list.neutral_2")}
|
||||
/>
|
||||
<VisualListItem Icon={IconCheck} success>
|
||||
{t("frontend.reset_cross_signing.effect_list.positive_1")}
|
||||
</VisualListItem>
|
||||
<VisualListItem Icon={IconInfo}>
|
||||
{t("frontend.reset_cross_signing.effect_list.neutral_1")}
|
||||
</VisualListItem>
|
||||
<VisualListItem Icon={IconInfo}>
|
||||
{t("frontend.reset_cross_signing.effect_list.neutral_2")}
|
||||
</VisualListItem>
|
||||
</VisualList>
|
||||
|
||||
<Text className="text-center" size="md" weight="semibold">
|
||||
|
||||
@@ -13,7 +13,6 @@ import { Button, Text } from "@vector-im/compound-web";
|
||||
import * as v from "valibot";
|
||||
|
||||
import { useTranslation } from "react-i18next";
|
||||
import BlockList from "../components/BlockList";
|
||||
import Layout from "../components/Layout";
|
||||
import PageHeading from "../components/PageHeading";
|
||||
|
||||
@@ -25,9 +24,9 @@ export const Route = createFileRoute("/reset-cross-signing")({
|
||||
validateSearch: searchSchema,
|
||||
component: () => (
|
||||
<Layout>
|
||||
<BlockList>
|
||||
<div className="flex flex-col gap-10">
|
||||
<Outlet />
|
||||
</BlockList>
|
||||
</div>
|
||||
</Layout>
|
||||
),
|
||||
errorComponent: ResetCrossSigningError,
|
||||
|
||||
@@ -4,19 +4,18 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
// Please see LICENSE in the repository root for full details.
|
||||
|
||||
import { useSuspenseQuery } from "@tanstack/react-query";
|
||||
import { createLazyFileRoute, notFound } from "@tanstack/react-router";
|
||||
import { Alert } from "@vector-im/compound-web";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import Layout from "../components/Layout";
|
||||
import { Link } from "../components/Link";
|
||||
import BrowserSessionDetail from "../components/SessionDetail/BrowserSessionDetail";
|
||||
import CompatSessionDetail from "../components/SessionDetail/CompatSessionDetail";
|
||||
import OAuth2SessionDetail from "../components/SessionDetail/OAuth2SessionDetail";
|
||||
import { query } from "./sessions.$id";
|
||||
|
||||
import { useSuspenseQuery } from "@tanstack/react-query";
|
||||
import { query } from "./_account.sessions.$id";
|
||||
|
||||
export const Route = createLazyFileRoute("/_account/sessions/$id")({
|
||||
export const Route = createLazyFileRoute("/sessions/$id")({
|
||||
notFoundComponent: NotFound,
|
||||
component: SessionDetail,
|
||||
});
|
||||
@@ -26,13 +25,15 @@ function NotFound(): React.ReactElement {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<Alert
|
||||
type="critical"
|
||||
title={t("frontend.session_detail.alert.title", { deviceId: id })}
|
||||
>
|
||||
{t("frontend.session_detail.alert.text")}
|
||||
<Link to="/sessions">{t("frontend.session_detail.alert.button")}</Link>
|
||||
</Alert>
|
||||
<Layout>
|
||||
<Alert
|
||||
type="critical"
|
||||
title={t("frontend.session_detail.alert.title", { deviceId: id })}
|
||||
>
|
||||
{t("frontend.session_detail.alert.text")}
|
||||
<Link to="/sessions">{t("frontend.session_detail.alert.button")}</Link>
|
||||
</Alert>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -45,15 +46,25 @@ function SessionDetail(): React.ReactElement {
|
||||
|
||||
switch (node.__typename) {
|
||||
case "CompatSession":
|
||||
return <CompatSessionDetail session={node} />;
|
||||
return (
|
||||
<Layout wide>
|
||||
<CompatSessionDetail session={node} />
|
||||
</Layout>
|
||||
);
|
||||
case "Oauth2Session":
|
||||
return <OAuth2SessionDetail session={node} />;
|
||||
return (
|
||||
<Layout wide>
|
||||
<OAuth2SessionDetail session={node} />
|
||||
</Layout>
|
||||
);
|
||||
case "BrowserSession":
|
||||
return (
|
||||
<BrowserSessionDetail
|
||||
session={node}
|
||||
isCurrent={node.id === viewerSession.id}
|
||||
/>
|
||||
<Layout wide>
|
||||
<BrowserSessionDetail
|
||||
session={node}
|
||||
isCurrent={node.id === viewerSession.id}
|
||||
/>
|
||||
</Layout>
|
||||
);
|
||||
default:
|
||||
throw new Error("Unknown session type");
|
||||
@@ -34,7 +34,7 @@ export const query = (id: string) =>
|
||||
graphqlRequest({ query: QUERY, signal, variables: { id } }),
|
||||
});
|
||||
|
||||
export const Route = createFileRoute("/_account/sessions/$id")({
|
||||
export const Route = createFileRoute("/sessions/$id")({
|
||||
loader: ({ context, params }) =>
|
||||
context.queryClient.ensureQueryData(query(params.id)),
|
||||
});
|
||||
33
frontend/src/utils/simplifyUrl.ts
Normal file
33
frontend/src/utils/simplifyUrl.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
// Copyright 2025 New Vector Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
// Please see LICENSE in the repository root for full details.
|
||||
|
||||
/**
|
||||
* Simplify a URL by removing the protocol, search params and hash.
|
||||
*
|
||||
* @param url The URL to simplify
|
||||
* @returns The simplified URL
|
||||
*/
|
||||
const simplifyUrl = (url: string): string => {
|
||||
let parsed: URL;
|
||||
try {
|
||||
parsed = new URL(url);
|
||||
} catch (_e) {
|
||||
// Not a valid URL, return the original
|
||||
return url;
|
||||
}
|
||||
|
||||
// Clear out the search params and hash
|
||||
parsed.search = "";
|
||||
parsed.hash = "";
|
||||
|
||||
if (parsed.protocol === "https:") {
|
||||
return parsed.hostname;
|
||||
}
|
||||
|
||||
// Return the simplified URL
|
||||
return parsed.toString();
|
||||
};
|
||||
|
||||
export default simplifyUrl;
|
||||
@@ -43,10 +43,13 @@ const userProfileHandler = ({
|
||||
mockUserProfileQuery(() =>
|
||||
HttpResponse.json({
|
||||
data: {
|
||||
viewer: {
|
||||
__typename: "User",
|
||||
emails: {
|
||||
totalCount: emailTotalCount,
|
||||
viewerSession: {
|
||||
__typename: "BrowserSession",
|
||||
id: "session-id",
|
||||
user: {
|
||||
emails: {
|
||||
totalCount: emailTotalCount,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
@@ -60,23 +60,19 @@ export const handlers = [
|
||||
mockCurrentUserGreetingQuery(() =>
|
||||
HttpResponse.json({
|
||||
data: {
|
||||
viewerSession: {
|
||||
__typename: "BrowserSession",
|
||||
|
||||
id: "session-id",
|
||||
user: Object.assign(
|
||||
makeFragmentData(
|
||||
{
|
||||
id: "user-id",
|
||||
matrix: {
|
||||
mxid: "@alice:example.com",
|
||||
displayName: "Alice",
|
||||
},
|
||||
viewer: Object.assign(
|
||||
makeFragmentData(
|
||||
{
|
||||
__typename: "User",
|
||||
id: "user-id",
|
||||
matrix: {
|
||||
mxid: "@alice:example.com",
|
||||
displayName: "Alice",
|
||||
},
|
||||
USER_GREETING_FRAGMENT,
|
||||
),
|
||||
},
|
||||
USER_GREETING_FRAGMENT,
|
||||
),
|
||||
},
|
||||
),
|
||||
|
||||
siteConfig: makeFragmentData(
|
||||
{
|
||||
@@ -91,10 +87,13 @@ export const handlers = [
|
||||
mockUserProfileQuery(() =>
|
||||
HttpResponse.json({
|
||||
data: {
|
||||
viewer: {
|
||||
__typename: "User",
|
||||
emails: {
|
||||
totalCount: 1,
|
||||
viewerSession: {
|
||||
__typename: "BrowserSession",
|
||||
id: "browser-session-id",
|
||||
user: {
|
||||
emails: {
|
||||
totalCount: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ exports[`Reset cross signing > renders the cancelled page 1`] = `
|
||||
class="_layoutContainer_0c8bf9"
|
||||
>
|
||||
<div
|
||||
class="_blockList_f8cc7f"
|
||||
class="flex flex-col gap-10"
|
||||
>
|
||||
<header
|
||||
class="_pageHeading_c10486"
|
||||
@@ -60,7 +60,7 @@ exports[`Reset cross signing > renders the deep link page 1`] = `
|
||||
class="_layoutContainer_0c8bf9"
|
||||
>
|
||||
<div
|
||||
class="_blockList_f8cc7f"
|
||||
class="flex flex-col gap-10"
|
||||
>
|
||||
<header
|
||||
class="_pageHeading_c10486"
|
||||
@@ -96,38 +96,36 @@ exports[`Reset cross signing > renders the deep link page 1`] = `
|
||||
If you're not signed in to any other devices and you've lost your recovery key, then you'll need to reset your identity to continue using the app.
|
||||
</p>
|
||||
<ul
|
||||
class="_list_7f22f8"
|
||||
class="_visual-list_4dcf8_17"
|
||||
>
|
||||
<li
|
||||
class="_item_7f22f8"
|
||||
class="_visual-list-item_bqeu7_17"
|
||||
>
|
||||
<svg
|
||||
color="var(--cpd-color-icon-success-primary)"
|
||||
aria-hidden="true"
|
||||
class="_visual-list-item-icon_bqeu7_26 _visual-list-item-icon-success_bqeu7_31"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
height="24px"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
width="24px"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M9.55 17.575c-.133 0-.258-.02-.375-.063a.876.876 0 0 1-.325-.212L4.55 13c-.183-.183-.27-.42-.263-.713.009-.291.105-.529.288-.712a.948.948 0 0 1 .7-.275.95.95 0 0 1 .7.275L9.55 15.15l8.475-8.475c.183-.183.42-.275.713-.275.291 0 .529.092.712.275.183.183.275.42.275.713 0 .291-.092.529-.275.712l-9.2 9.2c-.1.1-.208.17-.325.212a1.106 1.106 0 0 1-.375.063Z"
|
||||
/>
|
||||
</svg>
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59"
|
||||
>
|
||||
Your account details, contacts, preferences, and chat list will be kept
|
||||
</p>
|
||||
Your account details, contacts, preferences, and chat list will be kept
|
||||
</li>
|
||||
<li
|
||||
class="_item_7f22f8"
|
||||
class="_visual-list-item_bqeu7_17"
|
||||
>
|
||||
<svg
|
||||
color="var(--cpd-color-icon-tertiary)"
|
||||
aria-hidden="true"
|
||||
class="_visual-list-item-icon_bqeu7_26"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
height="24px"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
width="24px"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
@@ -139,21 +137,18 @@ exports[`Reset cross signing > renders the deep link page 1`] = `
|
||||
fill-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59"
|
||||
>
|
||||
You will lose any message history that's stored only on the server
|
||||
</p>
|
||||
You will lose any message history that's stored only on the server
|
||||
</li>
|
||||
<li
|
||||
class="_item_7f22f8"
|
||||
class="_visual-list-item_bqeu7_17"
|
||||
>
|
||||
<svg
|
||||
color="var(--cpd-color-icon-tertiary)"
|
||||
aria-hidden="true"
|
||||
class="_visual-list-item-icon_bqeu7_26"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
height="24px"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
width="24px"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
@@ -165,11 +160,7 @@ exports[`Reset cross signing > renders the deep link page 1`] = `
|
||||
fill-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59"
|
||||
>
|
||||
You will need to verify all your existing devices and contacts again
|
||||
</p>
|
||||
You will need to verify all your existing devices and contacts again
|
||||
</li>
|
||||
</ul>
|
||||
<p
|
||||
@@ -340,7 +331,7 @@ exports[`Reset cross signing > renders the page 1`] = `
|
||||
class="_layoutContainer_0c8bf9"
|
||||
>
|
||||
<div
|
||||
class="_blockList_f8cc7f"
|
||||
class="flex flex-col gap-10"
|
||||
>
|
||||
<header
|
||||
class="_pageHeading_c10486"
|
||||
@@ -376,38 +367,36 @@ exports[`Reset cross signing > renders the page 1`] = `
|
||||
If you're not signed in to any other devices and you've lost your recovery key, then you'll need to reset your identity to continue using the app.
|
||||
</p>
|
||||
<ul
|
||||
class="_list_7f22f8"
|
||||
class="_visual-list_4dcf8_17"
|
||||
>
|
||||
<li
|
||||
class="_item_7f22f8"
|
||||
class="_visual-list-item_bqeu7_17"
|
||||
>
|
||||
<svg
|
||||
color="var(--cpd-color-icon-success-primary)"
|
||||
aria-hidden="true"
|
||||
class="_visual-list-item-icon_bqeu7_26 _visual-list-item-icon-success_bqeu7_31"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
height="24px"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
width="24px"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M9.55 17.575c-.133 0-.258-.02-.375-.063a.876.876 0 0 1-.325-.212L4.55 13c-.183-.183-.27-.42-.263-.713.009-.291.105-.529.288-.712a.948.948 0 0 1 .7-.275.95.95 0 0 1 .7.275L9.55 15.15l8.475-8.475c.183-.183.42-.275.713-.275.291 0 .529.092.712.275.183.183.275.42.275.713 0 .291-.092.529-.275.712l-9.2 9.2c-.1.1-.208.17-.325.212a1.106 1.106 0 0 1-.375.063Z"
|
||||
/>
|
||||
</svg>
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59"
|
||||
>
|
||||
Your account details, contacts, preferences, and chat list will be kept
|
||||
</p>
|
||||
Your account details, contacts, preferences, and chat list will be kept
|
||||
</li>
|
||||
<li
|
||||
class="_item_7f22f8"
|
||||
class="_visual-list-item_bqeu7_17"
|
||||
>
|
||||
<svg
|
||||
color="var(--cpd-color-icon-tertiary)"
|
||||
aria-hidden="true"
|
||||
class="_visual-list-item-icon_bqeu7_26"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
height="24px"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
width="24px"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
@@ -419,21 +408,18 @@ exports[`Reset cross signing > renders the page 1`] = `
|
||||
fill-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59"
|
||||
>
|
||||
You will lose any message history that's stored only on the server
|
||||
</p>
|
||||
You will lose any message history that's stored only on the server
|
||||
</li>
|
||||
<li
|
||||
class="_item_7f22f8"
|
||||
class="_visual-list-item_bqeu7_17"
|
||||
>
|
||||
<svg
|
||||
color="var(--cpd-color-icon-tertiary)"
|
||||
aria-hidden="true"
|
||||
class="_visual-list-item-icon_bqeu7_26"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
height="24px"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
width="24px"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
@@ -445,11 +431,7 @@ exports[`Reset cross signing > renders the page 1`] = `
|
||||
fill-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59"
|
||||
>
|
||||
You will need to verify all your existing devices and contacts again
|
||||
</p>
|
||||
You will need to verify all your existing devices and contacts again
|
||||
</li>
|
||||
</ul>
|
||||
<p
|
||||
@@ -529,7 +511,7 @@ exports[`Reset cross signing > renders the success page 1`] = `
|
||||
class="_layoutContainer_0c8bf9"
|
||||
>
|
||||
<div
|
||||
class="_blockList_f8cc7f"
|
||||
class="flex flex-col gap-10"
|
||||
>
|
||||
<header
|
||||
class="_pageHeading_c10486"
|
||||
@@ -578,7 +560,7 @@ exports[`Reset cross signing > renders the success page 2`] = `
|
||||
class="_layoutContainer_0c8bf9"
|
||||
>
|
||||
<div
|
||||
class="_blockList_f8cc7f"
|
||||
class="flex flex-col gap-10"
|
||||
>
|
||||
<header
|
||||
class="_pageHeading_c10486"
|
||||
|
||||
@@ -2,18 +2,18 @@
|
||||
|
||||
exports[`Account home page > display name edit box > displays an error if the display name is invalid 1`] = `
|
||||
<div
|
||||
aria-describedby="radix-:r75:"
|
||||
aria-labelledby="radix-:r74:"
|
||||
aria-describedby="radix-:r72:"
|
||||
aria-labelledby="radix-:r71:"
|
||||
class="_body_9cf7b0"
|
||||
data-state="open"
|
||||
id="radix-:r73:"
|
||||
id="radix-:r70:"
|
||||
role="dialog"
|
||||
style="pointer-events: auto;"
|
||||
tabindex="-1"
|
||||
>
|
||||
<h2
|
||||
class="_title_9cf7b0"
|
||||
id="radix-:r74:"
|
||||
id="radix-:r71:"
|
||||
>
|
||||
Edit profile
|
||||
</h2>
|
||||
@@ -150,18 +150,18 @@ exports[`Account home page > display name edit box > displays an error if the di
|
||||
|
||||
exports[`Account home page > display name edit box > lets edit the display name 1`] = `
|
||||
<div
|
||||
aria-describedby="radix-:r1h:"
|
||||
aria-labelledby="radix-:r1g:"
|
||||
aria-describedby="radix-:r1e:"
|
||||
aria-labelledby="radix-:r1d:"
|
||||
class="_body_9cf7b0"
|
||||
data-state="open"
|
||||
id="radix-:r1f:"
|
||||
id="radix-:r1c:"
|
||||
role="dialog"
|
||||
style="pointer-events: auto;"
|
||||
tabindex="-1"
|
||||
>
|
||||
<h2
|
||||
class="_title_9cf7b0"
|
||||
id="radix-:r1g:"
|
||||
id="radix-:r1d:"
|
||||
>
|
||||
Edit profile
|
||||
</h2>
|
||||
@@ -308,32 +308,6 @@ exports[`Account home page > renders the page 1`] = `
|
||||
>
|
||||
Your account
|
||||
</h1>
|
||||
<button
|
||||
aria-controls="radix-:r0:"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="dialog"
|
||||
class="_button_i91xf_17 _has-icon_i91xf_66 _destructive_i91xf_116"
|
||||
data-kind="secondary"
|
||||
data-size="sm"
|
||||
data-state="closed"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
type="button"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="currentColor"
|
||||
height="20"
|
||||
viewBox="0 0 24 24"
|
||||
width="20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M9 12.031c0-.283.096-.52.288-.712A.968.968 0 0 1 10 11.03h7.15l-1.875-1.875a.96.96 0 0 1-.3-.7c0-.266.108-.508.325-.725a.93.93 0 0 1 .712-.287.977.977 0 0 1 .688.287l3.6 3.6c.1.1.17.209.212.325.042.117.063.242.063.375 0 .134-.02.259-.063.375a.877.877 0 0 1-.212.325l-3.6 3.6a.93.93 0 0 1-.712.288.977.977 0 0 1-.688-.288 1.02 1.02 0 0 1-.313-.712.931.931 0 0 1 .288-.713l1.875-1.875H10a.968.968 0 0 1-.712-.287A.968.968 0 0 1 9 12.03Zm-6-7c0-.55.196-1.02.588-1.412A1.926 1.926 0 0 1 5 3.03h6a.97.97 0 0 1 .713.288.968.968 0 0 1 .287.712.97.97 0 0 1-.287.713.968.968 0 0 1-.713.287H5v14h6a.97.97 0 0 1 .713.288.968.968 0 0 1 .287.712.97.97 0 0 1-.287.713.968.968 0 0 1-.713.287H5c-.55 0-1.02-.196-1.412-.587A1.926 1.926 0 0 1 3 19.03v-14Z"
|
||||
/>
|
||||
</svg>
|
||||
Sign out
|
||||
</button>
|
||||
</header>
|
||||
<div
|
||||
class="flex flex-col gap-4"
|
||||
@@ -366,10 +340,10 @@ exports[`Account home page > renders the page 1`] = `
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
aria-controls="radix-:r3:"
|
||||
aria-controls="radix-:r0:"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="dialog"
|
||||
aria-labelledby=":r6:"
|
||||
aria-labelledby=":r3:"
|
||||
class="_icon-button_bh2qc_17 _editButton_66f22a"
|
||||
data-state="closed"
|
||||
role="button"
|
||||
@@ -430,10 +404,10 @@ exports[`Account home page > renders the page 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="flex flex-col gap-4 mb-4"
|
||||
class="flex flex-col gap-4"
|
||||
>
|
||||
<section
|
||||
aria-labelledby=":rb:"
|
||||
aria-labelledby=":r8:"
|
||||
class="_root_f1daaa"
|
||||
data-state="open"
|
||||
>
|
||||
@@ -445,14 +419,14 @@ exports[`Account home page > renders the page 1`] = `
|
||||
>
|
||||
<h4
|
||||
class="_typography_yh5dq_162 _font-heading-sm-semibold_yh5dq_102 _triggerTitle_f1daaa"
|
||||
id=":rb:"
|
||||
id=":r8:"
|
||||
>
|
||||
Contact info
|
||||
</h4>
|
||||
<button
|
||||
aria-controls="radix-:rd:"
|
||||
aria-controls="radix-:ra:"
|
||||
aria-expanded="true"
|
||||
aria-labelledby=":re:"
|
||||
aria-labelledby=":rb:"
|
||||
class="_icon-button_bh2qc_17 _triggerIcon_f1daaa"
|
||||
data-state="open"
|
||||
role="button"
|
||||
@@ -482,7 +456,7 @@ exports[`Account home page > renders the page 1`] = `
|
||||
<article
|
||||
class="_content_f1daaa"
|
||||
data-state="open"
|
||||
id="radix-:rd:"
|
||||
id="radix-:ra:"
|
||||
style="transition-duration: 0s; animation-name: none;"
|
||||
>
|
||||
<form
|
||||
@@ -493,7 +467,7 @@ exports[`Account home page > renders the page 1`] = `
|
||||
>
|
||||
<label
|
||||
class="_label_ssths_67"
|
||||
for="radix-:rj:"
|
||||
for="radix-:rg:"
|
||||
>
|
||||
Email
|
||||
</label>
|
||||
@@ -502,7 +476,7 @@ exports[`Account home page > renders the page 1`] = `
|
||||
>
|
||||
<input
|
||||
class="_control_9gon8_18 _userEmailField_e2a518"
|
||||
id="radix-:rj:"
|
||||
id="radix-:rg:"
|
||||
name="email"
|
||||
readonly=""
|
||||
title=""
|
||||
@@ -520,7 +494,7 @@ exports[`Account home page > renders the page 1`] = `
|
||||
>
|
||||
<label
|
||||
class="_label_ssths_67"
|
||||
for="radix-:rk:"
|
||||
for="radix-:rh:"
|
||||
>
|
||||
Add email
|
||||
</label>
|
||||
@@ -528,9 +502,9 @@ exports[`Account home page > renders the page 1`] = `
|
||||
class="_controls_1h4nb_17"
|
||||
>
|
||||
<input
|
||||
aria-describedby="radix-:rl:"
|
||||
aria-describedby="radix-:ri:"
|
||||
class="_control_9gon8_18"
|
||||
id="radix-:rk:"
|
||||
id="radix-:rh:"
|
||||
name="input"
|
||||
required=""
|
||||
title=""
|
||||
@@ -539,7 +513,7 @@ exports[`Account home page > renders the page 1`] = `
|
||||
</div>
|
||||
<span
|
||||
class="_message_ssths_93 _help-message_ssths_99"
|
||||
id="radix-:rl:"
|
||||
id="radix-:ri:"
|
||||
>
|
||||
Add an alternative email you can use to access this account.
|
||||
</span>
|
||||
@@ -554,7 +528,7 @@ exports[`Account home page > renders the page 1`] = `
|
||||
role="separator"
|
||||
/>
|
||||
<section
|
||||
aria-labelledby=":rm:"
|
||||
aria-labelledby=":rj:"
|
||||
class="_root_f1daaa"
|
||||
data-state="open"
|
||||
>
|
||||
@@ -566,14 +540,14 @@ exports[`Account home page > renders the page 1`] = `
|
||||
>
|
||||
<h4
|
||||
class="_typography_yh5dq_162 _font-heading-sm-semibold_yh5dq_102 _triggerTitle_f1daaa"
|
||||
id=":rm:"
|
||||
id=":rj:"
|
||||
>
|
||||
Account password
|
||||
</h4>
|
||||
<button
|
||||
aria-controls="radix-:ro:"
|
||||
aria-controls="radix-:rl:"
|
||||
aria-expanded="true"
|
||||
aria-labelledby=":rp:"
|
||||
aria-labelledby=":rm:"
|
||||
class="_icon-button_bh2qc_17 _triggerIcon_f1daaa"
|
||||
data-state="open"
|
||||
role="button"
|
||||
@@ -603,7 +577,7 @@ exports[`Account home page > renders the page 1`] = `
|
||||
<article
|
||||
class="_content_f1daaa"
|
||||
data-state="open"
|
||||
id="radix-:ro:"
|
||||
id="radix-:rl:"
|
||||
style="transition-duration: 0s; animation-name: none;"
|
||||
>
|
||||
<form
|
||||
@@ -614,14 +588,14 @@ exports[`Account home page > renders the page 1`] = `
|
||||
>
|
||||
<label
|
||||
class="_label_ssths_67"
|
||||
for="radix-:ru:"
|
||||
for="radix-:rr:"
|
||||
>
|
||||
Password
|
||||
</label>
|
||||
<input
|
||||
aria-describedby="radix-:rv:"
|
||||
aria-describedby="radix-:rs:"
|
||||
class="_control_9gon8_18"
|
||||
id="radix-:ru:"
|
||||
id="radix-:rr:"
|
||||
name="password_preview"
|
||||
readonly=""
|
||||
title=""
|
||||
@@ -630,7 +604,7 @@ exports[`Account home page > renders the page 1`] = `
|
||||
/>
|
||||
<span
|
||||
class="_message_ssths_93 _help-message_ssths_99"
|
||||
id="radix-:rv:"
|
||||
id="radix-:rs:"
|
||||
>
|
||||
<a
|
||||
class="_link_7634c3"
|
||||
@@ -650,7 +624,7 @@ exports[`Account home page > renders the page 1`] = `
|
||||
role="separator"
|
||||
/>
|
||||
<section
|
||||
aria-labelledby=":r10:"
|
||||
aria-labelledby=":rt:"
|
||||
class="_root_f1daaa"
|
||||
data-state="closed"
|
||||
>
|
||||
@@ -662,14 +636,14 @@ exports[`Account home page > renders the page 1`] = `
|
||||
>
|
||||
<h4
|
||||
class="_typography_yh5dq_162 _font-heading-sm-semibold_yh5dq_102 _triggerTitle_f1daaa"
|
||||
id=":r10:"
|
||||
id=":rt:"
|
||||
>
|
||||
End-to-end encryption
|
||||
</h4>
|
||||
<button
|
||||
aria-controls="radix-:r12:"
|
||||
aria-controls="radix-:rv:"
|
||||
aria-expanded="false"
|
||||
aria-labelledby=":r13:"
|
||||
aria-labelledby=":r10:"
|
||||
class="_icon-button_bh2qc_17 _triggerIcon_f1daaa"
|
||||
data-state="closed"
|
||||
role="button"
|
||||
@@ -697,7 +671,39 @@ exports[`Account home page > renders the page 1`] = `
|
||||
</div>
|
||||
</header>
|
||||
</section>
|
||||
<div
|
||||
class="_separator_144s5_17"
|
||||
data-kind="section"
|
||||
data-orientation="horizontal"
|
||||
role="separator"
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
aria-controls="radix-:r15:"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="dialog"
|
||||
class="_button_i91xf_17 _has-icon_i91xf_66 _destructive_i91xf_116"
|
||||
data-kind="primary"
|
||||
data-size="lg"
|
||||
data-state="closed"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
type="button"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="currentColor"
|
||||
height="20"
|
||||
viewBox="0 0 24 24"
|
||||
width="20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M9 12.031c0-.283.096-.52.288-.712A.968.968 0 0 1 10 11.03h7.15l-1.875-1.875a.96.96 0 0 1-.3-.7c0-.266.108-.508.325-.725a.93.93 0 0 1 .712-.287.977.977 0 0 1 .688.287l3.6 3.6c.1.1.17.209.212.325.042.117.063.242.063.375 0 .134-.02.259-.063.375a.877.877 0 0 1-.212.325l-3.6 3.6a.93.93 0 0 1-.712.288.977.977 0 0 1-.688-.288 1.02 1.02 0 0 1-.313-.712.931.931 0 0 1 .288-.713l1.875-1.875H10a.968.968 0 0 1-.712-.287A.968.968 0 0 1 9 12.03Zm-6-7c0-.55.196-1.02.588-1.412A1.926 1.926 0 0 1 5 3.03h6a.97.97 0 0 1 .713.288.968.968 0 0 1 .287.712.97.97 0 0 1-.287.713.968.968 0 0 1-.713.287H5v14h6a.97.97 0 0 1 .713.288.968.968 0 0 1 .287.712.97.97 0 0 1-.287.713.968.968 0 0 1-.713.287H5c-.55 0-1.02-.196-1.412-.587A1.926 1.926 0 0 1 3 19.03v-14Z"
|
||||
/>
|
||||
</svg>
|
||||
Sign out of account
|
||||
</button>
|
||||
<footer
|
||||
class="_legalFooter_eb428f"
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user