You've already forked authentication-service
mirror of
https://github.com/matrix-org/matrix-authentication-service.git
synced 2025-07-31 09:24:31 +03:00
Cleanup the session details fragments & load last active IP
This also cleans up the GraphQL scalar types, by making sure we always parse dates correctly
This commit is contained in:
@ -21,6 +21,14 @@ const config: CodegenConfig = {
|
|||||||
generates: {
|
generates: {
|
||||||
"./src/gql/": {
|
"./src/gql/": {
|
||||||
preset: "client",
|
preset: "client",
|
||||||
|
config: {
|
||||||
|
// By default, unknown scalars are generated as `any`. This is not ideal for catching potential bugs.
|
||||||
|
defaultScalarType: "unknown",
|
||||||
|
scalars: {
|
||||||
|
DateTime: "string",
|
||||||
|
Url: "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"./src/gql/schema.ts": {
|
"./src/gql/schema.ts": {
|
||||||
plugins: ["urql-introspection"],
|
plugins: ["urql-introspection"],
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
import { parseISO } from "date-fns";
|
||||||
import { atom, useSetAtom } from "jotai";
|
import { atom, useSetAtom } from "jotai";
|
||||||
import { atomFamily } from "jotai/utils";
|
import { atomFamily } from "jotai/utils";
|
||||||
import { atomWithMutation } from "jotai-urql";
|
import { atomWithMutation } from "jotai-urql";
|
||||||
@ -29,12 +30,14 @@ import { useCurrentBrowserSessionId } from "../utils/session/useCurrentBrowserSe
|
|||||||
import EndSessionButton from "./Session/EndSessionButton";
|
import EndSessionButton from "./Session/EndSessionButton";
|
||||||
import Session from "./Session/Session";
|
import Session from "./Session/Session";
|
||||||
|
|
||||||
export const BROWSER_SESSION_FRAGMENT = graphql(/* GraphQL */ `
|
const FRAGMENT = graphql(/* GraphQL */ `
|
||||||
fragment BrowserSession_session on BrowserSession {
|
fragment BrowserSession_session on BrowserSession {
|
||||||
id
|
id
|
||||||
createdAt
|
createdAt
|
||||||
finishedAt
|
finishedAt
|
||||||
userAgent
|
userAgent
|
||||||
|
lastActiveIp
|
||||||
|
lastActiveAt
|
||||||
lastAuthentication {
|
lastAuthentication {
|
||||||
id
|
id
|
||||||
createdAt
|
createdAt
|
||||||
@ -92,17 +95,21 @@ export const useEndBrowserSession = (
|
|||||||
};
|
};
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
session: FragmentType<typeof BROWSER_SESSION_FRAGMENT>;
|
session: FragmentType<typeof FRAGMENT>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const BrowserSession: React.FC<Props> = ({ session }) => {
|
const BrowserSession: React.FC<Props> = ({ session }) => {
|
||||||
const currentBrowserSessionId = useCurrentBrowserSessionId();
|
const currentBrowserSessionId = useCurrentBrowserSessionId();
|
||||||
const data = useFragment(BROWSER_SESSION_FRAGMENT, session);
|
const data = useFragment(FRAGMENT, session);
|
||||||
const isCurrent = data.id === currentBrowserSessionId;
|
const isCurrent = data.id === currentBrowserSessionId;
|
||||||
|
|
||||||
const onSessionEnd = useEndBrowserSession(data.id, isCurrent);
|
const onSessionEnd = useEndBrowserSession(data.id, isCurrent);
|
||||||
|
|
||||||
const createdAt = data.createdAt;
|
const createdAt = parseISO(data.createdAt);
|
||||||
|
const finishedAt = data.finishedAt ? parseISO(data.finishedAt) : undefined;
|
||||||
|
const lastActiveAt = data.lastActiveAt
|
||||||
|
? parseISO(data.lastActiveAt)
|
||||||
|
: undefined;
|
||||||
const deviceInformation = parseUserAgent(data.userAgent || undefined);
|
const deviceInformation = parseUserAgent(data.userAgent || undefined);
|
||||||
const sessionName =
|
const sessionName =
|
||||||
sessionNameFromDeviceInformation(deviceInformation) || "Browser session";
|
sessionNameFromDeviceInformation(deviceInformation) || "Browser session";
|
||||||
@ -115,8 +122,10 @@ const BrowserSession: React.FC<Props> = ({ session }) => {
|
|||||||
id={data.id}
|
id={data.id}
|
||||||
name={name}
|
name={name}
|
||||||
createdAt={createdAt}
|
createdAt={createdAt}
|
||||||
finishedAt={data.finishedAt}
|
finishedAt={finishedAt}
|
||||||
isCurrent={isCurrent}
|
isCurrent={isCurrent}
|
||||||
|
lastActiveIp={data.lastActiveIp || undefined}
|
||||||
|
lastActiveAt={lastActiveAt}
|
||||||
>
|
>
|
||||||
{!data.finishedAt && <EndSessionButton endSession={onSessionEnd} />}
|
{!data.finishedAt && <EndSessionButton endSession={onSessionEnd} />}
|
||||||
</Session>
|
</Session>
|
||||||
|
@ -70,7 +70,7 @@ const OAuth2ClientDetail: React.FC<Props> = ({ client }) => {
|
|||||||
<BlockList>
|
<BlockList>
|
||||||
<header className={styles.header}>
|
<header className={styles.header}>
|
||||||
<ClientAvatar
|
<ClientAvatar
|
||||||
logoUri={data.logoUri}
|
logoUri={data.logoUri || undefined}
|
||||||
name={data.clientName || data.clientId}
|
name={data.clientName || data.clientId}
|
||||||
size="1.5rem"
|
size="1.5rem"
|
||||||
/>
|
/>
|
||||||
|
@ -17,28 +17,30 @@
|
|||||||
import { create } from "react-test-renderer";
|
import { create } from "react-test-renderer";
|
||||||
import { describe, expect, it, beforeAll } from "vitest";
|
import { describe, expect, it, beforeAll } from "vitest";
|
||||||
|
|
||||||
import { FragmentType } from "../gql/fragment-masking";
|
import { makeFragmentData } from "../gql";
|
||||||
import { WithLocation } from "../test-utils/WithLocation";
|
import { WithLocation } from "../test-utils/WithLocation";
|
||||||
import { mockLocale } from "../test-utils/mockLocale";
|
import { mockLocale } from "../test-utils/mockLocale";
|
||||||
|
|
||||||
import CompatSession, { COMPAT_SESSION_FRAGMENT } from "./CompatSession";
|
import CompatSession, { FRAGMENT } from "./CompatSession";
|
||||||
|
|
||||||
describe("<CompatSession />", () => {
|
describe("<CompatSession />", () => {
|
||||||
const session = {
|
const baseSession = {
|
||||||
id: "session-id",
|
id: "session-id",
|
||||||
deviceId: "abcd1234",
|
deviceId: "abcd1234",
|
||||||
createdAt: "2023-06-29T03:35:17.451292+00:00",
|
createdAt: "2023-06-29T03:35:17.451292+00:00",
|
||||||
|
lastActiveIp: "1.2.3.4",
|
||||||
ssoLogin: {
|
ssoLogin: {
|
||||||
id: "test-id",
|
id: "test-id",
|
||||||
redirectUri: "https://element.io",
|
redirectUri: "https://element.io",
|
||||||
},
|
},
|
||||||
} as FragmentType<typeof COMPAT_SESSION_FRAGMENT>;
|
};
|
||||||
|
|
||||||
const finishedAt = "2023-06-29T03:35:19.451292+00:00";
|
const finishedAt = "2023-06-29T03:35:19.451292+00:00";
|
||||||
|
|
||||||
beforeAll(() => mockLocale());
|
beforeAll(() => mockLocale());
|
||||||
|
|
||||||
it("renders an active session", () => {
|
it("renders an active session", () => {
|
||||||
|
const session = makeFragmentData(baseSession, FRAGMENT);
|
||||||
const component = create(
|
const component = create(
|
||||||
<WithLocation>
|
<WithLocation>
|
||||||
<CompatSession session={session} />
|
<CompatSession session={session} />
|
||||||
@ -48,13 +50,16 @@ describe("<CompatSession />", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("renders a finished session", () => {
|
it("renders a finished session", () => {
|
||||||
const finishedSession = {
|
const session = makeFragmentData(
|
||||||
...session,
|
{
|
||||||
finishedAt,
|
...baseSession,
|
||||||
};
|
finishedAt,
|
||||||
|
},
|
||||||
|
FRAGMENT,
|
||||||
|
);
|
||||||
const component = create(
|
const component = create(
|
||||||
<WithLocation>
|
<WithLocation>
|
||||||
<CompatSession session={finishedSession} />
|
<CompatSession session={session} />
|
||||||
</WithLocation>,
|
</WithLocation>,
|
||||||
);
|
);
|
||||||
expect(component.toJSON()).toMatchSnapshot();
|
expect(component.toJSON()).toMatchSnapshot();
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
import { parseISO } from "date-fns";
|
||||||
import { atom, useSetAtom } from "jotai";
|
import { atom, useSetAtom } from "jotai";
|
||||||
import { atomFamily } from "jotai/utils";
|
import { atomFamily } from "jotai/utils";
|
||||||
import { atomWithMutation } from "jotai-urql";
|
import { atomWithMutation } from "jotai-urql";
|
||||||
@ -22,12 +23,14 @@ import { Link } from "../routing";
|
|||||||
import { Session } from "./Session";
|
import { Session } from "./Session";
|
||||||
import EndSessionButton from "./Session/EndSessionButton";
|
import EndSessionButton from "./Session/EndSessionButton";
|
||||||
|
|
||||||
export const COMPAT_SESSION_FRAGMENT = graphql(/* GraphQL */ `
|
export const FRAGMENT = graphql(/* GraphQL */ `
|
||||||
fragment CompatSession_session on CompatSession {
|
fragment CompatSession_session on CompatSession {
|
||||||
id
|
id
|
||||||
createdAt
|
createdAt
|
||||||
deviceId
|
deviceId
|
||||||
finishedAt
|
finishedAt
|
||||||
|
lastActiveIp
|
||||||
|
lastActiveAt
|
||||||
ssoLogin {
|
ssoLogin {
|
||||||
id
|
id
|
||||||
redirectUri
|
redirectUri
|
||||||
@ -81,9 +84,9 @@ export const simplifyUrl = (url: string): string => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const CompatSession: React.FC<{
|
const CompatSession: React.FC<{
|
||||||
session: FragmentType<typeof COMPAT_SESSION_FRAGMENT>;
|
session: FragmentType<typeof FRAGMENT>;
|
||||||
}> = ({ session }) => {
|
}> = ({ session }) => {
|
||||||
const data = useFragment(COMPAT_SESSION_FRAGMENT, session);
|
const data = useFragment(FRAGMENT, session);
|
||||||
const endCompatSession = useSetAtom(endCompatSessionFamily(data.id));
|
const endCompatSession = useSetAtom(endCompatSessionFamily(data.id));
|
||||||
|
|
||||||
const onSessionEnd = async (): Promise<void> => {
|
const onSessionEnd = async (): Promise<void> => {
|
||||||
@ -98,13 +101,21 @@ const CompatSession: React.FC<{
|
|||||||
? simplifyUrl(data.ssoLogin.redirectUri)
|
? simplifyUrl(data.ssoLogin.redirectUri)
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
|
const createdAt = parseISO(data.createdAt);
|
||||||
|
const finishedAt = data.finishedAt ? parseISO(data.finishedAt) : undefined;
|
||||||
|
const lastActiveAt = data.lastActiveAt
|
||||||
|
? parseISO(data.lastActiveAt)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Session
|
<Session
|
||||||
id={data.id}
|
id={data.id}
|
||||||
name={sessionName}
|
name={sessionName}
|
||||||
createdAt={data.createdAt}
|
createdAt={createdAt}
|
||||||
finishedAt={data.finishedAt || undefined}
|
finishedAt={finishedAt}
|
||||||
clientName={clientName}
|
clientName={clientName}
|
||||||
|
lastActiveIp={data.lastActiveIp || undefined}
|
||||||
|
lastActiveAt={lastActiveAt}
|
||||||
>
|
>
|
||||||
{!data.finishedAt && <EndSessionButton endSession={onSessionEnd} />}
|
{!data.finishedAt && <EndSessionButton endSession={onSessionEnd} />}
|
||||||
</Session>
|
</Session>
|
||||||
|
@ -17,26 +17,25 @@
|
|||||||
import { create } from "react-test-renderer";
|
import { create } from "react-test-renderer";
|
||||||
import { describe, expect, it, beforeAll } from "vitest";
|
import { describe, expect, it, beforeAll } from "vitest";
|
||||||
|
|
||||||
import { FragmentType } from "../gql/fragment-masking";
|
import { makeFragmentData } from "../gql";
|
||||||
import { WithLocation } from "../test-utils/WithLocation";
|
import { WithLocation } from "../test-utils/WithLocation";
|
||||||
import { mockLocale } from "../test-utils/mockLocale";
|
import { mockLocale } from "../test-utils/mockLocale";
|
||||||
|
|
||||||
import OAuth2Session, { OAUTH2_SESSION_FRAGMENT } from "./OAuth2Session";
|
import OAuth2Session, { FRAGMENT } from "./OAuth2Session";
|
||||||
|
|
||||||
describe("<OAuth2Session />", () => {
|
describe("<OAuth2Session />", () => {
|
||||||
const defaultProps = {
|
const defaultSession = {
|
||||||
session: {
|
id: "session-id",
|
||||||
id: "session-id",
|
scope:
|
||||||
scope:
|
"openid urn:matrix:org.matrix.msc2967.client:api:* urn:matrix:org.matrix.msc2967.client:device:abcd1234",
|
||||||
"openid urn:matrix:org.matrix.msc2967.client:api:* urn:matrix:org.matrix.msc2967.client:device:abcd1234",
|
createdAt: "2023-06-29T03:35:17.451292+00:00",
|
||||||
createdAt: "2023-06-29T03:35:17.451292+00:00",
|
lastActiveIp: "1.2.3.4",
|
||||||
client: {
|
client: {
|
||||||
id: "test-id",
|
id: "test-id",
|
||||||
clientId: "test-client-id",
|
clientId: "test-client-id",
|
||||||
clientName: "Element",
|
clientName: "Element",
|
||||||
clientUri: "https://element.io",
|
clientUri: "https://element.io",
|
||||||
},
|
},
|
||||||
} as FragmentType<typeof OAUTH2_SESSION_FRAGMENT>,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const finishedAt = "2023-06-29T03:35:19.451292+00:00";
|
const finishedAt = "2023-06-29T03:35:19.451292+00:00";
|
||||||
@ -44,22 +43,27 @@ describe("<OAuth2Session />", () => {
|
|||||||
beforeAll(() => mockLocale());
|
beforeAll(() => mockLocale());
|
||||||
|
|
||||||
it("renders an active session", () => {
|
it("renders an active session", () => {
|
||||||
|
const session = makeFragmentData(defaultSession, FRAGMENT);
|
||||||
|
|
||||||
const component = create(
|
const component = create(
|
||||||
<WithLocation>
|
<WithLocation>
|
||||||
<OAuth2Session {...defaultProps} />
|
<OAuth2Session session={session} />
|
||||||
</WithLocation>,
|
</WithLocation>,
|
||||||
);
|
);
|
||||||
expect(component.toJSON()).toMatchSnapshot();
|
expect(component.toJSON()).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("renders a finished session", () => {
|
it("renders a finished session", () => {
|
||||||
const finishedSession = {
|
const session = makeFragmentData(
|
||||||
...defaultProps.session,
|
{
|
||||||
finishedAt,
|
...defaultSession,
|
||||||
};
|
finishedAt,
|
||||||
|
},
|
||||||
|
FRAGMENT,
|
||||||
|
);
|
||||||
const component = create(
|
const component = create(
|
||||||
<WithLocation>
|
<WithLocation>
|
||||||
<OAuth2Session session={finishedSession} />
|
<OAuth2Session session={session} />
|
||||||
</WithLocation>,
|
</WithLocation>,
|
||||||
);
|
);
|
||||||
expect(component.toJSON()).toMatchSnapshot();
|
expect(component.toJSON()).toMatchSnapshot();
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
import { parseISO } from "date-fns";
|
||||||
import { atom, useSetAtom } from "jotai";
|
import { atom, useSetAtom } from "jotai";
|
||||||
import { atomFamily } from "jotai/utils";
|
import { atomFamily } from "jotai/utils";
|
||||||
import { atomWithMutation } from "jotai-urql";
|
import { atomWithMutation } from "jotai-urql";
|
||||||
@ -23,36 +24,23 @@ import { getDeviceIdFromScope } from "../utils/deviceIdFromScope";
|
|||||||
import { Session } from "./Session";
|
import { Session } from "./Session";
|
||||||
import EndSessionButton from "./Session/EndSessionButton";
|
import EndSessionButton from "./Session/EndSessionButton";
|
||||||
|
|
||||||
export const OAUTH2_SESSION_FRAGMENT = graphql(/* GraphQL */ `
|
export const FRAGMENT = graphql(/* GraphQL */ `
|
||||||
fragment OAuth2Session_session on Oauth2Session {
|
fragment OAuth2Session_session on Oauth2Session {
|
||||||
id
|
id
|
||||||
scope
|
scope
|
||||||
createdAt
|
createdAt
|
||||||
finishedAt
|
finishedAt
|
||||||
|
lastActiveIp
|
||||||
|
lastActiveAt
|
||||||
client {
|
client {
|
||||||
id
|
id
|
||||||
clientId
|
clientId
|
||||||
clientName
|
clientName
|
||||||
clientUri
|
|
||||||
logoUri
|
logoUri
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`);
|
`);
|
||||||
|
|
||||||
export type Oauth2SessionType = {
|
|
||||||
id: string;
|
|
||||||
scope: string;
|
|
||||||
createdAt: string;
|
|
||||||
finishedAt: string | null;
|
|
||||||
client: {
|
|
||||||
id: string;
|
|
||||||
clientId: string;
|
|
||||||
clientName: string;
|
|
||||||
clientUri: string;
|
|
||||||
logoUri: string | null;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const END_SESSION_MUTATION = graphql(/* GraphQL */ `
|
const END_SESSION_MUTATION = graphql(/* GraphQL */ `
|
||||||
mutation EndOAuth2Session($id: ID!) {
|
mutation EndOAuth2Session($id: ID!) {
|
||||||
endOauth2Session(input: { oauth2SessionId: $id }) {
|
endOauth2Session(input: { oauth2SessionId: $id }) {
|
||||||
@ -78,14 +66,11 @@ export const endSessionFamily = atomFamily((id: string) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
session: FragmentType<typeof OAUTH2_SESSION_FRAGMENT>;
|
session: FragmentType<typeof FRAGMENT>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const OAuth2Session: React.FC<Props> = ({ session }) => {
|
const OAuth2Session: React.FC<Props> = ({ session }) => {
|
||||||
const data = useFragment(
|
const data = useFragment(FRAGMENT, session);
|
||||||
OAUTH2_SESSION_FRAGMENT,
|
|
||||||
session,
|
|
||||||
) as Oauth2SessionType;
|
|
||||||
const endSession = useSetAtom(endSessionFamily(data.id));
|
const endSession = useSetAtom(endSessionFamily(data.id));
|
||||||
|
|
||||||
const onSessionEnd = async (): Promise<void> => {
|
const onSessionEnd = async (): Promise<void> => {
|
||||||
@ -98,14 +83,22 @@ const OAuth2Session: React.FC<Props> = ({ session }) => {
|
|||||||
<Link route={{ type: "session", id: deviceId }}>{deviceId}</Link>
|
<Link route={{ type: "session", id: deviceId }}>{deviceId}</Link>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const createdAt = parseISO(data.createdAt);
|
||||||
|
const finishedAt = data.finishedAt ? parseISO(data.finishedAt) : undefined;
|
||||||
|
const lastActiveAt = data.lastActiveAt
|
||||||
|
? parseISO(data.lastActiveAt)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Session
|
<Session
|
||||||
id={data.id}
|
id={data.id}
|
||||||
name={name}
|
name={name}
|
||||||
createdAt={data.createdAt}
|
createdAt={createdAt}
|
||||||
finishedAt={data.finishedAt || undefined}
|
finishedAt={finishedAt}
|
||||||
clientName={data.client.clientName}
|
clientName={data.client.clientName || data.client.clientId || undefined}
|
||||||
clientLogoUri={data.client.logoUri || undefined}
|
clientLogoUri={data.client.logoUri || undefined}
|
||||||
|
lastActiveIp={data.lastActiveIp || undefined}
|
||||||
|
lastActiveAt={lastActiveAt}
|
||||||
>
|
>
|
||||||
{!data.finishedAt && <EndSessionButton endSession={onSessionEnd} />}
|
{!data.finishedAt && <EndSessionButton endSession={onSessionEnd} />}
|
||||||
</Session>
|
</Session>
|
||||||
|
@ -13,40 +13,44 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import type { Meta, StoryObj } from "@storybook/react";
|
import type { Meta, StoryObj } from "@storybook/react";
|
||||||
|
import { parseISO, subDays, subHours } from "date-fns";
|
||||||
|
|
||||||
import LastActive from "./LastActive";
|
import LastActive from "./LastActive";
|
||||||
|
|
||||||
type Props = {
|
|
||||||
lastActiveTimestamp: number;
|
|
||||||
now: number;
|
|
||||||
};
|
|
||||||
const Template: React.FC<Props> = ({ lastActiveTimestamp, now }) => {
|
|
||||||
return <LastActive lastActiveTimestamp={lastActiveTimestamp} now={now} />;
|
|
||||||
};
|
|
||||||
|
|
||||||
const meta = {
|
const meta = {
|
||||||
title: "UI/Session/Last active time",
|
title: "UI/Session/Last active time",
|
||||||
component: Template,
|
component: LastActive,
|
||||||
|
argTypes: {
|
||||||
|
lastActive: { control: { type: "date" } },
|
||||||
|
now: { control: { type: "date" } },
|
||||||
|
},
|
||||||
tags: ["autodocs"],
|
tags: ["autodocs"],
|
||||||
} satisfies Meta<typeof Template>;
|
} satisfies Meta<typeof LastActive>;
|
||||||
|
|
||||||
export default meta;
|
export default meta;
|
||||||
type Story = StoryObj<typeof Template>;
|
type Story = StoryObj<typeof LastActive>;
|
||||||
|
|
||||||
const now = 1694999531800;
|
const now = parseISO("2023-09-18T01:12:00.000Z");
|
||||||
const ONE_DAY_MS = 24 * 60 * 60 * 1000;
|
|
||||||
|
|
||||||
export const Basic: Story = {
|
export const Basic: Story = {
|
||||||
args: {
|
args: {
|
||||||
// yesterday
|
// An hour ago
|
||||||
lastActiveTimestamp: now - ONE_DAY_MS,
|
lastActive: subHours(now, 1),
|
||||||
|
now,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ActiveThreeDaysAgo: Story = {
|
||||||
|
args: {
|
||||||
|
// Three days ago
|
||||||
|
lastActive: subDays(now, 3),
|
||||||
now,
|
now,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ActiveNow: Story = {
|
export const ActiveNow: Story = {
|
||||||
args: {
|
args: {
|
||||||
lastActiveTimestamp: now - 1000,
|
lastActive: now,
|
||||||
now,
|
now,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -54,7 +58,7 @@ export const ActiveNow: Story = {
|
|||||||
export const Inactive: Story = {
|
export const Inactive: Story = {
|
||||||
args: {
|
args: {
|
||||||
// 91 days ago
|
// 91 days ago
|
||||||
lastActiveTimestamp: now - 91 * ONE_DAY_MS,
|
lastActive: subDays(now, 91),
|
||||||
now,
|
now,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -20,7 +20,12 @@ import { describe, afterEach, expect, it, beforeAll } from "vitest";
|
|||||||
|
|
||||||
import { mockLocale } from "../../test-utils/mockLocale";
|
import { mockLocale } from "../../test-utils/mockLocale";
|
||||||
|
|
||||||
import Meta, { ActiveNow, Basic, Inactive } from "./LastActive.stories";
|
import Meta, {
|
||||||
|
ActiveNow,
|
||||||
|
ActiveThreeDaysAgo,
|
||||||
|
Basic,
|
||||||
|
Inactive,
|
||||||
|
} from "./LastActive.stories";
|
||||||
|
|
||||||
describe("<LastActive", () => {
|
describe("<LastActive", () => {
|
||||||
beforeAll(() => mockLocale());
|
beforeAll(() => mockLocale());
|
||||||
@ -33,6 +38,12 @@ describe("<LastActive", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("renders a default timestamp", () => {
|
it("renders a default timestamp", () => {
|
||||||
|
const Component = composeStory(ActiveThreeDaysAgo, Meta);
|
||||||
|
const { container } = render(<Component />);
|
||||||
|
expect(container).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders a relative timestamp", () => {
|
||||||
const Component = composeStory(Basic, Meta);
|
const Component = composeStory(Basic, Meta);
|
||||||
const { container } = render(<Component />);
|
const { container } = render(<Component />);
|
||||||
expect(container).toMatchSnapshot();
|
expect(container).toMatchSnapshot();
|
||||||
|
@ -12,35 +12,44 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
import { differenceInSeconds, parseISO } from "date-fns";
|
||||||
|
|
||||||
import { formatDate, formatReadableDate } from "../DateTime";
|
import { formatDate, formatReadableDate } from "../DateTime";
|
||||||
|
|
||||||
import styles from "./LastActive.module.css";
|
import styles from "./LastActive.module.css";
|
||||||
|
|
||||||
// 3 minutes
|
// 3 minutes
|
||||||
const ACTIVE_NOW_MAX_AGE = 1000 * 60 * 3;
|
const ACTIVE_NOW_MAX_AGE = 60 * 3;
|
||||||
/// 90 days
|
/// 90 days
|
||||||
const INACTIVE_MIN_AGE = 1000 * 60 * 60 * 24 * 90;
|
const INACTIVE_MIN_AGE = 60 * 60 * 24 * 90;
|
||||||
|
|
||||||
const LastActive: React.FC<{ lastActiveTimestamp: number; now?: number }> = ({
|
const LastActive: React.FC<{
|
||||||
lastActiveTimestamp,
|
lastActive: Date | string;
|
||||||
now: nowProps,
|
now?: Date | string;
|
||||||
}) => {
|
}> = ({ lastActive: lastActiveProps, now: nowProps }) => {
|
||||||
const now = nowProps || Date.now();
|
const lastActive =
|
||||||
const formattedDate = formatDate(new Date(lastActiveTimestamp));
|
typeof lastActiveProps === "string"
|
||||||
if (lastActiveTimestamp >= now - ACTIVE_NOW_MAX_AGE) {
|
? parseISO(lastActiveProps)
|
||||||
|
: lastActiveProps;
|
||||||
|
|
||||||
|
const now = nowProps
|
||||||
|
? typeof nowProps === "string"
|
||||||
|
? parseISO(nowProps)
|
||||||
|
: nowProps
|
||||||
|
: new Date();
|
||||||
|
|
||||||
|
const formattedDate = formatDate(lastActive);
|
||||||
|
if (differenceInSeconds(now, lastActive) <= ACTIVE_NOW_MAX_AGE) {
|
||||||
return (
|
return (
|
||||||
<span title={formattedDate} className={styles.active}>
|
<span title={formattedDate} className={styles.active}>
|
||||||
Active now
|
Active now
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (lastActiveTimestamp < now - INACTIVE_MIN_AGE) {
|
if (differenceInSeconds(now, lastActive) > INACTIVE_MIN_AGE) {
|
||||||
return <span title={formattedDate}>Inactive for 90+ days</span>;
|
return <span title={formattedDate}>Inactive for 90+ days</span>;
|
||||||
}
|
}
|
||||||
const relativeDate = formatReadableDate(
|
const relativeDate = formatReadableDate(lastActive, now);
|
||||||
new Date(lastActiveTimestamp),
|
|
||||||
new Date(now),
|
|
||||||
);
|
|
||||||
return <span title={formattedDate}>{`Active ${relativeDate}`}</span>;
|
return <span title={formattedDate}>{`Active ${relativeDate}`}</span>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -14,20 +14,24 @@
|
|||||||
|
|
||||||
import type { Meta, StoryObj } from "@storybook/react";
|
import type { Meta, StoryObj } from "@storybook/react";
|
||||||
import { Button } from "@vector-im/compound-web";
|
import { Button } from "@vector-im/compound-web";
|
||||||
|
import { parseISO } from "date-fns";
|
||||||
import { ReactElement } from "react";
|
import { ReactElement } from "react";
|
||||||
|
|
||||||
import BlockList from "../BlockList/BlockList";
|
import BlockList from "../BlockList/BlockList";
|
||||||
|
|
||||||
import Session, { SessionProps } from "./Session";
|
import Session from "./Session";
|
||||||
|
|
||||||
const Template: React.FC<React.PropsWithChildren<SessionProps>> = (props) => {
|
|
||||||
return <Session {...props} />;
|
|
||||||
};
|
|
||||||
|
|
||||||
const meta = {
|
const meta = {
|
||||||
title: "UI/Session/Session",
|
title: "UI/Session/Session",
|
||||||
component: Template,
|
component: Session,
|
||||||
tags: ["autodocs"],
|
tags: ["autodocs"],
|
||||||
|
|
||||||
|
argTypes: {
|
||||||
|
createdAt: { control: { type: "date" } },
|
||||||
|
finishedAt: { control: { type: "date" } },
|
||||||
|
lastActiveAt: { control: { type: "date" } },
|
||||||
|
},
|
||||||
|
|
||||||
decorators: [
|
decorators: [
|
||||||
(Story): ReactElement => (
|
(Story): ReactElement => (
|
||||||
<div style={{ width: "378px" }}>
|
<div style={{ width: "378px" }}>
|
||||||
@ -37,21 +41,22 @@ const meta = {
|
|||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
} satisfies Meta<typeof Template>;
|
} satisfies Meta<typeof Session>;
|
||||||
|
|
||||||
export default meta;
|
export default meta;
|
||||||
type Story = StoryObj<typeof Template>;
|
type Story = StoryObj<typeof Session>;
|
||||||
|
|
||||||
const defaultProps = {
|
const defaultProps = {
|
||||||
id: "oauth2_session:01H5VAGA5NYTKJVXP3HMMKDJQ0",
|
id: "oauth2_session:01H5VAGA5NYTKJVXP3HMMKDJQ0",
|
||||||
createdAt: "2023-06-29T03:35:17.451292+00:00",
|
createdAt: parseISO("2023-06-29T03:35:17.451292+00:00"),
|
||||||
};
|
};
|
||||||
|
|
||||||
export const BasicSession: Story = {
|
export const BasicSession: Story = {
|
||||||
args: {
|
args: {
|
||||||
...defaultProps,
|
...defaultProps,
|
||||||
name: "KlTqK9CRt3",
|
name: "KlTqK9CRt3",
|
||||||
ipAddress: "2001:8003:c4614:f501:3091:888a:49c7",
|
lastActiveIp: "2001:8003:c4614:f501:3091:888a:49c7",
|
||||||
|
lastActiveAt: parseISO("2023-07-29T03:35:17.451292+00:00"),
|
||||||
clientName: "Element",
|
clientName: "Element",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -60,7 +65,7 @@ export const BasicFinishedSession: Story = {
|
|||||||
args: {
|
args: {
|
||||||
...defaultProps,
|
...defaultProps,
|
||||||
name: "Chrome on Android",
|
name: "Chrome on Android",
|
||||||
finishedAt: "2023-06-30T03:35:17.451292+00:00",
|
finishedAt: parseISO("2023-06-30T03:35:17.451292+00:00"),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
import { parseISO } from "date-fns";
|
||||||
import { create } from "react-test-renderer";
|
import { create } from "react-test-renderer";
|
||||||
import { describe, expect, it, beforeAll } from "vitest";
|
import { describe, expect, it, beforeAll } from "vitest";
|
||||||
|
|
||||||
@ -22,10 +23,10 @@ import Session from "./Session";
|
|||||||
describe("<Session />", () => {
|
describe("<Session />", () => {
|
||||||
const defaultProps = {
|
const defaultProps = {
|
||||||
id: "session-id",
|
id: "session-id",
|
||||||
createdAt: "2023-06-29T03:35:17.451292+00:00",
|
createdAt: parseISO("2023-06-29T03:35:17.451292+00:00"),
|
||||||
};
|
};
|
||||||
|
|
||||||
const finishedAt = "2023-06-29T03:35:19.451292+00:00";
|
const finishedAt = parseISO("2023-06-29T03:35:19.451292+00:00");
|
||||||
|
|
||||||
beforeAll(() => mockLocale());
|
beforeAll(() => mockLocale());
|
||||||
|
|
||||||
@ -69,7 +70,7 @@ describe("<Session />", () => {
|
|||||||
{...defaultProps}
|
{...defaultProps}
|
||||||
finishedAt={finishedAt}
|
finishedAt={finishedAt}
|
||||||
clientName={clientName}
|
clientName={clientName}
|
||||||
ipAddress="127.0.0.1"
|
lastActiveIp="127.0.0.1"
|
||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
expect(component.toJSON()).toMatchSnapshot();
|
expect(component.toJSON()).toMatchSnapshot();
|
||||||
|
@ -19,21 +19,23 @@ import Block from "../Block";
|
|||||||
import DateTime from "../DateTime";
|
import DateTime from "../DateTime";
|
||||||
|
|
||||||
import ClientAvatar from "./ClientAvatar";
|
import ClientAvatar from "./ClientAvatar";
|
||||||
|
import LastActive from "./LastActive";
|
||||||
import styles from "./Session.module.css";
|
import styles from "./Session.module.css";
|
||||||
|
|
||||||
const SessionMetadata: React.FC<React.ComponentProps<typeof Body>> = (
|
const SessionMetadata: React.FC<React.ComponentProps<typeof Body>> = (
|
||||||
props,
|
props,
|
||||||
) => <Body {...props} size="sm" className={styles.sessionMetadata} />;
|
) => <Body {...props} size="sm" className={styles.sessionMetadata} />;
|
||||||
|
|
||||||
export type SessionProps = {
|
type SessionProps = {
|
||||||
id: string;
|
id: string;
|
||||||
name?: string | ReactNode;
|
name?: string | ReactNode;
|
||||||
createdAt: string;
|
createdAt: Date;
|
||||||
finishedAt?: string;
|
finishedAt?: Date;
|
||||||
clientName?: string;
|
clientName?: string;
|
||||||
clientLogoUri?: string;
|
clientLogoUri?: string;
|
||||||
isCurrent?: boolean;
|
isCurrent?: boolean;
|
||||||
ipAddress?: string;
|
lastActiveIp?: string;
|
||||||
|
lastActiveAt?: Date;
|
||||||
};
|
};
|
||||||
const Session: React.FC<React.PropsWithChildren<SessionProps>> = ({
|
const Session: React.FC<React.PropsWithChildren<SessionProps>> = ({
|
||||||
id,
|
id,
|
||||||
@ -42,7 +44,8 @@ const Session: React.FC<React.PropsWithChildren<SessionProps>> = ({
|
|||||||
finishedAt,
|
finishedAt,
|
||||||
clientName,
|
clientName,
|
||||||
clientLogoUri,
|
clientLogoUri,
|
||||||
ipAddress,
|
lastActiveIp,
|
||||||
|
lastActiveAt,
|
||||||
isCurrent,
|
isCurrent,
|
||||||
children,
|
children,
|
||||||
}) => {
|
}) => {
|
||||||
@ -60,7 +63,12 @@ const Session: React.FC<React.PropsWithChildren<SessionProps>> = ({
|
|||||||
Finished <DateTime datetime={finishedAt} />
|
Finished <DateTime datetime={finishedAt} />
|
||||||
</SessionMetadata>
|
</SessionMetadata>
|
||||||
)}
|
)}
|
||||||
{!!ipAddress && <SessionMetadata>{ipAddress}</SessionMetadata>}
|
{!!lastActiveAt && (
|
||||||
|
<SessionMetadata>
|
||||||
|
<LastActive lastActive={lastActiveAt} />
|
||||||
|
</SessionMetadata>
|
||||||
|
)}
|
||||||
|
{!!lastActiveIp && <SessionMetadata>{lastActiveIp}</SessionMetadata>}
|
||||||
{!!clientName && (
|
{!!clientName && (
|
||||||
<SessionMetadata>
|
<SessionMetadata>
|
||||||
<ClientAvatar
|
<ClientAvatar
|
||||||
|
@ -3,9 +3,19 @@
|
|||||||
exports[`<LastActive > renders a default timestamp 1`] = `
|
exports[`<LastActive > renders a default timestamp 1`] = `
|
||||||
<div>
|
<div>
|
||||||
<span
|
<span
|
||||||
title="Sun, 17 Sept 2023, 01:12"
|
title="Fri, 15 Sept 2023, 01:12"
|
||||||
>
|
>
|
||||||
Active Sun, 17 Sept 2023, 01:12
|
Active Fri, 15 Sept 2023, 01:12
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`<LastActive > renders a relative timestamp 1`] = `
|
||||||
|
<div>
|
||||||
|
<span
|
||||||
|
title="Mon, 18 Sept 2023, 00:12"
|
||||||
|
>
|
||||||
|
Active 1 hour ago
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
@ -13,9 +13,9 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import { Badge } from "@vector-im/compound-web";
|
import { Badge } from "@vector-im/compound-web";
|
||||||
|
import { parseISO } from "date-fns";
|
||||||
|
|
||||||
import { FragmentType, useFragment } from "../../gql";
|
import { FragmentType, graphql, useFragment } from "../../gql";
|
||||||
import { BROWSER_SESSION_DETAIL_FRAGMENT } from "../../pages/BrowserSession";
|
|
||||||
import {
|
import {
|
||||||
parseUserAgent,
|
parseUserAgent,
|
||||||
sessionNameFromDeviceInformation,
|
sessionNameFromDeviceInformation,
|
||||||
@ -25,17 +25,37 @@ import BlockList from "../BlockList/BlockList";
|
|||||||
import { useEndBrowserSession } from "../BrowserSession";
|
import { useEndBrowserSession } from "../BrowserSession";
|
||||||
import DateTime from "../DateTime";
|
import DateTime from "../DateTime";
|
||||||
import EndSessionButton from "../Session/EndSessionButton";
|
import EndSessionButton from "../Session/EndSessionButton";
|
||||||
|
import LastActive from "../Session/LastActive";
|
||||||
|
|
||||||
import styles from "./BrowserSessionDetail.module.css";
|
import styles from "./BrowserSessionDetail.module.css";
|
||||||
import SessionDetails from "./SessionDetails";
|
import SessionDetails from "./SessionDetails";
|
||||||
import SessionHeader from "./SessionHeader";
|
import SessionHeader from "./SessionHeader";
|
||||||
|
|
||||||
|
const FRAGMENT = graphql(/* GraphQL */ `
|
||||||
|
fragment BrowserSession_detail on BrowserSession {
|
||||||
|
id
|
||||||
|
createdAt
|
||||||
|
finishedAt
|
||||||
|
userAgent
|
||||||
|
lastActiveIp
|
||||||
|
lastActiveAt
|
||||||
|
lastAuthentication {
|
||||||
|
id
|
||||||
|
createdAt
|
||||||
|
}
|
||||||
|
user {
|
||||||
|
id
|
||||||
|
username
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
session: FragmentType<typeof BROWSER_SESSION_DETAIL_FRAGMENT>;
|
session: FragmentType<typeof FRAGMENT>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const BrowserSessionDetail: React.FC<Props> = ({ session }) => {
|
const BrowserSessionDetail: React.FC<Props> = ({ session }) => {
|
||||||
const data = useFragment(BROWSER_SESSION_DETAIL_FRAGMENT, session);
|
const data = useFragment(FRAGMENT, session);
|
||||||
const currentBrowserSessionId = useCurrentBrowserSessionId();
|
const currentBrowserSessionId = useCurrentBrowserSessionId();
|
||||||
|
|
||||||
const isCurrent = currentBrowserSessionId === data.id;
|
const isCurrent = currentBrowserSessionId === data.id;
|
||||||
@ -46,18 +66,34 @@ const BrowserSessionDetail: React.FC<Props> = ({ session }) => {
|
|||||||
sessionNameFromDeviceInformation(deviceInformation) || "Browser session";
|
sessionNameFromDeviceInformation(deviceInformation) || "Browser session";
|
||||||
|
|
||||||
const finishedAt = data.finishedAt
|
const finishedAt = data.finishedAt
|
||||||
? [{ label: "Finished", value: <DateTime datetime={data.finishedAt} /> }]
|
? [
|
||||||
|
{
|
||||||
|
label: "Finished",
|
||||||
|
value: <DateTime datetime={parseISO(data.finishedAt)} />,
|
||||||
|
},
|
||||||
|
]
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
const ipAddress = data.ipAddress
|
const lastActiveIp = data.lastActiveIp
|
||||||
? [{ label: "IP Address", value: <code>{data.ipAddress}</code> }]
|
? [{ label: "IP Address", value: <code>{data.lastActiveIp}</code> }]
|
||||||
|
: [];
|
||||||
|
|
||||||
|
const lastActiveAt = data.lastActiveAt
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
label: "Last Active",
|
||||||
|
value: <LastActive lastActive={parseISO(data.lastActiveAt)} />,
|
||||||
|
},
|
||||||
|
]
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
const lastAuthentication = data.lastAuthentication
|
const lastAuthentication = data.lastAuthentication
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
label: "Last Authentication",
|
label: "Last Authentication",
|
||||||
value: <DateTime datetime={data.lastAuthentication.createdAt} />,
|
value: (
|
||||||
|
<DateTime datetime={parseISO(data.lastAuthentication.createdAt)} />
|
||||||
|
),
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
: [];
|
: [];
|
||||||
@ -68,7 +104,8 @@ const BrowserSessionDetail: React.FC<Props> = ({ session }) => {
|
|||||||
{ label: "User Name", value: <code>{data.user.username}</code> },
|
{ label: "User Name", value: <code>{data.user.username}</code> },
|
||||||
{ label: "Signed in", value: <DateTime datetime={data.createdAt} /> },
|
{ label: "Signed in", value: <DateTime datetime={data.createdAt} /> },
|
||||||
...finishedAt,
|
...finishedAt,
|
||||||
...ipAddress,
|
...lastActiveAt,
|
||||||
|
...lastActiveIp,
|
||||||
...lastAuthentication,
|
...lastAuthentication,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -17,18 +17,19 @@
|
|||||||
import { render, cleanup } from "@testing-library/react";
|
import { render, cleanup } from "@testing-library/react";
|
||||||
import { describe, expect, it, afterEach, beforeAll } from "vitest";
|
import { describe, expect, it, afterEach, beforeAll } from "vitest";
|
||||||
|
|
||||||
import { makeFragmentData } from "../../gql/fragment-masking";
|
import { makeFragmentData } from "../../gql";
|
||||||
import { WithLocation } from "../../test-utils/WithLocation";
|
import { WithLocation } from "../../test-utils/WithLocation";
|
||||||
import { mockLocale } from "../../test-utils/mockLocale";
|
import { mockLocale } from "../../test-utils/mockLocale";
|
||||||
import { COMPAT_SESSION_FRAGMENT } from "../CompatSession";
|
|
||||||
|
|
||||||
import CompatSessionDetail from "./CompatSessionDetail";
|
import CompatSessionDetail, { FRAGMENT } from "./CompatSessionDetail";
|
||||||
|
|
||||||
describe("<CompatSessionDetail>", () => {
|
describe("<CompatSessionDetail>", () => {
|
||||||
const baseSession = {
|
const baseSession = {
|
||||||
id: "session-id",
|
id: "session-id",
|
||||||
deviceId: "abcd1234",
|
deviceId: "abcd1234",
|
||||||
createdAt: "2023-06-29T03:35:17.451292+00:00",
|
createdAt: "2023-06-29T03:35:17.451292+00:00",
|
||||||
|
lastActiveIp: "1.2.3.4",
|
||||||
|
lastActiveAt: "2023-07-29T03:35:17.451292+00:00",
|
||||||
ssoLogin: {
|
ssoLogin: {
|
||||||
id: "test-id",
|
id: "test-id",
|
||||||
redirectUri: "https://element.io",
|
redirectUri: "https://element.io",
|
||||||
@ -39,7 +40,7 @@ describe("<CompatSessionDetail>", () => {
|
|||||||
afterEach(cleanup);
|
afterEach(cleanup);
|
||||||
|
|
||||||
it("renders a compatability session details", () => {
|
it("renders a compatability session details", () => {
|
||||||
const data = makeFragmentData(baseSession, COMPAT_SESSION_FRAGMENT);
|
const data = makeFragmentData(baseSession, FRAGMENT);
|
||||||
|
|
||||||
const { container } = render(
|
const { container } = render(
|
||||||
<WithLocation>
|
<WithLocation>
|
||||||
@ -50,16 +51,13 @@ describe("<CompatSessionDetail>", () => {
|
|||||||
expect(container).toMatchSnapshot();
|
expect(container).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("renders a compatability session without an ssoLogin redirectUri", () => {
|
it("renders a compatability session without an ssoLogin", () => {
|
||||||
const data = makeFragmentData(
|
const data = makeFragmentData(
|
||||||
{
|
{
|
||||||
...baseSession,
|
...baseSession,
|
||||||
ssoLogin: {
|
ssoLogin: null,
|
||||||
id: "dfsdjfdk",
|
|
||||||
redirectUri: undefined,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
COMPAT_SESSION_FRAGMENT,
|
FRAGMENT,
|
||||||
);
|
);
|
||||||
|
|
||||||
const { container } = render(
|
const { container } = render(
|
||||||
@ -77,7 +75,7 @@ describe("<CompatSessionDetail>", () => {
|
|||||||
...baseSession,
|
...baseSession,
|
||||||
finishedAt: "2023-07-29T03:35:17.451292+00:00",
|
finishedAt: "2023-07-29T03:35:17.451292+00:00",
|
||||||
},
|
},
|
||||||
COMPAT_SESSION_FRAGMENT,
|
FRAGMENT,
|
||||||
);
|
);
|
||||||
|
|
||||||
const { getByText, queryByText } = render(
|
const { getByText, queryByText } = render(
|
||||||
|
@ -12,28 +12,41 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
import { parseISO } from "date-fns";
|
||||||
import { useSetAtom } from "jotai";
|
import { useSetAtom } from "jotai";
|
||||||
|
|
||||||
import { FragmentType, useFragment } from "../../gql";
|
import { FragmentType, graphql, useFragment } from "../../gql";
|
||||||
import BlockList from "../BlockList/BlockList";
|
import BlockList from "../BlockList/BlockList";
|
||||||
import {
|
import { endCompatSessionFamily, simplifyUrl } from "../CompatSession";
|
||||||
COMPAT_SESSION_FRAGMENT,
|
|
||||||
endCompatSessionFamily,
|
|
||||||
simplifyUrl,
|
|
||||||
} from "../CompatSession";
|
|
||||||
import DateTime from "../DateTime";
|
import DateTime from "../DateTime";
|
||||||
import ExternalLink from "../ExternalLink/ExternalLink";
|
import ExternalLink from "../ExternalLink/ExternalLink";
|
||||||
import EndSessionButton from "../Session/EndSessionButton";
|
import EndSessionButton from "../Session/EndSessionButton";
|
||||||
|
import LastActive from "../Session/LastActive";
|
||||||
|
|
||||||
import SessionDetails from "./SessionDetails";
|
import SessionDetails from "./SessionDetails";
|
||||||
import SessionHeader from "./SessionHeader";
|
import SessionHeader from "./SessionHeader";
|
||||||
|
|
||||||
|
export const FRAGMENT = graphql(/* GraphQL */ `
|
||||||
|
fragment CompatSession_detail on CompatSession {
|
||||||
|
id
|
||||||
|
createdAt
|
||||||
|
deviceId
|
||||||
|
finishedAt
|
||||||
|
lastActiveIp
|
||||||
|
lastActiveAt
|
||||||
|
ssoLogin {
|
||||||
|
id
|
||||||
|
redirectUri
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
session: FragmentType<typeof COMPAT_SESSION_FRAGMENT>;
|
session: FragmentType<typeof FRAGMENT>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const CompatSessionDetail: React.FC<Props> = ({ session }) => {
|
const CompatSessionDetail: React.FC<Props> = ({ session }) => {
|
||||||
const data = useFragment(COMPAT_SESSION_FRAGMENT, session);
|
const data = useFragment(FRAGMENT, session);
|
||||||
const endSession = useSetAtom(endCompatSessionFamily(data.id));
|
const endSession = useSetAtom(endCompatSessionFamily(data.id));
|
||||||
|
|
||||||
const onSessionEnd = async (): Promise<void> => {
|
const onSessionEnd = async (): Promise<void> => {
|
||||||
@ -41,19 +54,37 @@ const CompatSessionDetail: React.FC<Props> = ({ session }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const finishedAt = data.finishedAt
|
const finishedAt = data.finishedAt
|
||||||
? [{ label: "Finished", value: <DateTime datetime={data.finishedAt} /> }]
|
? [
|
||||||
|
{
|
||||||
|
label: "Finished",
|
||||||
|
value: <DateTime datetime={parseISO(data.finishedAt)} />,
|
||||||
|
},
|
||||||
|
]
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
const ipAddress = data.ipAddress
|
const lastActiveIp = data.lastActiveIp
|
||||||
? [{ label: "IP Address", value: <code>{data.ipAddress}</code> }]
|
? [{ label: "IP Address", value: <code>{data.lastActiveIp}</code> }]
|
||||||
|
: [];
|
||||||
|
|
||||||
|
const lastActiveAt = data.lastActiveAt
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
label: "Last Active",
|
||||||
|
value: <LastActive lastActive={parseISO(data.lastActiveAt)} />,
|
||||||
|
},
|
||||||
|
]
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
const sessionDetails = [
|
const sessionDetails = [
|
||||||
{ label: "ID", value: <code>{data.id}</code> },
|
{ label: "ID", value: <code>{data.id}</code> },
|
||||||
{ label: "Device ID", value: <code>{data.deviceId}</code> },
|
{ label: "Device ID", value: <code>{data.deviceId}</code> },
|
||||||
{ label: "Signed in", value: <DateTime datetime={data.createdAt} /> },
|
{
|
||||||
|
label: "Signed in",
|
||||||
|
value: <DateTime datetime={parseISO(data.createdAt)} />,
|
||||||
|
},
|
||||||
...finishedAt,
|
...finishedAt,
|
||||||
...ipAddress,
|
...lastActiveAt,
|
||||||
|
...lastActiveIp,
|
||||||
];
|
];
|
||||||
|
|
||||||
const clientDetails: { label: string; value: string | JSX.Element }[] = [];
|
const clientDetails: { label: string; value: string | JSX.Element }[] = [];
|
||||||
|
@ -17,12 +17,11 @@
|
|||||||
import { render, cleanup } from "@testing-library/react";
|
import { render, cleanup } from "@testing-library/react";
|
||||||
import { describe, expect, it, afterEach, beforeAll } from "vitest";
|
import { describe, expect, it, afterEach, beforeAll } from "vitest";
|
||||||
|
|
||||||
import { makeFragmentData } from "../../gql/fragment-masking";
|
import { makeFragmentData } from "../../gql";
|
||||||
import { WithLocation } from "../../test-utils/WithLocation";
|
import { WithLocation } from "../../test-utils/WithLocation";
|
||||||
import { mockLocale } from "../../test-utils/mockLocale";
|
import { mockLocale } from "../../test-utils/mockLocale";
|
||||||
import { OAUTH2_SESSION_FRAGMENT } from "../OAuth2Session";
|
|
||||||
|
|
||||||
import OAuth2SessionDetail from "./OAuth2SessionDetail";
|
import OAuth2SessionDetail, { FRAGMENT } from "./OAuth2SessionDetail";
|
||||||
|
|
||||||
describe("<OAuth2SessionDetail>", () => {
|
describe("<OAuth2SessionDetail>", () => {
|
||||||
const baseSession = {
|
const baseSession = {
|
||||||
@ -30,6 +29,8 @@ describe("<OAuth2SessionDetail>", () => {
|
|||||||
scope:
|
scope:
|
||||||
"openid urn:matrix:org.matrix.msc2967.client:api:* urn:matrix:org.matrix.msc2967.client:device:abcd1234",
|
"openid urn:matrix:org.matrix.msc2967.client:api:* urn:matrix:org.matrix.msc2967.client:device:abcd1234",
|
||||||
createdAt: "2023-06-29T03:35:17.451292+00:00",
|
createdAt: "2023-06-29T03:35:17.451292+00:00",
|
||||||
|
lastActiveAt: "2023-07-29T03:35:17.451292+00:00",
|
||||||
|
lastActiveIp: "1.2.3.4",
|
||||||
client: {
|
client: {
|
||||||
id: "test-id",
|
id: "test-id",
|
||||||
clientId: "test-client-id",
|
clientId: "test-client-id",
|
||||||
@ -42,7 +43,7 @@ describe("<OAuth2SessionDetail>", () => {
|
|||||||
afterEach(cleanup);
|
afterEach(cleanup);
|
||||||
|
|
||||||
it("renders session details", () => {
|
it("renders session details", () => {
|
||||||
const data = makeFragmentData(baseSession, OAUTH2_SESSION_FRAGMENT);
|
const data = makeFragmentData(baseSession, FRAGMENT);
|
||||||
|
|
||||||
const { container } = render(
|
const { container } = render(
|
||||||
<WithLocation>
|
<WithLocation>
|
||||||
@ -59,7 +60,7 @@ describe("<OAuth2SessionDetail>", () => {
|
|||||||
...baseSession,
|
...baseSession,
|
||||||
finishedAt: "2023-07-29T03:35:17.451292+00:00",
|
finishedAt: "2023-07-29T03:35:17.451292+00:00",
|
||||||
},
|
},
|
||||||
OAUTH2_SESSION_FRAGMENT,
|
FRAGMENT,
|
||||||
);
|
);
|
||||||
|
|
||||||
const { getByText, queryByText } = render(
|
const { getByText, queryByText } = render(
|
||||||
|
@ -12,26 +12,46 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
import { parseISO } from "date-fns";
|
||||||
import { useSetAtom } from "jotai";
|
import { useSetAtom } from "jotai";
|
||||||
|
|
||||||
import { FragmentType, useFragment } from "../../gql";
|
import { FragmentType, graphql, useFragment } from "../../gql";
|
||||||
import { Link } from "../../routing";
|
import { Link } from "../../routing";
|
||||||
import { getDeviceIdFromScope } from "../../utils/deviceIdFromScope";
|
import { getDeviceIdFromScope } from "../../utils/deviceIdFromScope";
|
||||||
import BlockList from "../BlockList/BlockList";
|
import BlockList from "../BlockList/BlockList";
|
||||||
import DateTime from "../DateTime";
|
import DateTime from "../DateTime";
|
||||||
import { OAUTH2_SESSION_FRAGMENT, endSessionFamily } from "../OAuth2Session";
|
import { endSessionFamily } from "../OAuth2Session";
|
||||||
import ClientAvatar from "../Session/ClientAvatar";
|
import ClientAvatar from "../Session/ClientAvatar";
|
||||||
import EndSessionButton from "../Session/EndSessionButton";
|
import EndSessionButton from "../Session/EndSessionButton";
|
||||||
|
import LastActive from "../Session/LastActive";
|
||||||
|
|
||||||
import SessionDetails from "./SessionDetails";
|
import SessionDetails from "./SessionDetails";
|
||||||
import SessionHeader from "./SessionHeader";
|
import SessionHeader from "./SessionHeader";
|
||||||
|
|
||||||
|
export const FRAGMENT = graphql(/* GraphQL */ `
|
||||||
|
fragment OAuth2Session_detail on Oauth2Session {
|
||||||
|
id
|
||||||
|
scope
|
||||||
|
createdAt
|
||||||
|
finishedAt
|
||||||
|
lastActiveIp
|
||||||
|
lastActiveAt
|
||||||
|
client {
|
||||||
|
id
|
||||||
|
clientId
|
||||||
|
clientName
|
||||||
|
clientUri
|
||||||
|
logoUri
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
session: FragmentType<typeof OAUTH2_SESSION_FRAGMENT>;
|
session: FragmentType<typeof FRAGMENT>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const OAuth2SessionDetail: React.FC<Props> = ({ session }) => {
|
const OAuth2SessionDetail: React.FC<Props> = ({ session }) => {
|
||||||
const data = useFragment(OAUTH2_SESSION_FRAGMENT, session);
|
const data = useFragment(FRAGMENT, session);
|
||||||
const endSession = useSetAtom(endSessionFamily(data.id));
|
const endSession = useSetAtom(endSessionFamily(data.id));
|
||||||
|
|
||||||
const onSessionEnd = async (): Promise<void> => {
|
const onSessionEnd = async (): Promise<void> => {
|
||||||
@ -43,11 +63,25 @@ const OAuth2SessionDetail: React.FC<Props> = ({ session }) => {
|
|||||||
const scopes = data.scope.split(" ");
|
const scopes = data.scope.split(" ");
|
||||||
|
|
||||||
const finishedAt = data.finishedAt
|
const finishedAt = data.finishedAt
|
||||||
? [{ label: "Finished", value: <DateTime datetime={data.createdAt} /> }]
|
? [
|
||||||
|
{
|
||||||
|
label: "Finished",
|
||||||
|
value: <DateTime datetime={parseISO(data.createdAt)} />,
|
||||||
|
},
|
||||||
|
]
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
const ipAddress = data.ipAddress
|
const lastActiveIp = data.lastActiveIp
|
||||||
? [{ label: "IP Address", value: <code>{data.ipAddress}</code> }]
|
? [{ label: "IP Address", value: <code>{data.lastActiveIp}</code> }]
|
||||||
|
: [];
|
||||||
|
|
||||||
|
const lastActiveAt = data.lastActiveAt
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
label: "Last Active",
|
||||||
|
value: <LastActive lastActive={parseISO(data.lastActiveAt)} />,
|
||||||
|
},
|
||||||
|
]
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
const sessionDetails = [
|
const sessionDetails = [
|
||||||
@ -55,15 +89,16 @@ const OAuth2SessionDetail: React.FC<Props> = ({ session }) => {
|
|||||||
{ label: "Device ID", value: <code>{deviceId}</code> },
|
{ label: "Device ID", value: <code>{deviceId}</code> },
|
||||||
{ label: "Signed in", value: <DateTime datetime={data.createdAt} /> },
|
{ label: "Signed in", value: <DateTime datetime={data.createdAt} /> },
|
||||||
...finishedAt,
|
...finishedAt,
|
||||||
...ipAddress,
|
...lastActiveAt,
|
||||||
|
...lastActiveIp,
|
||||||
{
|
{
|
||||||
label: "Scopes",
|
label: "Scopes",
|
||||||
value: (
|
value: (
|
||||||
<div>
|
<span>
|
||||||
{scopes.map((scope) => (
|
{scopes.map((scope) => (
|
||||||
<code key={scope}>{scope}</code>
|
<code key={scope}>{scope}</code>
|
||||||
))}
|
))}
|
||||||
</div>
|
</span>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
@ -89,7 +124,7 @@ const OAuth2SessionDetail: React.FC<Props> = ({ session }) => {
|
|||||||
{
|
{
|
||||||
label: "Uri",
|
label: "Uri",
|
||||||
value: (
|
value: (
|
||||||
<a target="_blank" href={data.client.clientUri}>
|
<a target="_blank" href={data.client.clientUri || undefined}>
|
||||||
{data.client.clientUri}
|
{data.client.clientUri}
|
||||||
</a>
|
</a>
|
||||||
),
|
),
|
||||||
|
@ -28,8 +28,8 @@ const QUERY = graphql(/* GraphQL */ `
|
|||||||
query SessionQuery($userId: ID!, $deviceId: String!) {
|
query SessionQuery($userId: ID!, $deviceId: String!) {
|
||||||
session(userId: $userId, deviceId: $deviceId) {
|
session(userId: $userId, deviceId: $deviceId) {
|
||||||
__typename
|
__typename
|
||||||
...CompatSession_session
|
...CompatSession_detail
|
||||||
...OAuth2Session_session
|
...OAuth2Session_detail
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`);
|
`);
|
||||||
@ -45,6 +45,11 @@ const sessionFamily = atomFamily(
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// A type-safe way to ensure we've handled all session types
|
||||||
|
const unknownSessionType = (type: never): never => {
|
||||||
|
throw new Error(`Unknown session type: ${type}`);
|
||||||
|
};
|
||||||
|
|
||||||
const SessionDetail: React.FC<{
|
const SessionDetail: React.FC<{
|
||||||
deviceId: string;
|
deviceId: string;
|
||||||
userId: string;
|
userId: string;
|
||||||
@ -70,10 +75,13 @@ const SessionDetail: React.FC<{
|
|||||||
|
|
||||||
const sessionType = session.__typename;
|
const sessionType = session.__typename;
|
||||||
|
|
||||||
if (sessionType === "Oauth2Session") {
|
switch (sessionType) {
|
||||||
return <OAuth2SessionDetail session={session} />;
|
case "CompatSession":
|
||||||
} else {
|
return <CompatSessionDetail session={session} />;
|
||||||
return <CompatSessionDetail session={session} />;
|
case "Oauth2Session":
|
||||||
|
return <OAuth2SessionDetail session={session} />;
|
||||||
|
default:
|
||||||
|
unknownSessionType(sessionType);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -94,6 +94,40 @@ exports[`<CompatSessionDetail> > renders a compatability session details 1`] = `
|
|||||||
</time>
|
</time>
|
||||||
</p>
|
</p>
|
||||||
</li>
|
</li>
|
||||||
|
<li
|
||||||
|
class="_detailRow_040867"
|
||||||
|
>
|
||||||
|
<p
|
||||||
|
class="_font-body-sm-semibold_1jx6b_45 _detailLabel_040867"
|
||||||
|
>
|
||||||
|
Last Active
|
||||||
|
</p>
|
||||||
|
<p
|
||||||
|
class="_font-body-sm-regular_1jx6b_40 _detailValue_040867"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
title="Sat, 29 Jul 2023, 03:35"
|
||||||
|
>
|
||||||
|
Active Sat, 29 Jul 2023, 03:35
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
<li
|
||||||
|
class="_detailRow_040867"
|
||||||
|
>
|
||||||
|
<p
|
||||||
|
class="_font-body-sm-semibold_1jx6b_45 _detailLabel_040867"
|
||||||
|
>
|
||||||
|
IP Address
|
||||||
|
</p>
|
||||||
|
<p
|
||||||
|
class="_font-body-sm-regular_1jx6b_40 _detailValue_040867"
|
||||||
|
>
|
||||||
|
<code>
|
||||||
|
1.2.3.4
|
||||||
|
</code>
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@ -163,7 +197,7 @@ exports[`<CompatSessionDetail> > renders a compatability session details 1`] = `
|
|||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`<CompatSessionDetail> > renders a compatability session without an ssoLogin redirectUri 1`] = `
|
exports[`<CompatSessionDetail> > renders a compatability session without an ssoLogin 1`] = `
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
class="_blockList_f8cc7f"
|
class="_blockList_f8cc7f"
|
||||||
@ -257,6 +291,40 @@ exports[`<CompatSessionDetail> > renders a compatability session without an ssoL
|
|||||||
</time>
|
</time>
|
||||||
</p>
|
</p>
|
||||||
</li>
|
</li>
|
||||||
|
<li
|
||||||
|
class="_detailRow_040867"
|
||||||
|
>
|
||||||
|
<p
|
||||||
|
class="_font-body-sm-semibold_1jx6b_45 _detailLabel_040867"
|
||||||
|
>
|
||||||
|
Last Active
|
||||||
|
</p>
|
||||||
|
<p
|
||||||
|
class="_font-body-sm-regular_1jx6b_40 _detailValue_040867"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
title="Sat, 29 Jul 2023, 03:35"
|
||||||
|
>
|
||||||
|
Active Sat, 29 Jul 2023, 03:35
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
<li
|
||||||
|
class="_detailRow_040867"
|
||||||
|
>
|
||||||
|
<p
|
||||||
|
class="_font-body-sm-semibold_1jx6b_45 _detailLabel_040867"
|
||||||
|
>
|
||||||
|
IP Address
|
||||||
|
</p>
|
||||||
|
<p
|
||||||
|
class="_font-body-sm-regular_1jx6b_40 _detailValue_040867"
|
||||||
|
>
|
||||||
|
<code>
|
||||||
|
1.2.3.4
|
||||||
|
</code>
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
|
@ -94,6 +94,40 @@ exports[`<OAuth2SessionDetail> > renders session details 1`] = `
|
|||||||
</time>
|
</time>
|
||||||
</p>
|
</p>
|
||||||
</li>
|
</li>
|
||||||
|
<li
|
||||||
|
class="_detailRow_040867"
|
||||||
|
>
|
||||||
|
<p
|
||||||
|
class="_font-body-sm-semibold_1jx6b_45 _detailLabel_040867"
|
||||||
|
>
|
||||||
|
Last Active
|
||||||
|
</p>
|
||||||
|
<p
|
||||||
|
class="_font-body-sm-regular_1jx6b_40 _detailValue_040867"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
title="Sat, 29 Jul 2023, 03:35"
|
||||||
|
>
|
||||||
|
Active Sat, 29 Jul 2023, 03:35
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
<li
|
||||||
|
class="_detailRow_040867"
|
||||||
|
>
|
||||||
|
<p
|
||||||
|
class="_font-body-sm-semibold_1jx6b_45 _detailLabel_040867"
|
||||||
|
>
|
||||||
|
IP Address
|
||||||
|
</p>
|
||||||
|
<p
|
||||||
|
class="_font-body-sm-regular_1jx6b_40 _detailValue_040867"
|
||||||
|
>
|
||||||
|
<code>
|
||||||
|
1.2.3.4
|
||||||
|
</code>
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
<li
|
<li
|
||||||
class="_detailRow_040867"
|
class="_detailRow_040867"
|
||||||
>
|
>
|
||||||
@ -105,7 +139,7 @@ exports[`<OAuth2SessionDetail> > renders session details 1`] = `
|
|||||||
<p
|
<p
|
||||||
class="_font-body-sm-regular_1jx6b_40 _detailValue_040867"
|
class="_font-body-sm-regular_1jx6b_40 _detailValue_040867"
|
||||||
>
|
>
|
||||||
<div>
|
<span>
|
||||||
<code>
|
<code>
|
||||||
openid
|
openid
|
||||||
</code>
|
</code>
|
||||||
@ -115,7 +149,7 @@ exports[`<OAuth2SessionDetail> > renders session details 1`] = `
|
|||||||
<code>
|
<code>
|
||||||
urn:matrix:org.matrix.msc2967.client:device:abcd1234
|
urn:matrix:org.matrix.msc2967.client:device:abcd1234
|
||||||
</code>
|
</code>
|
||||||
</div>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -37,6 +37,11 @@ exports[`<CompatSession /> > renders a finished session 1`] = `
|
|||||||
Thu, 29 Jun 2023, 03:35
|
Thu, 29 Jun 2023, 03:35
|
||||||
</time>
|
</time>
|
||||||
</p>
|
</p>
|
||||||
|
<p
|
||||||
|
className="_font-body-sm-regular_1jx6b_40 _sessionMetadata_634806"
|
||||||
|
>
|
||||||
|
1.2.3.4
|
||||||
|
</p>
|
||||||
<p
|
<p
|
||||||
className="_font-body-sm-regular_1jx6b_40 _sessionMetadata_634806"
|
className="_font-body-sm-regular_1jx6b_40 _sessionMetadata_634806"
|
||||||
>
|
>
|
||||||
@ -76,6 +81,11 @@ exports[`<CompatSession /> > renders an active session 1`] = `
|
|||||||
Thu, 29 Jun 2023, 03:35
|
Thu, 29 Jun 2023, 03:35
|
||||||
</time>
|
</time>
|
||||||
</p>
|
</p>
|
||||||
|
<p
|
||||||
|
className="_font-body-sm-regular_1jx6b_40 _sessionMetadata_634806"
|
||||||
|
>
|
||||||
|
1.2.3.4
|
||||||
|
</p>
|
||||||
<p
|
<p
|
||||||
className="_font-body-sm-regular_1jx6b_40 _sessionMetadata_634806"
|
className="_font-body-sm-regular_1jx6b_40 _sessionMetadata_634806"
|
||||||
>
|
>
|
||||||
|
@ -37,6 +37,11 @@ exports[`<OAuth2Session /> > renders a finished session 1`] = `
|
|||||||
Thu, 29 Jun 2023, 03:35
|
Thu, 29 Jun 2023, 03:35
|
||||||
</time>
|
</time>
|
||||||
</p>
|
</p>
|
||||||
|
<p
|
||||||
|
className="_font-body-sm-regular_1jx6b_40 _sessionMetadata_634806"
|
||||||
|
>
|
||||||
|
1.2.3.4
|
||||||
|
</p>
|
||||||
<p
|
<p
|
||||||
className="_font-body-sm-regular_1jx6b_40 _sessionMetadata_634806"
|
className="_font-body-sm-regular_1jx6b_40 _sessionMetadata_634806"
|
||||||
>
|
>
|
||||||
@ -76,6 +81,11 @@ exports[`<OAuth2Session /> > renders an active session 1`] = `
|
|||||||
Thu, 29 Jun 2023, 03:35
|
Thu, 29 Jun 2023, 03:35
|
||||||
</time>
|
</time>
|
||||||
</p>
|
</p>
|
||||||
|
<p
|
||||||
|
className="_font-body-sm-regular_1jx6b_40 _sessionMetadata_634806"
|
||||||
|
>
|
||||||
|
1.2.3.4
|
||||||
|
</p>
|
||||||
<p
|
<p
|
||||||
className="_font-body-sm-regular_1jx6b_40 _sessionMetadata_634806"
|
className="_font-body-sm-regular_1jx6b_40 _sessionMetadata_634806"
|
||||||
>
|
>
|
||||||
|
@ -17,7 +17,7 @@ const documents = {
|
|||||||
types.CurrentViewerQueryDocument,
|
types.CurrentViewerQueryDocument,
|
||||||
"\n query CurrentViewerSessionQuery {\n viewerSession {\n __typename\n ... on BrowserSession {\n id\n }\n\n ... on Anonymous {\n id\n }\n }\n }\n":
|
"\n query CurrentViewerSessionQuery {\n viewerSession {\n __typename\n ... on BrowserSession {\n id\n }\n\n ... on Anonymous {\n id\n }\n }\n }\n":
|
||||||
types.CurrentViewerSessionQueryDocument,
|
types.CurrentViewerSessionQueryDocument,
|
||||||
"\n fragment BrowserSession_session on BrowserSession {\n id\n createdAt\n finishedAt\n userAgent\n lastAuthentication {\n id\n createdAt\n }\n }\n":
|
"\n fragment BrowserSession_session on BrowserSession {\n id\n createdAt\n finishedAt\n userAgent\n lastActiveIp\n lastActiveAt\n lastAuthentication {\n id\n createdAt\n }\n }\n":
|
||||||
types.BrowserSession_SessionFragmentDoc,
|
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":
|
"\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,
|
types.EndBrowserSessionDocument,
|
||||||
@ -25,15 +25,21 @@ const documents = {
|
|||||||
types.BrowserSessionListDocument,
|
types.BrowserSessionListDocument,
|
||||||
"\n fragment OAuth2Client_detail on Oauth2Client {\n id\n clientId\n clientName\n clientUri\n logoUri\n tosUri\n policyUri\n redirectUris\n }\n":
|
"\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,
|
types.OAuth2Client_DetailFragmentDoc,
|
||||||
"\n fragment CompatSession_session on CompatSession {\n id\n createdAt\n deviceId\n finishedAt\n ssoLogin {\n id\n redirectUri\n }\n }\n":
|
"\n fragment CompatSession_session on CompatSession {\n id\n createdAt\n deviceId\n finishedAt\n lastActiveIp\n lastActiveAt\n ssoLogin {\n id\n redirectUri\n }\n }\n":
|
||||||
types.CompatSession_SessionFragmentDoc,
|
types.CompatSession_SessionFragmentDoc,
|
||||||
"\n mutation EndCompatSession($id: ID!) {\n endCompatSession(input: { compatSessionId: $id }) {\n status\n compatSession {\n id\n finishedAt\n }\n }\n }\n":
|
"\n mutation EndCompatSession($id: ID!) {\n endCompatSession(input: { compatSessionId: $id }) {\n status\n compatSession {\n id\n finishedAt\n }\n }\n }\n":
|
||||||
types.EndCompatSessionDocument,
|
types.EndCompatSessionDocument,
|
||||||
"\n fragment OAuth2Session_session on Oauth2Session {\n id\n scope\n createdAt\n finishedAt\n client {\n id\n clientId\n clientName\n clientUri\n logoUri\n }\n }\n":
|
"\n fragment OAuth2Session_session on Oauth2Session {\n id\n scope\n createdAt\n finishedAt\n lastActiveIp\n lastActiveAt\n client {\n id\n clientId\n clientName\n logoUri\n }\n }\n":
|
||||||
types.OAuth2Session_SessionFragmentDoc,
|
types.OAuth2Session_SessionFragmentDoc,
|
||||||
"\n mutation EndOAuth2Session($id: ID!) {\n endOauth2Session(input: { oauth2SessionId: $id }) {\n status\n oauth2Session {\n id\n ...OAuth2Session_session\n }\n }\n }\n":
|
"\n mutation EndOAuth2Session($id: ID!) {\n endOauth2Session(input: { oauth2SessionId: $id }) {\n status\n oauth2Session {\n id\n ...OAuth2Session_session\n }\n }\n }\n":
|
||||||
types.EndOAuth2SessionDocument,
|
types.EndOAuth2SessionDocument,
|
||||||
"\n query SessionQuery($userId: ID!, $deviceId: String!) {\n session(userId: $userId, deviceId: $deviceId) {\n __typename\n ...CompatSession_session\n ...OAuth2Session_session\n }\n }\n":
|
"\n fragment BrowserSession_detail on BrowserSession {\n id\n createdAt\n finishedAt\n userAgent\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 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 query SessionQuery($userId: ID!, $deviceId: String!) {\n session(userId: $userId, deviceId: $deviceId) {\n __typename\n ...CompatSession_detail\n ...OAuth2Session_detail\n }\n }\n":
|
||||||
types.SessionQueryDocument,
|
types.SessionQueryDocument,
|
||||||
"\n fragment UnverifiedEmailAlert on User {\n id\n unverifiedEmails: emails(first: 0, state: PENDING) {\n totalCount\n }\n }\n":
|
"\n fragment UnverifiedEmailAlert on User {\n id\n unverifiedEmails: emails(first: 0, state: PENDING) {\n totalCount\n }\n }\n":
|
||||||
types.UnverifiedEmailAlertFragmentDoc,
|
types.UnverifiedEmailAlertFragmentDoc,
|
||||||
@ -63,8 +69,6 @@ const documents = {
|
|||||||
types.VerifyEmailDocument,
|
types.VerifyEmailDocument,
|
||||||
"\n mutation ResendVerificationEmail($id: ID!) {\n sendVerificationEmail(input: { userEmailId: $id }) {\n status\n\n user {\n id\n primaryEmail {\n id\n }\n }\n\n email {\n id\n ...UserEmail_email\n }\n }\n }\n":
|
"\n mutation ResendVerificationEmail($id: ID!) {\n sendVerificationEmail(input: { userEmailId: $id }) {\n status\n\n user {\n id\n primaryEmail {\n id\n }\n }\n\n email {\n id\n ...UserEmail_email\n }\n }\n }\n":
|
||||||
types.ResendVerificationEmailDocument,
|
types.ResendVerificationEmailDocument,
|
||||||
"\n fragment BrowserSession_detail on BrowserSession {\n id\n createdAt\n finishedAt\n userAgent\n lastAuthentication {\n id\n createdAt\n }\n user {\n id\n username\n }\n }\n":
|
|
||||||
types.BrowserSession_DetailFragmentDoc,
|
|
||||||
"\n query BrowserSessionQuery($id: ID!) {\n browserSession(id: $id) {\n id\n ...BrowserSession_detail\n }\n }\n":
|
"\n query BrowserSessionQuery($id: ID!) {\n browserSession(id: $id) {\n id\n ...BrowserSession_detail\n }\n }\n":
|
||||||
types.BrowserSessionQueryDocument,
|
types.BrowserSessionQueryDocument,
|
||||||
"\n query OAuth2ClientQuery($id: ID!) {\n oauth2Client(id: $id) {\n ...OAuth2Client_detail\n }\n }\n":
|
"\n query OAuth2ClientQuery($id: ID!) {\n oauth2Client(id: $id) {\n ...OAuth2Client_detail\n }\n }\n":
|
||||||
@ -105,8 +109,8 @@ export function graphql(
|
|||||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||||
*/
|
*/
|
||||||
export function graphql(
|
export function graphql(
|
||||||
source: "\n fragment BrowserSession_session on BrowserSession {\n id\n createdAt\n finishedAt\n userAgent\n lastAuthentication {\n id\n createdAt\n }\n }\n",
|
source: "\n fragment BrowserSession_session on BrowserSession {\n id\n createdAt\n finishedAt\n userAgent\n lastActiveIp\n lastActiveAt\n lastAuthentication {\n id\n createdAt\n }\n }\n",
|
||||||
): (typeof documents)["\n fragment BrowserSession_session on BrowserSession {\n id\n createdAt\n finishedAt\n userAgent\n lastAuthentication {\n id\n createdAt\n }\n }\n"];
|
): (typeof documents)["\n fragment BrowserSession_session on BrowserSession {\n id\n createdAt\n finishedAt\n userAgent\n lastActiveIp\n lastActiveAt\n lastAuthentication {\n id\n createdAt\n }\n }\n"];
|
||||||
/**
|
/**
|
||||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||||
*/
|
*/
|
||||||
@ -129,8 +133,8 @@ export function graphql(
|
|||||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||||
*/
|
*/
|
||||||
export function graphql(
|
export function graphql(
|
||||||
source: "\n fragment CompatSession_session on CompatSession {\n id\n createdAt\n deviceId\n finishedAt\n ssoLogin {\n id\n redirectUri\n }\n }\n",
|
source: "\n fragment CompatSession_session on CompatSession {\n id\n createdAt\n deviceId\n finishedAt\n lastActiveIp\n lastActiveAt\n ssoLogin {\n id\n redirectUri\n }\n }\n",
|
||||||
): (typeof documents)["\n fragment CompatSession_session on CompatSession {\n id\n createdAt\n deviceId\n finishedAt\n ssoLogin {\n id\n redirectUri\n }\n }\n"];
|
): (typeof documents)["\n fragment CompatSession_session on CompatSession {\n id\n createdAt\n deviceId\n finishedAt\n lastActiveIp\n lastActiveAt\n ssoLogin {\n id\n redirectUri\n }\n }\n"];
|
||||||
/**
|
/**
|
||||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||||
*/
|
*/
|
||||||
@ -141,8 +145,8 @@ export function graphql(
|
|||||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||||
*/
|
*/
|
||||||
export function graphql(
|
export function graphql(
|
||||||
source: "\n fragment OAuth2Session_session on Oauth2Session {\n id\n scope\n createdAt\n finishedAt\n client {\n id\n clientId\n clientName\n clientUri\n logoUri\n }\n }\n",
|
source: "\n fragment OAuth2Session_session on Oauth2Session {\n id\n scope\n createdAt\n finishedAt\n lastActiveIp\n lastActiveAt\n client {\n id\n clientId\n clientName\n logoUri\n }\n }\n",
|
||||||
): (typeof documents)["\n fragment OAuth2Session_session on Oauth2Session {\n id\n scope\n createdAt\n finishedAt\n client {\n id\n clientId\n clientName\n clientUri\n logoUri\n }\n }\n"];
|
): (typeof documents)["\n fragment OAuth2Session_session on Oauth2Session {\n id\n scope\n createdAt\n finishedAt\n lastActiveIp\n lastActiveAt\n client {\n id\n clientId\n clientName\n logoUri\n }\n }\n"];
|
||||||
/**
|
/**
|
||||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||||
*/
|
*/
|
||||||
@ -153,8 +157,26 @@ export function graphql(
|
|||||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||||
*/
|
*/
|
||||||
export function graphql(
|
export function graphql(
|
||||||
source: "\n query SessionQuery($userId: ID!, $deviceId: String!) {\n session(userId: $userId, deviceId: $deviceId) {\n __typename\n ...CompatSession_session\n ...OAuth2Session_session\n }\n }\n",
|
source: "\n fragment BrowserSession_detail on BrowserSession {\n id\n createdAt\n finishedAt\n userAgent\n lastActiveIp\n lastActiveAt\n lastAuthentication {\n id\n createdAt\n }\n user {\n id\n username\n }\n }\n",
|
||||||
): (typeof documents)["\n query SessionQuery($userId: ID!, $deviceId: String!) {\n session(userId: $userId, deviceId: $deviceId) {\n __typename\n ...CompatSession_session\n ...OAuth2Session_session\n }\n }\n"];
|
): (typeof documents)["\n fragment BrowserSession_detail on BrowserSession {\n id\n createdAt\n finishedAt\n userAgent\n lastActiveIp\n lastActiveAt\n lastAuthentication {\n id\n createdAt\n }\n user {\n id\n username\n }\n }\n"];
|
||||||
|
/**
|
||||||
|
* 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 ssoLogin {\n id\n redirectUri\n }\n }\n",
|
||||||
|
): (typeof documents)["\n fragment CompatSession_detail on CompatSession {\n id\n createdAt\n deviceId\n finishedAt\n lastActiveIp\n lastActiveAt\n ssoLogin {\n id\n redirectUri\n }\n }\n"];
|
||||||
|
/**
|
||||||
|
* 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 documents)["\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"];
|
||||||
|
/**
|
||||||
|
* 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 SessionQuery($userId: ID!, $deviceId: String!) {\n session(userId: $userId, deviceId: $deviceId) {\n __typename\n ...CompatSession_detail\n ...OAuth2Session_detail\n }\n }\n",
|
||||||
|
): (typeof documents)["\n query SessionQuery($userId: ID!, $deviceId: String!) {\n session(userId: $userId, deviceId: $deviceId) {\n __typename\n ...CompatSession_detail\n ...OAuth2Session_detail\n }\n }\n"];
|
||||||
/**
|
/**
|
||||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||||
*/
|
*/
|
||||||
@ -239,12 +261,6 @@ export function graphql(
|
|||||||
export function graphql(
|
export function graphql(
|
||||||
source: "\n mutation ResendVerificationEmail($id: ID!) {\n sendVerificationEmail(input: { userEmailId: $id }) {\n status\n\n user {\n id\n primaryEmail {\n id\n }\n }\n\n email {\n id\n ...UserEmail_email\n }\n }\n }\n",
|
source: "\n mutation ResendVerificationEmail($id: ID!) {\n sendVerificationEmail(input: { userEmailId: $id }) {\n status\n\n user {\n id\n primaryEmail {\n id\n }\n }\n\n email {\n id\n ...UserEmail_email\n }\n }\n }\n",
|
||||||
): (typeof documents)["\n mutation ResendVerificationEmail($id: ID!) {\n sendVerificationEmail(input: { userEmailId: $id }) {\n status\n\n user {\n id\n primaryEmail {\n id\n }\n }\n\n email {\n id\n ...UserEmail_email\n }\n }\n }\n"];
|
): (typeof documents)["\n mutation ResendVerificationEmail($id: ID!) {\n sendVerificationEmail(input: { userEmailId: $id }) {\n status\n\n user {\n id\n primaryEmail {\n id\n }\n }\n\n email {\n id\n ...UserEmail_email\n }\n }\n }\n"];
|
||||||
/**
|
|
||||||
* 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 lastAuthentication {\n id\n createdAt\n }\n user {\n id\n username\n }\n }\n",
|
|
||||||
): (typeof documents)["\n fragment BrowserSession_detail on BrowserSession {\n id\n createdAt\n finishedAt\n userAgent\n lastAuthentication {\n id\n createdAt\n }\n user {\n id\n username\n }\n }\n"];
|
|
||||||
/**
|
/**
|
||||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||||
*/
|
*/
|
||||||
|
@ -32,9 +32,9 @@ export type Scalars = {
|
|||||||
*
|
*
|
||||||
* The input/output is a string in RFC3339 format.
|
* The input/output is a string in RFC3339 format.
|
||||||
*/
|
*/
|
||||||
DateTime: { input: any; output: any };
|
DateTime: { input: string; output: string };
|
||||||
/** URL is a String implementing the [URL Standard](http://url.spec.whatwg.org/) */
|
/** URL is a String implementing the [URL Standard](http://url.spec.whatwg.org/) */
|
||||||
Url: { input: any; output: any };
|
Url: { input: string; output: string };
|
||||||
};
|
};
|
||||||
|
|
||||||
/** The input for the `addEmail` mutation */
|
/** The input for the `addEmail` mutation */
|
||||||
@ -1083,13 +1083,15 @@ export type CurrentViewerSessionQueryQuery = {
|
|||||||
export type BrowserSession_SessionFragment = {
|
export type BrowserSession_SessionFragment = {
|
||||||
__typename?: "BrowserSession";
|
__typename?: "BrowserSession";
|
||||||
id: string;
|
id: string;
|
||||||
createdAt: any;
|
createdAt: string;
|
||||||
finishedAt?: any | null;
|
finishedAt?: string | null;
|
||||||
userAgent?: string | null;
|
userAgent?: string | null;
|
||||||
|
lastActiveIp?: string | null;
|
||||||
|
lastActiveAt?: string | null;
|
||||||
lastAuthentication?: {
|
lastAuthentication?: {
|
||||||
__typename?: "Authentication";
|
__typename?: "Authentication";
|
||||||
id: string;
|
id: string;
|
||||||
createdAt: any;
|
createdAt: string;
|
||||||
} | null;
|
} | null;
|
||||||
} & { " $fragmentName"?: "BrowserSession_SessionFragment" };
|
} & { " $fragmentName"?: "BrowserSession_SessionFragment" };
|
||||||
|
|
||||||
@ -1154,23 +1156,25 @@ export type OAuth2Client_DetailFragment = {
|
|||||||
id: string;
|
id: string;
|
||||||
clientId: string;
|
clientId: string;
|
||||||
clientName?: string | null;
|
clientName?: string | null;
|
||||||
clientUri?: any | null;
|
clientUri?: string | null;
|
||||||
logoUri?: any | null;
|
logoUri?: string | null;
|
||||||
tosUri?: any | null;
|
tosUri?: string | null;
|
||||||
policyUri?: any | null;
|
policyUri?: string | null;
|
||||||
redirectUris: Array<any>;
|
redirectUris: Array<string>;
|
||||||
} & { " $fragmentName"?: "OAuth2Client_DetailFragment" };
|
} & { " $fragmentName"?: "OAuth2Client_DetailFragment" };
|
||||||
|
|
||||||
export type CompatSession_SessionFragment = {
|
export type CompatSession_SessionFragment = {
|
||||||
__typename?: "CompatSession";
|
__typename?: "CompatSession";
|
||||||
id: string;
|
id: string;
|
||||||
createdAt: any;
|
createdAt: string;
|
||||||
deviceId: string;
|
deviceId: string;
|
||||||
finishedAt?: any | null;
|
finishedAt?: string | null;
|
||||||
|
lastActiveIp?: string | null;
|
||||||
|
lastActiveAt?: string | null;
|
||||||
ssoLogin?: {
|
ssoLogin?: {
|
||||||
__typename?: "CompatSsoLogin";
|
__typename?: "CompatSsoLogin";
|
||||||
id: string;
|
id: string;
|
||||||
redirectUri: any;
|
redirectUri: string;
|
||||||
} | null;
|
} | null;
|
||||||
} & { " $fragmentName"?: "CompatSession_SessionFragment" };
|
} & { " $fragmentName"?: "CompatSession_SessionFragment" };
|
||||||
|
|
||||||
@ -1186,7 +1190,7 @@ export type EndCompatSessionMutation = {
|
|||||||
compatSession?: {
|
compatSession?: {
|
||||||
__typename?: "CompatSession";
|
__typename?: "CompatSession";
|
||||||
id: string;
|
id: string;
|
||||||
finishedAt?: any | null;
|
finishedAt?: string | null;
|
||||||
} | null;
|
} | null;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@ -1195,15 +1199,16 @@ export type OAuth2Session_SessionFragment = {
|
|||||||
__typename?: "Oauth2Session";
|
__typename?: "Oauth2Session";
|
||||||
id: string;
|
id: string;
|
||||||
scope: string;
|
scope: string;
|
||||||
createdAt: any;
|
createdAt: string;
|
||||||
finishedAt?: any | null;
|
finishedAt?: string | null;
|
||||||
|
lastActiveIp?: string | null;
|
||||||
|
lastActiveAt?: string | null;
|
||||||
client: {
|
client: {
|
||||||
__typename?: "Oauth2Client";
|
__typename?: "Oauth2Client";
|
||||||
id: string;
|
id: string;
|
||||||
clientId: string;
|
clientId: string;
|
||||||
clientName?: string | null;
|
clientName?: string | null;
|
||||||
clientUri?: any | null;
|
logoUri?: string | null;
|
||||||
logoUri?: any | null;
|
|
||||||
};
|
};
|
||||||
} & { " $fragmentName"?: "OAuth2Session_SessionFragment" };
|
} & { " $fragmentName"?: "OAuth2Session_SessionFragment" };
|
||||||
|
|
||||||
@ -1226,6 +1231,55 @@ export type EndOAuth2SessionMutation = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type BrowserSession_DetailFragment = {
|
||||||
|
__typename?: "BrowserSession";
|
||||||
|
id: string;
|
||||||
|
createdAt: string;
|
||||||
|
finishedAt?: string | null;
|
||||||
|
userAgent?: string | null;
|
||||||
|
lastActiveIp?: string | null;
|
||||||
|
lastActiveAt?: string | 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;
|
||||||
|
finishedAt?: string | null;
|
||||||
|
lastActiveIp?: string | null;
|
||||||
|
lastActiveAt?: string | 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 SessionQueryQueryVariables = Exact<{
|
export type SessionQueryQueryVariables = Exact<{
|
||||||
userId: Scalars["ID"]["input"];
|
userId: Scalars["ID"]["input"];
|
||||||
deviceId: Scalars["String"]["input"];
|
deviceId: Scalars["String"]["input"];
|
||||||
@ -1236,12 +1290,12 @@ export type SessionQueryQuery = {
|
|||||||
session?:
|
session?:
|
||||||
| ({ __typename: "CompatSession" } & {
|
| ({ __typename: "CompatSession" } & {
|
||||||
" $fragmentRefs"?: {
|
" $fragmentRefs"?: {
|
||||||
CompatSession_SessionFragment: CompatSession_SessionFragment;
|
CompatSession_DetailFragment: CompatSession_DetailFragment;
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
| ({ __typename: "Oauth2Session" } & {
|
| ({ __typename: "Oauth2Session" } & {
|
||||||
" $fragmentRefs"?: {
|
" $fragmentRefs"?: {
|
||||||
OAuth2Session_SessionFragment: OAuth2Session_SessionFragment;
|
OAuth2Session_DetailFragment: OAuth2Session_DetailFragment;
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
| null;
|
| null;
|
||||||
@ -1257,7 +1311,7 @@ export type UserEmail_EmailFragment = {
|
|||||||
__typename?: "UserEmail";
|
__typename?: "UserEmail";
|
||||||
id: string;
|
id: string;
|
||||||
email: string;
|
email: string;
|
||||||
confirmedAt?: any | null;
|
confirmedAt?: string | null;
|
||||||
} & { " $fragmentName"?: "UserEmail_EmailFragment" };
|
} & { " $fragmentName"?: "UserEmail_EmailFragment" };
|
||||||
|
|
||||||
export type RemoveEmailMutationVariables = Exact<{
|
export type RemoveEmailMutationVariables = Exact<{
|
||||||
@ -1505,20 +1559,6 @@ export type ResendVerificationEmailMutation = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export type BrowserSession_DetailFragment = {
|
|
||||||
__typename?: "BrowserSession";
|
|
||||||
id: string;
|
|
||||||
createdAt: any;
|
|
||||||
finishedAt?: any | null;
|
|
||||||
userAgent?: string | null;
|
|
||||||
lastAuthentication?: {
|
|
||||||
__typename?: "Authentication";
|
|
||||||
id: string;
|
|
||||||
createdAt: any;
|
|
||||||
} | null;
|
|
||||||
user: { __typename?: "User"; id: string; username: string };
|
|
||||||
} & { " $fragmentName"?: "BrowserSession_DetailFragment" };
|
|
||||||
|
|
||||||
export type BrowserSessionQueryQueryVariables = Exact<{
|
export type BrowserSessionQueryQueryVariables = Exact<{
|
||||||
id: Scalars["ID"]["input"];
|
id: Scalars["ID"]["input"];
|
||||||
}>;
|
}>;
|
||||||
@ -1596,6 +1636,8 @@ export const BrowserSession_SessionFragmentDoc = {
|
|||||||
{ kind: "Field", name: { kind: "Name", value: "createdAt" } },
|
{ kind: "Field", name: { kind: "Name", value: "createdAt" } },
|
||||||
{ kind: "Field", name: { kind: "Name", value: "finishedAt" } },
|
{ kind: "Field", name: { kind: "Name", value: "finishedAt" } },
|
||||||
{ kind: "Field", name: { kind: "Name", value: "userAgent" } },
|
{ kind: "Field", name: { kind: "Name", value: "userAgent" } },
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "lastActiveIp" } },
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "lastActiveAt" } },
|
||||||
{
|
{
|
||||||
kind: "Field",
|
kind: "Field",
|
||||||
name: { kind: "Name", value: "lastAuthentication" },
|
name: { kind: "Name", value: "lastAuthentication" },
|
||||||
@ -1655,6 +1697,8 @@ export const CompatSession_SessionFragmentDoc = {
|
|||||||
{ kind: "Field", name: { kind: "Name", value: "createdAt" } },
|
{ kind: "Field", name: { kind: "Name", value: "createdAt" } },
|
||||||
{ kind: "Field", name: { kind: "Name", value: "deviceId" } },
|
{ kind: "Field", name: { kind: "Name", value: "deviceId" } },
|
||||||
{ kind: "Field", name: { kind: "Name", value: "finishedAt" } },
|
{ kind: "Field", name: { kind: "Name", value: "finishedAt" } },
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "lastActiveIp" } },
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "lastActiveAt" } },
|
||||||
{
|
{
|
||||||
kind: "Field",
|
kind: "Field",
|
||||||
name: { kind: "Name", value: "ssoLogin" },
|
name: { kind: "Name", value: "ssoLogin" },
|
||||||
@ -1688,6 +1732,126 @@ export const OAuth2Session_SessionFragmentDoc = {
|
|||||||
{ kind: "Field", name: { kind: "Name", value: "scope" } },
|
{ kind: "Field", name: { kind: "Name", value: "scope" } },
|
||||||
{ kind: "Field", name: { kind: "Name", value: "createdAt" } },
|
{ kind: "Field", name: { kind: "Name", value: "createdAt" } },
|
||||||
{ kind: "Field", name: { kind: "Name", value: "finishedAt" } },
|
{ kind: "Field", name: { kind: "Name", value: "finishedAt" } },
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "lastActiveIp" } },
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "lastActiveAt" } },
|
||||||
|
{
|
||||||
|
kind: "Field",
|
||||||
|
name: { kind: "Name", value: "client" },
|
||||||
|
selectionSet: {
|
||||||
|
kind: "SelectionSet",
|
||||||
|
selections: [
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "id" } },
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "clientId" } },
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "clientName" } },
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "logoUri" } },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
} as unknown as DocumentNode<OAuth2Session_SessionFragment, unknown>;
|
||||||
|
export const BrowserSession_DetailFragmentDoc = {
|
||||||
|
kind: "Document",
|
||||||
|
definitions: [
|
||||||
|
{
|
||||||
|
kind: "FragmentDefinition",
|
||||||
|
name: { kind: "Name", value: "BrowserSession_detail" },
|
||||||
|
typeCondition: {
|
||||||
|
kind: "NamedType",
|
||||||
|
name: { kind: "Name", value: "BrowserSession" },
|
||||||
|
},
|
||||||
|
selectionSet: {
|
||||||
|
kind: "SelectionSet",
|
||||||
|
selections: [
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "id" } },
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "createdAt" } },
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "finishedAt" } },
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "userAgent" } },
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "lastActiveIp" } },
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "lastActiveAt" } },
|
||||||
|
{
|
||||||
|
kind: "Field",
|
||||||
|
name: { kind: "Name", value: "lastAuthentication" },
|
||||||
|
selectionSet: {
|
||||||
|
kind: "SelectionSet",
|
||||||
|
selections: [
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "id" } },
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "createdAt" } },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
kind: "Field",
|
||||||
|
name: { kind: "Name", value: "user" },
|
||||||
|
selectionSet: {
|
||||||
|
kind: "SelectionSet",
|
||||||
|
selections: [
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "id" } },
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "username" } },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
} as unknown as DocumentNode<BrowserSession_DetailFragment, unknown>;
|
||||||
|
export const CompatSession_DetailFragmentDoc = {
|
||||||
|
kind: "Document",
|
||||||
|
definitions: [
|
||||||
|
{
|
||||||
|
kind: "FragmentDefinition",
|
||||||
|
name: { kind: "Name", value: "CompatSession_detail" },
|
||||||
|
typeCondition: {
|
||||||
|
kind: "NamedType",
|
||||||
|
name: { kind: "Name", value: "CompatSession" },
|
||||||
|
},
|
||||||
|
selectionSet: {
|
||||||
|
kind: "SelectionSet",
|
||||||
|
selections: [
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "id" } },
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "createdAt" } },
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "deviceId" } },
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "finishedAt" } },
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "lastActiveIp" } },
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "lastActiveAt" } },
|
||||||
|
{
|
||||||
|
kind: "Field",
|
||||||
|
name: { kind: "Name", value: "ssoLogin" },
|
||||||
|
selectionSet: {
|
||||||
|
kind: "SelectionSet",
|
||||||
|
selections: [
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "id" } },
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "redirectUri" } },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
} as unknown as DocumentNode<CompatSession_DetailFragment, unknown>;
|
||||||
|
export const OAuth2Session_DetailFragmentDoc = {
|
||||||
|
kind: "Document",
|
||||||
|
definitions: [
|
||||||
|
{
|
||||||
|
kind: "FragmentDefinition",
|
||||||
|
name: { kind: "Name", value: "OAuth2Session_detail" },
|
||||||
|
typeCondition: {
|
||||||
|
kind: "NamedType",
|
||||||
|
name: { kind: "Name", value: "Oauth2Session" },
|
||||||
|
},
|
||||||
|
selectionSet: {
|
||||||
|
kind: "SelectionSet",
|
||||||
|
selections: [
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "id" } },
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "scope" } },
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "createdAt" } },
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "finishedAt" } },
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "lastActiveIp" } },
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "lastActiveAt" } },
|
||||||
{
|
{
|
||||||
kind: "Field",
|
kind: "Field",
|
||||||
name: { kind: "Name", value: "client" },
|
name: { kind: "Name", value: "client" },
|
||||||
@ -1706,7 +1870,7 @@ export const OAuth2Session_SessionFragmentDoc = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
} as unknown as DocumentNode<OAuth2Session_SessionFragment, unknown>;
|
} as unknown as DocumentNode<OAuth2Session_DetailFragment, unknown>;
|
||||||
export const UnverifiedEmailAlertFragmentDoc = {
|
export const UnverifiedEmailAlertFragmentDoc = {
|
||||||
kind: "Document",
|
kind: "Document",
|
||||||
definitions: [
|
definitions: [
|
||||||
@ -1831,50 +1995,6 @@ export const UserEmail_VerifyEmailFragmentDoc = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
} as unknown as DocumentNode<UserEmail_VerifyEmailFragment, unknown>;
|
} as unknown as DocumentNode<UserEmail_VerifyEmailFragment, unknown>;
|
||||||
export const BrowserSession_DetailFragmentDoc = {
|
|
||||||
kind: "Document",
|
|
||||||
definitions: [
|
|
||||||
{
|
|
||||||
kind: "FragmentDefinition",
|
|
||||||
name: { kind: "Name", value: "BrowserSession_detail" },
|
|
||||||
typeCondition: {
|
|
||||||
kind: "NamedType",
|
|
||||||
name: { kind: "Name", value: "BrowserSession" },
|
|
||||||
},
|
|
||||||
selectionSet: {
|
|
||||||
kind: "SelectionSet",
|
|
||||||
selections: [
|
|
||||||
{ kind: "Field", name: { kind: "Name", value: "id" } },
|
|
||||||
{ kind: "Field", name: { kind: "Name", value: "createdAt" } },
|
|
||||||
{ kind: "Field", name: { kind: "Name", value: "finishedAt" } },
|
|
||||||
{ kind: "Field", name: { kind: "Name", value: "userAgent" } },
|
|
||||||
{
|
|
||||||
kind: "Field",
|
|
||||||
name: { kind: "Name", value: "lastAuthentication" },
|
|
||||||
selectionSet: {
|
|
||||||
kind: "SelectionSet",
|
|
||||||
selections: [
|
|
||||||
{ kind: "Field", name: { kind: "Name", value: "id" } },
|
|
||||||
{ kind: "Field", name: { kind: "Name", value: "createdAt" } },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
kind: "Field",
|
|
||||||
name: { kind: "Name", value: "user" },
|
|
||||||
selectionSet: {
|
|
||||||
kind: "SelectionSet",
|
|
||||||
selections: [
|
|
||||||
{ kind: "Field", name: { kind: "Name", value: "id" } },
|
|
||||||
{ kind: "Field", name: { kind: "Name", value: "username" } },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
} as unknown as DocumentNode<BrowserSession_DetailFragment, unknown>;
|
|
||||||
export const CurrentViewerQueryDocument = {
|
export const CurrentViewerQueryDocument = {
|
||||||
kind: "Document",
|
kind: "Document",
|
||||||
definitions: [
|
definitions: [
|
||||||
@ -2063,6 +2183,8 @@ export const EndBrowserSessionDocument = {
|
|||||||
{ kind: "Field", name: { kind: "Name", value: "createdAt" } },
|
{ kind: "Field", name: { kind: "Name", value: "createdAt" } },
|
||||||
{ kind: "Field", name: { kind: "Name", value: "finishedAt" } },
|
{ kind: "Field", name: { kind: "Name", value: "finishedAt" } },
|
||||||
{ kind: "Field", name: { kind: "Name", value: "userAgent" } },
|
{ kind: "Field", name: { kind: "Name", value: "userAgent" } },
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "lastActiveIp" } },
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "lastActiveAt" } },
|
||||||
{
|
{
|
||||||
kind: "Field",
|
kind: "Field",
|
||||||
name: { kind: "Name", value: "lastAuthentication" },
|
name: { kind: "Name", value: "lastAuthentication" },
|
||||||
@ -2295,6 +2417,8 @@ export const BrowserSessionListDocument = {
|
|||||||
{ kind: "Field", name: { kind: "Name", value: "createdAt" } },
|
{ kind: "Field", name: { kind: "Name", value: "createdAt" } },
|
||||||
{ kind: "Field", name: { kind: "Name", value: "finishedAt" } },
|
{ kind: "Field", name: { kind: "Name", value: "finishedAt" } },
|
||||||
{ kind: "Field", name: { kind: "Name", value: "userAgent" } },
|
{ kind: "Field", name: { kind: "Name", value: "userAgent" } },
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "lastActiveIp" } },
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "lastActiveAt" } },
|
||||||
{
|
{
|
||||||
kind: "Field",
|
kind: "Field",
|
||||||
name: { kind: "Name", value: "lastAuthentication" },
|
name: { kind: "Name", value: "lastAuthentication" },
|
||||||
@ -2465,6 +2589,8 @@ export const EndOAuth2SessionDocument = {
|
|||||||
{ kind: "Field", name: { kind: "Name", value: "scope" } },
|
{ kind: "Field", name: { kind: "Name", value: "scope" } },
|
||||||
{ kind: "Field", name: { kind: "Name", value: "createdAt" } },
|
{ kind: "Field", name: { kind: "Name", value: "createdAt" } },
|
||||||
{ kind: "Field", name: { kind: "Name", value: "finishedAt" } },
|
{ kind: "Field", name: { kind: "Name", value: "finishedAt" } },
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "lastActiveIp" } },
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "lastActiveAt" } },
|
||||||
{
|
{
|
||||||
kind: "Field",
|
kind: "Field",
|
||||||
name: { kind: "Name", value: "client" },
|
name: { kind: "Name", value: "client" },
|
||||||
@ -2474,7 +2600,6 @@ export const EndOAuth2SessionDocument = {
|
|||||||
{ kind: "Field", name: { kind: "Name", value: "id" } },
|
{ kind: "Field", name: { kind: "Name", value: "id" } },
|
||||||
{ kind: "Field", name: { kind: "Name", value: "clientId" } },
|
{ kind: "Field", name: { kind: "Name", value: "clientId" } },
|
||||||
{ kind: "Field", name: { kind: "Name", value: "clientName" } },
|
{ kind: "Field", name: { kind: "Name", value: "clientName" } },
|
||||||
{ kind: "Field", name: { kind: "Name", value: "clientUri" } },
|
|
||||||
{ kind: "Field", name: { kind: "Name", value: "logoUri" } },
|
{ kind: "Field", name: { kind: "Name", value: "logoUri" } },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -2551,11 +2676,11 @@ export const SessionQueryDocument = {
|
|||||||
{ kind: "Field", name: { kind: "Name", value: "__typename" } },
|
{ kind: "Field", name: { kind: "Name", value: "__typename" } },
|
||||||
{
|
{
|
||||||
kind: "FragmentSpread",
|
kind: "FragmentSpread",
|
||||||
name: { kind: "Name", value: "CompatSession_session" },
|
name: { kind: "Name", value: "CompatSession_detail" },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
kind: "FragmentSpread",
|
kind: "FragmentSpread",
|
||||||
name: { kind: "Name", value: "OAuth2Session_session" },
|
name: { kind: "Name", value: "OAuth2Session_detail" },
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -2565,7 +2690,7 @@ export const SessionQueryDocument = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
kind: "FragmentDefinition",
|
kind: "FragmentDefinition",
|
||||||
name: { kind: "Name", value: "CompatSession_session" },
|
name: { kind: "Name", value: "CompatSession_detail" },
|
||||||
typeCondition: {
|
typeCondition: {
|
||||||
kind: "NamedType",
|
kind: "NamedType",
|
||||||
name: { kind: "Name", value: "CompatSession" },
|
name: { kind: "Name", value: "CompatSession" },
|
||||||
@ -2577,6 +2702,8 @@ export const SessionQueryDocument = {
|
|||||||
{ kind: "Field", name: { kind: "Name", value: "createdAt" } },
|
{ kind: "Field", name: { kind: "Name", value: "createdAt" } },
|
||||||
{ kind: "Field", name: { kind: "Name", value: "deviceId" } },
|
{ kind: "Field", name: { kind: "Name", value: "deviceId" } },
|
||||||
{ kind: "Field", name: { kind: "Name", value: "finishedAt" } },
|
{ kind: "Field", name: { kind: "Name", value: "finishedAt" } },
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "lastActiveIp" } },
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "lastActiveAt" } },
|
||||||
{
|
{
|
||||||
kind: "Field",
|
kind: "Field",
|
||||||
name: { kind: "Name", value: "ssoLogin" },
|
name: { kind: "Name", value: "ssoLogin" },
|
||||||
@ -2593,7 +2720,7 @@ export const SessionQueryDocument = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
kind: "FragmentDefinition",
|
kind: "FragmentDefinition",
|
||||||
name: { kind: "Name", value: "OAuth2Session_session" },
|
name: { kind: "Name", value: "OAuth2Session_detail" },
|
||||||
typeCondition: {
|
typeCondition: {
|
||||||
kind: "NamedType",
|
kind: "NamedType",
|
||||||
name: { kind: "Name", value: "Oauth2Session" },
|
name: { kind: "Name", value: "Oauth2Session" },
|
||||||
@ -2605,6 +2732,8 @@ export const SessionQueryDocument = {
|
|||||||
{ kind: "Field", name: { kind: "Name", value: "scope" } },
|
{ kind: "Field", name: { kind: "Name", value: "scope" } },
|
||||||
{ kind: "Field", name: { kind: "Name", value: "createdAt" } },
|
{ kind: "Field", name: { kind: "Name", value: "createdAt" } },
|
||||||
{ kind: "Field", name: { kind: "Name", value: "finishedAt" } },
|
{ kind: "Field", name: { kind: "Name", value: "finishedAt" } },
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "lastActiveIp" } },
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "lastActiveAt" } },
|
||||||
{
|
{
|
||||||
kind: "Field",
|
kind: "Field",
|
||||||
name: { kind: "Name", value: "client" },
|
name: { kind: "Name", value: "client" },
|
||||||
@ -3563,6 +3692,8 @@ export const AppSessionListDocument = {
|
|||||||
{ kind: "Field", name: { kind: "Name", value: "createdAt" } },
|
{ kind: "Field", name: { kind: "Name", value: "createdAt" } },
|
||||||
{ kind: "Field", name: { kind: "Name", value: "deviceId" } },
|
{ kind: "Field", name: { kind: "Name", value: "deviceId" } },
|
||||||
{ kind: "Field", name: { kind: "Name", value: "finishedAt" } },
|
{ kind: "Field", name: { kind: "Name", value: "finishedAt" } },
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "lastActiveIp" } },
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "lastActiveAt" } },
|
||||||
{
|
{
|
||||||
kind: "Field",
|
kind: "Field",
|
||||||
name: { kind: "Name", value: "ssoLogin" },
|
name: { kind: "Name", value: "ssoLogin" },
|
||||||
@ -3591,6 +3722,8 @@ export const AppSessionListDocument = {
|
|||||||
{ kind: "Field", name: { kind: "Name", value: "scope" } },
|
{ kind: "Field", name: { kind: "Name", value: "scope" } },
|
||||||
{ kind: "Field", name: { kind: "Name", value: "createdAt" } },
|
{ kind: "Field", name: { kind: "Name", value: "createdAt" } },
|
||||||
{ kind: "Field", name: { kind: "Name", value: "finishedAt" } },
|
{ kind: "Field", name: { kind: "Name", value: "finishedAt" } },
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "lastActiveIp" } },
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "lastActiveAt" } },
|
||||||
{
|
{
|
||||||
kind: "Field",
|
kind: "Field",
|
||||||
name: { kind: "Name", value: "client" },
|
name: { kind: "Name", value: "client" },
|
||||||
@ -3600,7 +3733,6 @@ export const AppSessionListDocument = {
|
|||||||
{ kind: "Field", name: { kind: "Name", value: "id" } },
|
{ kind: "Field", name: { kind: "Name", value: "id" } },
|
||||||
{ kind: "Field", name: { kind: "Name", value: "clientId" } },
|
{ kind: "Field", name: { kind: "Name", value: "clientId" } },
|
||||||
{ kind: "Field", name: { kind: "Name", value: "clientName" } },
|
{ kind: "Field", name: { kind: "Name", value: "clientName" } },
|
||||||
{ kind: "Field", name: { kind: "Name", value: "clientUri" } },
|
|
||||||
{ kind: "Field", name: { kind: "Name", value: "logoUri" } },
|
{ kind: "Field", name: { kind: "Name", value: "logoUri" } },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -3907,6 +4039,8 @@ export const BrowserSessionQueryDocument = {
|
|||||||
{ kind: "Field", name: { kind: "Name", value: "createdAt" } },
|
{ kind: "Field", name: { kind: "Name", value: "createdAt" } },
|
||||||
{ kind: "Field", name: { kind: "Name", value: "finishedAt" } },
|
{ kind: "Field", name: { kind: "Name", value: "finishedAt" } },
|
||||||
{ kind: "Field", name: { kind: "Name", value: "userAgent" } },
|
{ kind: "Field", name: { kind: "Name", value: "userAgent" } },
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "lastActiveIp" } },
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "lastActiveAt" } },
|
||||||
{
|
{
|
||||||
kind: "Field",
|
kind: "Field",
|
||||||
name: { kind: "Name", value: "lastAuthentication" },
|
name: { kind: "Name", value: "lastAuthentication" },
|
||||||
|
@ -24,23 +24,6 @@ import BrowserSessionDetail from "../components/SessionDetail/BrowserSessionDeta
|
|||||||
import { graphql } from "../gql";
|
import { graphql } from "../gql";
|
||||||
import { isErr, unwrapErr, unwrapOk } from "../result";
|
import { isErr, unwrapErr, unwrapOk } from "../result";
|
||||||
|
|
||||||
export const BROWSER_SESSION_DETAIL_FRAGMENT = graphql(/* GraphQL */ `
|
|
||||||
fragment BrowserSession_detail on BrowserSession {
|
|
||||||
id
|
|
||||||
createdAt
|
|
||||||
finishedAt
|
|
||||||
userAgent
|
|
||||||
lastAuthentication {
|
|
||||||
id
|
|
||||||
createdAt
|
|
||||||
}
|
|
||||||
user {
|
|
||||||
id
|
|
||||||
username
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`);
|
|
||||||
|
|
||||||
const QUERY = graphql(/* GraphQL */ `
|
const QUERY = graphql(/* GraphQL */ `
|
||||||
query BrowserSessionQuery($id: ID!) {
|
query BrowserSessionQuery($id: ID!) {
|
||||||
browserSession(id: $id) {
|
browserSession(id: $id) {
|
||||||
|
@ -122,7 +122,7 @@ export default defineConfig((env) => ({
|
|||||||
proxy: {
|
proxy: {
|
||||||
// Routes mostly extracted from crates/router/src/endpoints.rs
|
// Routes mostly extracted from crates/router/src/endpoints.rs
|
||||||
"^/(|graphql.*|assets.*|\\.well-known.*|oauth2.*|login.*|logout.*|register.*|reauth.*|add-email.*|verify-email.*|change-password.*|consent.*|_matrix.*|complete-compat-sso.*)$":
|
"^/(|graphql.*|assets.*|\\.well-known.*|oauth2.*|login.*|logout.*|register.*|reauth.*|add-email.*|verify-email.*|change-password.*|consent.*|_matrix.*|complete-compat-sso.*)$":
|
||||||
"https://auth-oidc.lab.element.dev",
|
"http://127.0.0.1:8080",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user