1
0
mirror of https://github.com/matrix-org/matrix-authentication-service.git synced 2025-07-31 09:24:31 +03:00

Expose a unified session list in the GraphQL API

This commit is contained in:
Quentin Gliech
2023-09-20 20:18:02 +02:00
parent f1d420f381
commit d91b0e20e4
13 changed files with 459 additions and 177 deletions

View File

@ -12,23 +12,13 @@
// 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.
use async_graphql::{Context, Description, Enum, Object, ID}; use async_graphql::{Context, Description, Object, ID};
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use mas_storage::{user::BrowserSessionRepository, RepositoryAccess}; use mas_storage::{user::BrowserSessionRepository, RepositoryAccess};
use super::{NodeType, User}; use super::{NodeType, SessionState, User};
use crate::state::ContextExt; use crate::state::ContextExt;
/// The state of a browser session.
#[derive(Enum, Copy, Clone, Eq, PartialEq)]
pub enum BrowserSessionState {
/// The session is active.
Active,
/// The session is no longer active.
Finished,
}
/// A browser session represents a logged in user in a browser. /// A browser session represents a logged in user in a browser.
#[derive(Description)] #[derive(Description)]
pub struct BrowserSession(pub mas_data_model::BrowserSession); pub struct BrowserSession(pub mas_data_model::BrowserSession);
@ -80,11 +70,11 @@ impl BrowserSession {
} }
/// The state of the session. /// The state of the session.
pub async fn state(&self) -> BrowserSessionState { pub async fn state(&self) -> SessionState {
if self.0.finished_at.is_some() { if self.0.finished_at.is_some() {
BrowserSessionState::Finished SessionState::Finished
} else { } else {
BrowserSessionState::Active SessionState::Active
} }
} }

View File

