1
0
mirror of https://github.com/matrix-org/matrix-authentication-service.git synced 2025-11-20 12:02:22 +03:00

split browser sessions section into own component

This commit is contained in:
Kerry Archibald
2023-09-21 12:21:30 +12:00
committed by Quentin Gliech
parent 58b235e9de
commit e646319f5a
4 changed files with 223 additions and 0 deletions

View File

@@ -0,0 +1,27 @@
/* Copyright 2023 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
.session-list-block {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: flex-start;
gap: var(--cpd-space-1x);
}
.session-list-block-info {
display: flex;
flex-direction: column;
}

View File

@@ -0,0 +1,74 @@
// Copyright 2022 The Matrix.org Foundation C.I.C.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import type { Meta, StoryObj } from "@storybook/react";
import { Provider } from "jotai";
import { useHydrateAtoms } from "jotai/utils";
import { makeFragmentData } from "../../gql";
import { appConfigAtom, locationAtom } from "../../routing";
import BrowserSessionsOverview, { FRAGMENT } from "./BrowserSessionsOverview";
type Props = {
browserSessions: number;
};
const WithHomePage: React.FC<React.PropsWithChildren<{}>> = ({ children }) => {
useHydrateAtoms([
[appConfigAtom, { root: "/" }],
[locationAtom, { pathname: "/" }],
]);
return <>{children}</>;
};
const Template: React.FC<Props> = ({ browserSessions }) => {
const data = makeFragmentData(
{
id: "user:123",
browserSessions: {
totalCount: browserSessions,
},
},
FRAGMENT,
);
return (
<Provider>
<WithHomePage>
<BrowserSessionsOverview user={data} />
</WithHomePage>
</Provider>
);
};
const meta = {
title: "Pages/User Sessions Overview/Browser Sessions",
component: Template,
tags: ["autodocs"],
} satisfies Meta<typeof Template>;
export default meta;
type Story = StoryObj<typeof Template>;
export const Basic: Story = {
args: {
browserSessions: 2,
},
};
export const Empty: Story = {
args: {
browserSessions: 0,
},
};

View File

@@ -0,0 +1,64 @@
// Copyright 2023 The Matrix.org Foundation C.I.C.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// @vitest-environment happy-dom
import { render, cleanup } from "@testing-library/react";
import { describe, expect, it, afterEach } from "vitest";
import { makeFragmentData } from "../../gql";
import { WithLocation } from "../../test-utils/WithLocation";
import BrowserSessionsOverview, { FRAGMENT } from "./BrowserSessionsOverview";
describe("BrowserSessionsOverview", () => {
afterEach(cleanup);
it("renders with no browser sessions", async () => {
const user = makeFragmentData(
{
id: "user:123",
browserSessions: {
totalCount: 0,
},
},
FRAGMENT,
);
const { container } = render(
<WithLocation>
<BrowserSessionsOverview user={user} />
</WithLocation>,
);
expect(container).toMatchSnapshot();
});
it("renders with sessions", () => {
const user = makeFragmentData(
{
id: "user:123",
browserSessions: {
totalCount: 2,
},
},
FRAGMENT,
);
const { container } = render(
<WithLocation>
<BrowserSessionsOverview user={user} />
</WithLocation>,
);
expect(container).toMatchSnapshot();
});
});

View File

@@ -0,0 +1,58 @@
// Copyright 2023 The Matrix.org Foundation C.I.C.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { Body, H5 } from "@vector-im/compound-web";
import { FragmentType, graphql, useFragment } from "../../gql";
import { Link } from "../../routing";
import Block from "../Block";
import styles from "./BrowserSessionsOverview.module.css";
export const FRAGMENT = graphql(/* GraphQL */ `
fragment BrowserSessionsOverview_user on User {
id
browserSessions(first: 0, state: ACTIVE) {
totalCount
}
}
`);
const BrowserSessionsOverview: React.FC<{
user: FragmentType<typeof FRAGMENT>;
}> = ({ user }) => {
const data = useFragment(FRAGMENT, user);
// allow this until we get i18n
const pluraliseSession = (count: number): string =>
count === 1 ? "session" : "sessions";
return (
<Block className={styles.sessionListBlock}>
<div className={styles.sessionListBlockInfo}>
<H5>Browsers</H5>
<Body>
{data.browserSessions.totalCount} active{" "}
{pluraliseSession(data.browserSessions.totalCount)}
</Body>
</div>
<Link kind="button" route={{ type: "browser-session-list" }}>
View all
</Link>
</Block>
);
};
export default BrowserSessionsOverview;