@ -18,7 +18,7 @@ use chrono::{DateTime, Utc};
use mas_storage::{compat::CompatSessionRepository, user::UserRepository}; use mas_storage::{compat::CompatSessionRepository, user::UserRepository};
use url::Url; use url::Url;
use super::{NodeType, User}; use super::{NodeType, SessionState, User};
use crate::state::ContextExt; use crate::state::ContextExt;
/// Lazy-loaded reverse reference. /// Lazy-loaded reverse reference.
@ -57,16 +57,6 @@ impl CompatSession {
} }
} }
/// The state of a compatibility session.
#[derive(Enum, Copy, Clone, Eq, PartialEq)]
pub enum CompatSessionState {
/// The session is active.
Active,
/// The session is no longer active.
Finished,
}
/// The type of a compatibility session. /// The type of a compatibility session.
#[derive(Enum, Copy, Clone, Eq, PartialEq)] #[derive(Enum, Copy, Clone, Eq, PartialEq)]
pub enum CompatSessionType { pub enum CompatSessionType {
@ -136,10 +126,10 @@ impl CompatSession {
} }
/// The state of the session. /// The state of the session.
pub async fn state(&self) -> CompatSessionState { pub async fn state(&self) -> SessionState {
match &self.session.state { match &self.session.state {
mas_data_model::CompatSessionState::Valid => CompatSessionState::Active, mas_data_model::CompatSessionState::Valid => SessionState::Active,
mas_data_model::CompatSessionState::Finished { .. } => CompatSessionState::Finished, mas_data_model::CompatSessionState::Finished { .. } => SessionState::Finished,
} }
} }

View File

@ -22,6 +22,14 @@ pub use super::NodeType;
pub struct NodeCursor(pub NodeType, pub Ulid); pub struct NodeCursor(pub NodeType, pub Ulid);
impl NodeCursor { impl NodeCursor {
pub fn extract_for_types(&self, node_types: &[NodeType]) -> Result<Ulid, async_graphql::Error> {
if node_types.contains(&self.0) {
Ok(self.1)
} else {
Err(async_graphql::Error::new("invalid cursor"))
}
}
pub fn extract_for_type(&self, node_type: NodeType) -> Result<Ulid, async_graphql::Error> { pub fn extract_for_type(&self, node_type: NodeType) -> Result<Ulid, async_graphql::Error> {
if self.0 == node_type { if self.0 == node_type {
Ok(self.1) Ok(self.1)

View File

@ -12,7 +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.
use async_graphql::{Interface, Object}; use async_graphql::{Enum, Interface, Object};
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
mod browser_sessions; mod browser_sessions;
@ -63,3 +63,13 @@ impl PreloadedTotalCount {
.ok_or_else(|| async_graphql::Error::new("total count not preloaded")) .ok_or_else(|| async_graphql::Error::new("total count not preloaded"))
} }
} }
/// The state of a session
#[derive(Enum, Copy, Clone, Eq, PartialEq)]
pub enum SessionState {
/// The session is active.
Active,
/// The session is no longer active.
Finished,
}

View File

@ -15,25 +15,14 @@
use anyhow::Context as _; use anyhow::Context as _;
use async_graphql::{Context, Description, Enum, Object, ID}; use async_graphql::{Context, Description, Enum, Object, ID};
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use mas_data_model::SessionState;
use mas_storage::{oauth2::OAuth2ClientRepository, user::BrowserSessionRepository}; use mas_storage::{oauth2::OAuth2ClientRepository, user::BrowserSessionRepository};
use oauth2_types::{oidc::ApplicationType, scope::Scope}; use oauth2_types::{oidc::ApplicationType, scope::Scope};
use ulid::Ulid; use ulid::Ulid;
use url::Url; use url::Url;
use super::{BrowserSession, NodeType, User}; use super::{BrowserSession, NodeType, SessionState, User};
use crate::{state::ContextExt, UserId}; use crate::{state::ContextExt, UserId};
/// The state of an OAuth 2.0 session.
#[derive(Enum, Copy, Clone, Eq, PartialEq)]
pub enum OAuth2SessionState {
/// The session is active.
Active,
/// The session is no longer active.
Finished,
}
/// An OAuth 2.0 session represents a client session which used the OAuth APIs /// An OAuth 2.0 session represents a client session which used the OAuth APIs
/// to login. /// to login.
#[derive(Description)] #[derive(Description)]
@ -73,16 +62,16 @@ impl OAuth2Session {
/// When the session ended. /// When the session ended.
pub async fn finished_at(&self) -> Option<DateTime<Utc>> { pub async fn finished_at(&self) -> Option<DateTime<Utc>> {
match &self.0.state { match &self.0.state {
SessionState::Valid => None, mas_data_model::SessionState::Valid => None,
SessionState::Finished { finished_at } => Some(*finished_at), mas_data_model::SessionState::Finished { finished_at } => Some(*finished_at),
} }
} }
/// The state of the session. /// The state of the session.
pub async fn state(&self) -> OAuth2SessionState { pub async fn state(&self) -> SessionState {
match &self.0.state { match &self.0.state {
SessionState::Valid => OAuth2SessionState::Active, mas_data_model::SessionState::Valid => SessionState::Active,
SessionState::Finished { .. } => OAuth2SessionState::Finished, mas_data_model::SessionState::Finished { .. } => SessionState::Finished,
} }
} }

View File

@ -14,10 +14,11 @@
use async_graphql::{ use async_graphql::{
connection::{query, Connection, Edge, OpaqueCursor}, connection::{query, Connection, Edge, OpaqueCursor},
Context, Description, Enum, Object, ID, Context, Description, Enum, Object, Union, ID,
}; };
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use mas_storage::{ use mas_storage::{
app_session::AppSessionFilter,
compat::{CompatSessionFilter, CompatSsoLoginFilter, CompatSsoLoginRepository}, compat::{CompatSessionFilter, CompatSsoLoginFilter, CompatSsoLoginRepository},
oauth2::{OAuth2SessionFilter, OAuth2SessionRepository}, oauth2::{OAuth2SessionFilter, OAuth2SessionRepository},
upstream_oauth2::{UpstreamOAuthLinkFilter, UpstreamOAuthLinkRepository}, upstream_oauth2::{UpstreamOAuthLinkFilter, UpstreamOAuthLinkRepository},
@ -26,12 +27,10 @@ use mas_storage::{
}; };
use super::{ use super::{
browser_sessions::BrowserSessionState, compat_sessions::{CompatSessionType, CompatSsoLogin},
compat_sessions::{CompatSessionState, CompatSessionType, CompatSsoLogin},
matrix::MatrixUser, matrix::MatrixUser,
oauth::OAuth2SessionState,
BrowserSession, CompatSession, Cursor, NodeCursor, NodeType, OAuth2Session, BrowserSession, CompatSession, Cursor, NodeCursor, NodeType, OAuth2Session,
PreloadedTotalCount, UpstreamOAuth2Link, PreloadedTotalCount, SessionState, UpstreamOAuth2Link,
}; };
use crate::state::ContextExt; use crate::state::ContextExt;
@ -160,7 +159,7 @@ impl User {
ctx: &Context<'_>, ctx: &Context<'_>,
#[graphql(name = "state", desc = "List only sessions with the given state.")] #[graphql(name = "state", desc = "List only sessions with the given state.")]
state_param: Option<CompatSessionState>, state_param: Option<SessionState>,
#[graphql(name = "type", desc = "List only sessions with the given type.")] #[graphql(name = "type", desc = "List only sessions with the given type.")]
type_param: Option<CompatSessionType>, type_param: Option<CompatSessionType>,
@ -192,8 +191,8 @@ impl User {
// Build the query filter // Build the query filter
let filter = CompatSessionFilter::new().for_user(&self.0); let filter = CompatSessionFilter::new().for_user(&self.0);
let filter = match state_param { let filter = match state_param {
Some(CompatSessionState::Active) => filter.active_only(), Some(SessionState::Active) => filter.active_only(),
Some(CompatSessionState::Finished) => filter.finished_only(), Some(SessionState::Finished) => filter.finished_only(),
None => filter, None => filter,
}; };
let filter = match type_param { let filter = match type_param {
@ -239,7 +238,7 @@ impl User {
ctx: &Context<'_>, ctx: &Context<'_>,
#[graphql(name = "state", desc = "List only sessions in the given state.")] #[graphql(name = "state", desc = "List only sessions in the given state.")]
state_param: Option<BrowserSessionState>, state_param: Option<SessionState>,
#[graphql(desc = "Returns the elements in the list that come after the cursor.")] #[graphql(desc = "Returns the elements in the list that come after the cursor.")]
after: Option<String>, after: Option<String>,
@ -267,8 +266,8 @@ impl User {
let filter = BrowserSessionFilter::new().for_user(&self.0); let filter = BrowserSessionFilter::new().for_user(&self.0);
let filter = match state_param { let filter = match state_param {
Some(BrowserSessionState::Active) => filter.active_only(), Some(SessionState::Active) => filter.active_only(),
Some(BrowserSessionState::Finished) => filter.finished_only(), Some(SessionState::Finished) => filter.finished_only(),
None => filter, None => filter,
}; };
@ -377,7 +376,7 @@ impl User {
ctx: &Context<'_>, ctx: &Context<'_>,
#[graphql(name = "state", desc = "List only sessions in the given state.")] #[graphql(name = "state", desc = "List only sessions in the given state.")]
state_param: Option<OAuth2SessionState>, state_param: Option<SessionState>,
#[graphql(desc = "List only sessions for the given client.")] client: Option<ID>, #[graphql(desc = "List only sessions for the given client.")] client: Option<ID>,
@ -422,8 +421,8 @@ impl User {
let filter = OAuth2SessionFilter::new().for_user(&self.0); let filter = OAuth2SessionFilter::new().for_user(&self.0);
let filter = match state_param { let filter = match state_param {
Some(OAuth2SessionState::Active) => filter.active_only(), Some(SessionState::Active) => filter.active_only(),
Some(OAuth2SessionState::Finished) => filter.finished_only(), Some(SessionState::Finished) => filter.finished_only(),
None => filter, None => filter,
}; };
@ -525,6 +524,94 @@ impl User {
) )
.await .await
} }
/// Get the list of both compat and OAuth 2.0 sessions, chronologically
/// sorted
#[allow(clippy::too_many_arguments)]
async fn app_sessions(
&self,
ctx: &Context<'_>,
#[graphql(name = "state", desc = "List only sessions in the given state.")]
state_param: Option<SessionState>,
#[graphql(desc = "Returns the elements in the list that come after the cursor.")]
after: Option<String>,
#[graphql(desc = "Returns the elements in the list that come before the cursor.")]
before: Option<String>,
#[graphql(desc = "Returns the first *n* elements from the list.")] first: Option<i32>,
#[graphql(desc = "Returns the last *n* elements from the list.")] last: Option<i32>,
) -> Result<Connection<Cursor, AppSession, PreloadedTotalCount>, async_graphql::Error> {
let state = ctx.state();
let mut repo = state.repository().await?;
query(
after,
before,
first,
last,
|after, before, first, last| async move {
let after_id = after
.map(|x: OpaqueCursor<NodeCursor>| {
x.extract_for_types(&[NodeType::OAuth2Session, NodeType::CompatSession])
})
.transpose()?;
let before_id = before
.map(|x: OpaqueCursor<NodeCursor>| {
x.extract_for_types(&[NodeType::OAuth2Session, NodeType::CompatSession])
})
.transpose()?;
let pagination = Pagination::try_new(before_id, after_id, first, last)?;
let filter = AppSessionFilter::new().for_user(&self.0);
let filter = match state_param {
Some(SessionState::Active) => filter.active_only(),
Some(SessionState::Finished) => filter.finished_only(),
None => filter,
};
let page = repo.app_session().list(filter, pagination).await?;
let count = if ctx.look_ahead().field("totalCount").exists() {
Some(repo.app_session().count(filter).await?)
} else {
None
};
repo.cancel().await?;
let mut connection = Connection::with_additional_fields(
page.has_previous_page,
page.has_next_page,
PreloadedTotalCount(count),
);
connection
.edges
.extend(page.edges.into_iter().map(|s| match s {
mas_storage::app_session::AppSession::Compat(session) => Edge::new(
OpaqueCursor(NodeCursor(NodeType::CompatSession, session.id)),
AppSession::CompatSession(Box::new(CompatSession::new(*session))),
),
mas_storage::app_session::AppSession::OAuth2(session) => Edge::new(
OpaqueCursor(NodeCursor(NodeType::OAuth2Session, session.id)),
AppSession::OAuth2Session(Box::new(OAuth2Session(*session))),
),
}));
Ok::<_, async_graphql::Error>(connection)
},
)
.await
}
}
/// A session in an application, either a compatibility or an OAuth 2.0 one
#[derive(Union)]
enum AppSession {
CompatSession(Box<CompatSession>),
OAuth2Session(Box<OAuth2Session>),
} }
/// A user email address /// A user email address

View File

@ -110,6 +110,44 @@ type Anonymous implements Node {
id: ID! id: ID!
} }
"""
A session in an application, either a compatibility or an OAuth 2.0 one
"""
union AppSession = CompatSession | Oauth2Session
type AppSessionConnection {
"""
Information to aid in pagination.
"""
pageInfo: PageInfo!
"""
A list of edges.
"""
edges: [AppSessionEdge!]!
"""
A list of nodes.
"""
nodes: [AppSession!]!
"""
Identifies the total count of items in the connection.
"""
totalCount: Int!
}
"""
An edge in a connection.
"""
type AppSessionEdge {
"""
The item at the end of the edge
"""
node: AppSession!
"""
A cursor for use in pagination
"""
cursor: String!
}
""" """
An authentication records when a user enter their credential in a browser An authentication records when a user enter their credential in a browser
session. session.
@ -152,7 +190,7 @@ type BrowserSession implements Node & CreationEvent {
""" """
The state of the session. The state of the session.
""" """
state: BrowserSessionState! state: SessionState!
""" """
The user-agent string with which the session was created. The user-agent string with which the session was created.
""" """
@ -200,20 +238,6 @@ type BrowserSessionEdge {
cursor: String! cursor: String!
} }
"""
The state of a browser session.
"""
enum BrowserSessionState {
"""
The session is active.
"""
ACTIVE
"""
The session is no longer active.
"""
FINISHED
}
""" """
A compat session represents a client session which used the legacy Matrix A compat session represents a client session which used the legacy Matrix
login API. login API.
@ -246,7 +270,7 @@ type CompatSession implements Node & CreationEvent {
""" """
The state of the session. The state of the session.
""" """
state: CompatSessionState! state: SessionState!
""" """
The last IP address used by the session. The last IP address used by the session.
""" """
@ -290,20 +314,6 @@ type CompatSessionEdge {
cursor: String! cursor: String!
} }
"""
The state of a compatibility session.
"""
enum CompatSessionState {
"""
The session is active.
"""
ACTIVE
"""
The session is no longer active.
"""
FINISHED
}
""" """
The type of a compatibility session. The type of a compatibility session.
""" """
@ -747,7 +757,7 @@ type Oauth2Session implements Node & CreationEvent {
""" """
The state of the session. The state of the session.
""" """
state: Oauth2SessionState! state: SessionState!
""" """
The browser session which started this OAuth 2.0 session. The browser session which started this OAuth 2.0 session.
""" """
@ -799,20 +809,6 @@ type Oauth2SessionEdge {
cursor: String! cursor: String!
} }
"""
The state of an OAuth 2.0 session.
"""
enum Oauth2SessionState {
"""
The session is active.
"""
ACTIVE
"""
The session is no longer active.
"""
FINISHED
}
""" """
Information about pagination in a connection Information about pagination in a connection
""" """
@ -1008,6 +1004,20 @@ A client session, either compat or OAuth 2.0
""" """
union Session = CompatSession | Oauth2Session union Session = CompatSession | Oauth2Session
"""
The state of a session
"""
enum SessionState {
"""
The session is active.
"""
ACTIVE
"""
The session is no longer active.
"""
FINISHED
}
""" """
The input for the `addEmail` mutation The input for the `addEmail` mutation
""" """
@ -1258,7 +1268,7 @@ type User implements Node {
""" """
List only sessions with the given state. List only sessions with the given state.
""" """
state: CompatSessionState state: SessionState
""" """
List only sessions with the given type. List only sessions with the given type.
""" """
@ -1287,7 +1297,7 @@ type User implements Node {
""" """
List only sessions in the given state. List only sessions in the given state.
""" """
state: BrowserSessionState state: SessionState
""" """
Returns the elements in the list that come after the cursor. Returns the elements in the list that come after the cursor.
""" """
@ -1337,7 +1347,7 @@ type User implements Node {
""" """
List only sessions in the given state. List only sessions in the given state.
""" """
state: Oauth2SessionState state: SessionState
""" """
List only sessions for the given client. List only sessions for the given client.
""" """
@ -1380,6 +1390,32 @@ type User implements Node {
""" """
last: Int last: Int
): UpstreamOAuth2LinkConnection! ): UpstreamOAuth2LinkConnection!
"""
Get the list of both compat and OAuth 2.0 sessions, chronologically
sorted
"""
appSessions(
"""
List only sessions in the given state.
"""
state: SessionState
"""
Returns the elements in the list that come after the cursor.
"""
after: String
"""
Returns the elements in the list that come before the cursor.
"""
before: String
"""
Returns the first *n* elements from the list.
"""
first: Int
"""
Returns the last *n* elements from the list.
"""
last: Int
): AppSessionConnection!
} }
""" """

View File

@ -19,7 +19,7 @@ import { useTransition } from "react";
import { mapQueryAtom } from "../atoms"; import { mapQueryAtom } from "../atoms";
import { graphql } from "../gql"; import { graphql } from "../gql";
import { BrowserSessionState, PageInfo } from "../gql/graphql"; import { SessionState, PageInfo } from "../gql/graphql";
import { import {
atomForCurrentPagination, atomForCurrentPagination,
atomWithPagination, atomWithPagination,
@ -36,7 +36,7 @@ import { Title } from "./Typography";
const QUERY = graphql(/* GraphQL */ ` const QUERY = graphql(/* GraphQL */ `
query BrowserSessionList( query BrowserSessionList(
$userId: ID! $userId: ID!
$state: BrowserSessionState $state: SessionState
$first: Int $first: Int
$after: String $after: String
$last: Int $last: Int
@ -72,7 +72,7 @@ const QUERY = graphql(/* GraphQL */ `
} }
`); `);
const filterAtom = atom<BrowserSessionState | null>(BrowserSessionState.Active); const filterAtom = atom<SessionState | null>(SessionState.Active);
const currentPaginationAtom = atomForCurrentPagination(); const currentPaginationAtom = atomForCurrentPagination();
const browserSessionListFamily = atomFamily((userId: string) => { const browserSessionListFamily = atomFamily((userId: string) => {
@ -129,11 +129,7 @@ const BrowserSessionList: React.FC<{ userId: string }> = ({ userId }) => {
const toggleFilter = (): void => { const toggleFilter = (): void => {
startTransition(() => { startTransition(() => {
setPagination(FIRST_PAGE); setPagination(FIRST_PAGE);
setFilter( setFilter(filter === SessionState.Active ? null : SessionState.Active);
filter === BrowserSessionState.Active
? null
: BrowserSessionState.Active,
);
}); });
}; };
@ -149,7 +145,7 @@ const BrowserSessionList: React.FC<{ userId: string }> = ({ userId }) => {
<label> <label>
<input <input
type="checkbox" type="checkbox"
checked={filter === BrowserSessionState.Active} checked={filter === SessionState.Active}
onChange={toggleFilter} onChange={toggleFilter}
/>{" "} />{" "}
Active only Active only

View File

@ -19,7 +19,7 @@ import { useTransition } from "react";
import { mapQueryAtom } from "../atoms"; import { mapQueryAtom } from "../atoms";
import { graphql } from "../gql"; import { graphql } from "../gql";
import { CompatSessionState, PageInfo } from "../gql/graphql"; import { SessionState, PageInfo } from "../gql/graphql";
import { import {
atomForCurrentPagination, atomForCurrentPagination,
atomWithPagination, atomWithPagination,
@ -36,7 +36,7 @@ import { Title } from "./Typography";
const QUERY = graphql(/* GraphQL */ ` const QUERY = graphql(/* GraphQL */ `
query CompatSessionList( query CompatSessionList(
$userId: ID! $userId: ID!
$state: CompatSessionState $state: SessionState
$first: Int $first: Int
$after: String $after: String
$last: Int $last: Int
@ -71,7 +71,7 @@ const QUERY = graphql(/* GraphQL */ `
`); `);
const currentPaginationAtom = atomForCurrentPagination(); const currentPaginationAtom = atomForCurrentPagination();
const filterAtom = atom<CompatSessionState | null>(CompatSessionState.Active); const filterAtom = atom<SessionState | null>(SessionState.Active);
const compatSessionListFamily = atomFamily((userId: string) => { const compatSessionListFamily = atomFamily((userId: string) => {
const compatSessionListQuery = atomWithQuery({ const compatSessionListQuery = atomWithQuery({
@ -127,9 +127,7 @@ const CompatSessionList: React.FC<{ userId: string }> = ({ userId }) => {
const toggleFilter = (): void => { const toggleFilter = (): void => {
startTransition(() => { startTransition(() => {
setPagination(FIRST_PAGE); setPagination(FIRST_PAGE);
setFilter( setFilter(filter === SessionState.Active ? null : SessionState.Active);
filter === CompatSessionState.Active ? null : CompatSessionState.Active,
);
}); });
}; };
@ -139,7 +137,7 @@ const CompatSessionList: React.FC<{ userId: string }> = ({ userId }) => {
<label> <label>
<input <input
type="checkbox" type="checkbox"
checked={filter === CompatSessionState.Active} checked={filter === SessionState.Active}
onChange={toggleFilter} onChange={toggleFilter}
/>{" "} />{" "}
Active only Active only

View File

@ -19,7 +19,7 @@ import { useTransition } from "react";
import { mapQueryAtom } from "../atoms"; import { mapQueryAtom } from "../atoms";
import { graphql } from "../gql"; import { graphql } from "../gql";
import { Oauth2SessionState, PageInfo } from "../gql/graphql"; import { SessionState, PageInfo } from "../gql/graphql";
import { import {
atomForCurrentPagination, atomForCurrentPagination,
atomWithPagination, atomWithPagination,
@ -36,7 +36,7 @@ import { Title } from "./Typography";
const QUERY = graphql(/* GraphQL */ ` const QUERY = graphql(/* GraphQL */ `
query OAuth2SessionListQuery( query OAuth2SessionListQuery(
$userId: ID! $userId: ID!
$state: Oauth2SessionState $state: SessionState
$first: Int $first: Int
$after: String $after: String
$last: Int $last: Int
@ -72,7 +72,7 @@ const QUERY = graphql(/* GraphQL */ `
`); `);
const currentPaginationAtom = atomForCurrentPagination(); const currentPaginationAtom = atomForCurrentPagination();
const filterAtom = atom<Oauth2SessionState | null>(Oauth2SessionState.Active); const filterAtom = atom<SessionState | null>(SessionState.Active);
const oauth2SessionListFamily = atomFamily((userId: string) => { const oauth2SessionListFamily = atomFamily((userId: string) => {
const oauth2SessionListQuery = atomWithQuery({ const oauth2SessionListQuery = atomWithQuery({
@ -132,9 +132,7 @@ const OAuth2SessionList: React.FC<Props> = ({ userId }) => {
const toggleFilter = (): void => { const toggleFilter = (): void => {
startTransition(() => { startTransition(() => {
setPagination(FIRST_PAGE); setPagination(FIRST_PAGE);
setFilter( setFilter(filter === SessionState.Active ? null : SessionState.Active);
filter === Oauth2SessionState.Active ? null : Oauth2SessionState.Active,
);
}); });
}; };
@ -144,7 +142,7 @@ const OAuth2SessionList: React.FC<Props> = ({ userId }) => {
<label> <label>
<input <input
type="checkbox" type="checkbox"
checked={filter === Oauth2SessionState.Active} checked={filter === SessionState.Active}
onChange={toggleFilter} onChange={toggleFilter}
/>{" "} />{" "}
Active only Active only

View File

@ -21,7 +21,7 @@ const documents = {
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,
"\n query BrowserSessionList(\n $userId: ID!\n $state: BrowserSessionState\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n id\n browserSessions(\n first: $first\n after: $after\n last: $last\n before: $before\n state: $state\n ) {\n totalCount\n\n edges {\n cursor\n node {\n id\n ...BrowserSession_session\n }\n }\n\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n": "\n query BrowserSessionList(\n $userId: ID!\n $state: SessionState\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n id\n browserSessions(\n first: $first\n after: $after\n last: $last\n before: $before\n state: $state\n ) {\n totalCount\n\n edges {\n cursor\n node {\n id\n ...BrowserSession_session\n }\n }\n\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n":
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,
@ -29,13 +29,13 @@ const documents = {
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 query CompatSessionList(\n $userId: ID!\n $state: CompatSessionState\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n id\n compatSessions(\n first: $first\n after: $after\n last: $last\n before: $before\n state: $state\n ) {\n edges {\n node {\n id\n ...CompatSession_session\n }\n }\n\n totalCount\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n": "\n query CompatSessionList(\n $userId: ID!\n $state: SessionState\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n id\n compatSessions(\n first: $first\n after: $after\n last: $last\n before: $before\n state: $state\n ) {\n edges {\n node {\n id\n ...CompatSession_session\n }\n }\n\n totalCount\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n":
types.CompatSessionListDocument, types.CompatSessionListDocument,
"\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 client {\n id\n clientId\n clientName\n clientUri\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 OAuth2SessionListQuery(\n $userId: ID!\n $state: Oauth2SessionState\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n id\n oauth2Sessions(\n state: $state\n first: $first\n after: $after\n last: $last\n before: $before\n ) {\n edges {\n cursor\n node {\n id\n ...OAuth2Session_session\n }\n }\n\n totalCount\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n": "\n query OAuth2SessionListQuery(\n $userId: ID!\n $state: SessionState\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n id\n oauth2Sessions(\n state: $state\n first: $first\n after: $after\n last: $last\n before: $before\n ) {\n edges {\n cursor\n node {\n id\n ...OAuth2Session_session\n }\n }\n\n totalCount\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n":
types.OAuth2SessionListQueryDocument, types.OAuth2SessionListQueryDocument,
"\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 query SessionQuery($userId: ID!, $deviceId: String!) {\n session(userId: $userId, deviceId: $deviceId) {\n __typename\n ...CompatSession_session\n ...OAuth2Session_session\n }\n }\n":
types.SessionQueryDocument, types.SessionQueryDocument,
@ -119,8 +119,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 query BrowserSessionList(\n $userId: ID!\n $state: BrowserSessionState\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n id\n browserSessions(\n first: $first\n after: $after\n last: $last\n before: $before\n state: $state\n ) {\n totalCount\n\n edges {\n cursor\n node {\n id\n ...BrowserSession_session\n }\n }\n\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n", source: "\n query BrowserSessionList(\n $userId: ID!\n $state: SessionState\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n id\n browserSessions(\n first: $first\n after: $after\n last: $last\n before: $before\n state: $state\n ) {\n totalCount\n\n edges {\n cursor\n node {\n id\n ...BrowserSession_session\n }\n }\n\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n",
): (typeof documents)["\n query BrowserSessionList(\n $userId: ID!\n $state: BrowserSessionState\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n id\n browserSessions(\n first: $first\n after: $after\n last: $last\n before: $before\n state: $state\n ) {\n totalCount\n\n edges {\n cursor\n node {\n id\n ...BrowserSession_session\n }\n }\n\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n"]; ): (typeof documents)["\n query BrowserSessionList(\n $userId: ID!\n $state: SessionState\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n id\n browserSessions(\n first: $first\n after: $after\n last: $last\n before: $before\n state: $state\n ) {\n totalCount\n\n edges {\n cursor\n node {\n id\n ...BrowserSession_session\n }\n }\n\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n"];
/** /**
* 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.
*/ */
@ -143,8 +143,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 query CompatSessionList(\n $userId: ID!\n $state: CompatSessionState\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n id\n compatSessions(\n first: $first\n after: $after\n last: $last\n before: $before\n state: $state\n ) {\n edges {\n node {\n id\n ...CompatSession_session\n }\n }\n\n totalCount\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n", source: "\n query CompatSessionList(\n $userId: ID!\n $state: SessionState\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n id\n compatSessions(\n first: $first\n after: $after\n last: $last\n before: $before\n state: $state\n ) {\n edges {\n node {\n id\n ...CompatSession_session\n }\n }\n\n totalCount\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n",
): (typeof documents)["\n query CompatSessionList(\n $userId: ID!\n $state: CompatSessionState\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n id\n compatSessions(\n first: $first\n after: $after\n last: $last\n before: $before\n state: $state\n ) {\n edges {\n node {\n id\n ...CompatSession_session\n }\n }\n\n totalCount\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n"]; ): (typeof documents)["\n query CompatSessionList(\n $userId: ID!\n $state: SessionState\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n id\n compatSessions(\n first: $first\n after: $after\n last: $last\n before: $before\n state: $state\n ) {\n edges {\n node {\n id\n ...CompatSession_session\n }\n }\n\n totalCount\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\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.
*/ */
@ -161,8 +161,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 query OAuth2SessionListQuery(\n $userId: ID!\n $state: Oauth2SessionState\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n id\n oauth2Sessions(\n state: $state\n first: $first\n after: $after\n last: $last\n before: $before\n ) {\n edges {\n cursor\n node {\n id\n ...OAuth2Session_session\n }\n }\n\n totalCount\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n", source: "\n query OAuth2SessionListQuery(\n $userId: ID!\n $state: SessionState\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n id\n oauth2Sessions(\n state: $state\n first: $first\n after: $after\n last: $last\n before: $before\n ) {\n edges {\n cursor\n node {\n id\n ...OAuth2Session_session\n }\n }\n\n totalCount\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n",
): (typeof documents)["\n query OAuth2SessionListQuery(\n $userId: ID!\n $state: Oauth2SessionState\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n id\n oauth2Sessions(\n state: $state\n first: $first\n after: $after\n last: $last\n before: $before\n ) {\n edges {\n cursor\n node {\n id\n ...OAuth2Session_session\n }\n }\n\n totalCount\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n"]; ): (typeof documents)["\n query OAuth2SessionListQuery(\n $userId: ID!\n $state: SessionState\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n id\n oauth2Sessions(\n state: $state\n first: $first\n after: $after\n last: $last\n before: $before\n ) {\n edges {\n cursor\n node {\n id\n ...OAuth2Session_session\n }\n }\n\n totalCount\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\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.
*/ */

View File

@ -104,6 +104,30 @@ export type Anonymous = Node & {
id: Scalars["ID"]["output"]; id: Scalars["ID"]["output"];
}; };
/** A session in an application, either a compatibility or an OAuth 2.0 one */
export type AppSession = CompatSession | Oauth2Session;
export type AppSessionConnection = {
__typename?: "AppSessionConnection";
/** A list of edges. */
edges: Array<AppSessionEdge>;
/** A list of nodes. */
nodes: Array<AppSession>;
/** Information to aid in pagination. */
pageInfo: PageInfo;
/** Identifies the total count of items in the connection. */
totalCount: Scalars["Int"]["output"];
};
/** An edge in a connection. */
export type AppSessionEdge = {
__typename?: "AppSessionEdge";
/** A cursor for use in pagination */
cursor: Scalars["String"]["output"];
/** The item at the end of the edge */
node: AppSession;
};
/** /**
* An authentication records when a user enter their credential in a browser * An authentication records when a user enter their credential in a browser
* session. * session.
@ -134,7 +158,7 @@ export type BrowserSession = CreationEvent &
/** The most recent authentication of this session. */ /** The most recent authentication of this session. */
lastAuthentication?: Maybe<Authentication>; lastAuthentication?: Maybe<Authentication>;
/** The state of the session. */ /** The state of the session. */
state: BrowserSessionState; state: SessionState;
/** The user logged in this session. */ /** The user logged in this session. */
user: User; user: User;
/** The user-agent string with which the session was created. */ /** The user-agent string with which the session was created. */
@ -162,14 +186,6 @@ export type BrowserSessionEdge = {
node: BrowserSession; node: BrowserSession;
}; };
/** The state of a browser session. */
export enum BrowserSessionState {
/** The session is active. */
Active = "ACTIVE",
/** The session is no longer active. */
Finished = "FINISHED",
}
/** /**
* A compat session represents a client session which used the legacy Matrix * A compat session represents a client session which used the legacy Matrix
* login API. * login API.
@ -192,7 +208,7 @@ export type CompatSession = CreationEvent &
/** The associated SSO login, if any. */ /** The associated SSO login, if any. */
ssoLogin?: Maybe<CompatSsoLogin>; ssoLogin?: Maybe<CompatSsoLogin>;
/** The state of the session. */ /** The state of the session. */
state: CompatSessionState; state: SessionState;
/** The user authorized for this session. */ /** The user authorized for this session. */
user: User; user: User;
}; };
@ -218,14 +234,6 @@ export type CompatSessionEdge = {
node: CompatSession; node: CompatSession;
}; };
/** The state of a compatibility session. */
export enum CompatSessionState {
/** The session is active. */
Active = "ACTIVE",
/** The session is no longer active. */
Finished = "FINISHED",
}
/** The type of a compatibility session. */ /** The type of a compatibility session. */
export enum CompatSessionType { export enum CompatSessionType {
/** The session was created by a SSO login. */ /** The session was created by a SSO login. */
@ -559,7 +567,7 @@ export type Oauth2Session = CreationEvent &
/** Scope granted for this session. */ /** Scope granted for this session. */
scope: Scalars["String"]["output"]; scope: Scalars["String"]["output"];
/** The state of the session. */ /** The state of the session. */
state: Oauth2SessionState; state: SessionState;
/** User authorized for this session. */ /** User authorized for this session. */
user?: Maybe<User>; user?: Maybe<User>;
}; };
@ -585,14 +593,6 @@ export type Oauth2SessionEdge = {
node: Oauth2Session; node: Oauth2Session;
}; };
/** The state of an OAuth 2.0 session. */
export enum Oauth2SessionState {
/** The session is active. */
Active = "ACTIVE",
/** The session is no longer active. */
Finished = "FINISHED",
}
/** Information about pagination in a connection */ /** Information about pagination in a connection */
export type PageInfo = { export type PageInfo = {
__typename?: "PageInfo"; __typename?: "PageInfo";
@ -754,6 +754,14 @@ export enum SendVerificationEmailStatus {
/** A client session, either compat or OAuth 2.0 */ /** A client session, either compat or OAuth 2.0 */
export type Session = CompatSession | Oauth2Session; export type Session = CompatSession | Oauth2Session;
/** The state of a session */
export enum SessionState {
/** The session is active. */
Active = "ACTIVE",
/** The session is no longer active. */
Finished = "FINISHED",
}
/** The input for the `addEmail` mutation */ /** The input for the `addEmail` mutation */
export type SetDisplayNameInput = { export type SetDisplayNameInput = {
/** The display name to set. If `None`, the display name will be removed. */ /** The display name to set. If `None`, the display name will be removed. */
@ -876,6 +884,11 @@ export type UpstreamOAuth2ProviderEdge = {
/** A user is an individual's account. */ /** A user is an individual's account. */
export type User = Node & { export type User = Node & {
__typename?: "User"; __typename?: "User";
/**
* Get the list of both compat and OAuth 2.0 sessions, chronologically
* sorted
*/
appSessions: AppSessionConnection;
/** Get the list of active browser sessions, chronologically sorted */ /** Get the list of active browser sessions, chronologically sorted */
browserSessions: BrowserSessionConnection; browserSessions: BrowserSessionConnection;
/** Get the list of compatibility sessions, chronologically sorted */ /** Get the list of compatibility sessions, chronologically sorted */
@ -902,13 +915,22 @@ export type User = Node & {
username: Scalars["String"]["output"]; username: Scalars["String"]["output"];
}; };
/** A user is an individual's account. */
export type UserAppSessionsArgs = {
after?: InputMaybe<Scalars["String"]["input"]>;
before?: InputMaybe<Scalars["String"]["input"]>;
first?: InputMaybe<Scalars["Int"]["input"]>;
last?: InputMaybe<Scalars["Int"]["input"]>;
state?: InputMaybe<SessionState>;
};
/** A user is an individual's account. */ /** A user is an individual's account. */
export type UserBrowserSessionsArgs = { export type UserBrowserSessionsArgs = {
after?: InputMaybe<Scalars["String"]["input"]>; after?: InputMaybe<Scalars["String"]["input"]>;
before?: InputMaybe<Scalars["String"]["input"]>; before?: InputMaybe<Scalars["String"]["input"]>;
first?: InputMaybe<Scalars["Int"]["input"]>; first?: InputMaybe<Scalars["Int"]["input"]>;
last?: InputMaybe<Scalars["Int"]["input"]>; last?: InputMaybe<Scalars["Int"]["input"]>;
state?: InputMaybe<BrowserSessionState>; state?: InputMaybe<SessionState>;
}; };
/** A user is an individual's account. */ /** A user is an individual's account. */
@ -917,7 +939,7 @@ export type UserCompatSessionsArgs = {
before?: InputMaybe<Scalars["String"]["input"]>; before?: InputMaybe<Scalars["String"]["input"]>;
first?: InputMaybe<Scalars["Int"]["input"]>; first?: InputMaybe<Scalars["Int"]["input"]>;
last?: InputMaybe<Scalars["Int"]["input"]>; last?: InputMaybe<Scalars["Int"]["input"]>;
state?: InputMaybe<CompatSessionState>; state?: InputMaybe<SessionState>;
type?: InputMaybe<CompatSessionType>; type?: InputMaybe<CompatSessionType>;
}; };
@ -945,7 +967,7 @@ export type UserOauth2SessionsArgs = {
client?: InputMaybe<Scalars["ID"]["input"]>; client?: InputMaybe<Scalars["ID"]["input"]>;
first?: InputMaybe<Scalars["Int"]["input"]>; first?: InputMaybe<Scalars["Int"]["input"]>;
last?: InputMaybe<Scalars["Int"]["input"]>; last?: InputMaybe<Scalars["Int"]["input"]>;
state?: InputMaybe<Oauth2SessionState>; state?: InputMaybe<SessionState>;
}; };
/** A user is an individual's account. */ /** A user is an individual's account. */
@ -1092,7 +1114,7 @@ export type EndBrowserSessionMutation = {
export type BrowserSessionListQueryVariables = Exact<{ export type BrowserSessionListQueryVariables = Exact<{
userId: Scalars["ID"]["input"]; userId: Scalars["ID"]["input"];
state?: InputMaybe<BrowserSessionState>; state?: InputMaybe<SessionState>;
first?: InputMaybe<Scalars["Int"]["input"]>; first?: InputMaybe<Scalars["Int"]["input"]>;
after?: InputMaybe<Scalars["String"]["input"]>; after?: InputMaybe<Scalars["String"]["input"]>;
last?: InputMaybe<Scalars["Int"]["input"]>; last?: InputMaybe<Scalars["Int"]["input"]>;
@ -1171,7 +1193,7 @@ export type EndCompatSessionMutation = {
export type CompatSessionListQueryVariables = Exact<{ export type CompatSessionListQueryVariables = Exact<{
userId: Scalars["ID"]["input"]; userId: Scalars["ID"]["input"];
state?: InputMaybe<CompatSessionState>; state?: InputMaybe<SessionState>;
first?: InputMaybe<Scalars["Int"]["input"]>; first?: InputMaybe<Scalars["Int"]["input"]>;
after?: InputMaybe<Scalars["String"]["input"]>; after?: InputMaybe<Scalars["String"]["input"]>;
last?: InputMaybe<Scalars["Int"]["input"]>; last?: InputMaybe<Scalars["Int"]["input"]>;
@ -1242,7 +1264,7 @@ export type EndOAuth2SessionMutation = {
export type OAuth2SessionListQueryQueryVariables = Exact<{ export type OAuth2SessionListQueryQueryVariables = Exact<{
userId: Scalars["ID"]["input"]; userId: Scalars["ID"]["input"];
state?: InputMaybe<Oauth2SessionState>; state?: InputMaybe<SessionState>;
first?: InputMaybe<Scalars["Int"]["input"]>; first?: InputMaybe<Scalars["Int"]["input"]>;
after?: InputMaybe<Scalars["String"]["input"]>; after?: InputMaybe<Scalars["String"]["input"]>;
last?: InputMaybe<Scalars["Int"]["input"]>; last?: InputMaybe<Scalars["Int"]["input"]>;
@ -2228,7 +2250,7 @@ export const BrowserSessionListDocument = {
}, },
type: { type: {
kind: "NamedType", kind: "NamedType",
name: { kind: "Name", value: "BrowserSessionState" }, name: { kind: "Name", value: "SessionState" },
}, },
}, },
{ {
@ -2531,7 +2553,7 @@ export const CompatSessionListDocument = {
}, },
type: { type: {
kind: "NamedType", kind: "NamedType",
name: { kind: "Name", value: "CompatSessionState" }, name: { kind: "Name", value: "SessionState" },
}, },
}, },
{ {
@ -2861,7 +2883,7 @@ export const OAuth2SessionListQueryDocument = {
}, },
type: { type: {
kind: "NamedType", kind: "NamedType",
name: { kind: "Name", value: "Oauth2SessionState" }, name: { kind: "Name", value: "SessionState" },
}, },
}, },
{ {

View File

@ -109,6 +109,116 @@ export default {
}, },
], ],
}, },
{
kind: "UNION",
name: "AppSession",
possibleTypes: [
{
kind: "OBJECT",
name: "CompatSession",
},
{
kind: "OBJECT",
name: "Oauth2Session",
},
],
},
{
kind: "OBJECT",
name: "AppSessionConnection",
fields: [
{
name: "edges",
type: {
kind: "NON_NULL",
ofType: {
kind: "LIST",
ofType: {
kind: "NON_NULL",
ofType: {
kind: "OBJECT",
name: "AppSessionEdge",
ofType: null,
},
},
},
},
args: [],
},
{
name: "nodes",
type: {
kind: "NON_NULL",
ofType: {
kind: "LIST",
ofType: {
kind: "NON_NULL",
ofType: {
kind: "UNION",
name: "AppSession",
ofType: null,
},
},
},
},
args: [],
},
{
name: "pageInfo",
type: {
kind: "NON_NULL",
ofType: {
kind: "OBJECT",
name: "PageInfo",
ofType: null,
},
},
args: [],
},
{
name: "totalCount",
type: {
kind: "NON_NULL",
ofType: {
kind: "SCALAR",
name: "Any",
},
},
args: [],
},
],
interfaces: [],
},
{
kind: "OBJECT",
name: "AppSessionEdge",
fields: [
{
name: "cursor",
type: {
kind: "NON_NULL",
ofType: {
kind: "SCALAR",
name: "Any",
},
},
args: [],
},
{
name: "node",
type: {
kind: "NON_NULL",
ofType: {
kind: "UNION",
name: "AppSession",
ofType: null,
},
},
args: [],
},
],
interfaces: [],
},
{ {
kind: "OBJECT", kind: "OBJECT",
name: "Authentication", name: "Authentication",
@ -2410,6 +2520,54 @@ export default {
kind: "OBJECT", kind: "OBJECT",
name: "User", name: "User",
fields: [ fields: [
{
name: "appSessions",
type: {
kind: "NON_NULL",
ofType: {
kind: "OBJECT",
name: "AppSessionConnection",
ofType: null,
},
},
args: [
{
name: "after",
type: {
kind: "SCALAR",
name: "Any",
},
},
{
name: "before",
type: {
kind: "SCALAR",
name: "Any",
},
},
{
name: "first",
type: {
kind: "SCALAR",
name: "Any",
},
},
{
name: "last",
type: {
kind: "SCALAR",
name: "Any",
},
},
{
name: "state",
type: {
kind: "SCALAR",
name: "Any",
},
},
],
},
{ {
name: "browserSessions", name: "browserSessions",
type: { type: {