Skip to content
This repository has been archived by the owner on Sep 10, 2024. It is now read-only.

Commit

Permalink
Generic session list header component (#1832)
Browse files Browse the repository at this point in the history
* add session list header component

* remove unused

* copyright year
  • Loading branch information
Kerry authored Sep 26, 2023
1 parent dc7dacc commit a62aa87
Show file tree
Hide file tree
Showing 6 changed files with 218 additions and 2 deletions.
4 changes: 2 additions & 2 deletions frontend/src/components/BrowserSessionList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import { isOk, unwrap, unwrapOk } from "../result";
import BlockList from "./BlockList";
import BrowserSession from "./BrowserSession";
import PaginationControls from "./PaginationControls";
import { Title } from "./Typography";
import SessionListHeader from "./SessionList/SessionListHeader";

const QUERY = graphql(/* GraphQL */ `
query BrowserSessionList(
Expand Down Expand Up @@ -135,7 +135,7 @@ const BrowserSessionList: React.FC<{ userId: string }> = ({ userId }) => {

return (
<BlockList>
<Title>Browser:</Title>
<SessionListHeader title="Browsers" />
<PaginationControls
onPrev={prevPage ? (): void => paginate(prevPage) : null}
onNext={nextPage ? (): void => paginate(nextPage) : null}
Expand Down
26 changes: 26 additions & 0 deletions frontend/src/components/SessionList/SessionListHeader.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/* 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-header {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
gap: var(--cpd-space-1x);
}

.title {
flex: 1 1;
}
78 changes: 78 additions & 0 deletions frontend/src/components/SessionList/SessionListHeader.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// 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 type { Meta, StoryObj } from "@storybook/react";
import { Button } from "@vector-im/compound-web";
import { PropsWithChildren, ReactElement } from "react";

import SessionListHeader from "./SessionListHeader";

type Props = PropsWithChildren<{
title: string;
}>;

const NOOP = (): void => {};

const Template: React.FC<Props> = ({ title, children }) => {
return <SessionListHeader title={title}>{children}</SessionListHeader>;
};

const meta = {
title: "UI/Session/List header",
component: Template,
tags: ["autodocs"],
decorators: [
(Story): ReactElement => (
<div style={{ width: "378px" }}>
<Story />
</div>
),
],
} satisfies Meta<typeof Template>;

export default meta;
type Story = StoryObj<typeof Template>;

export const Basic: Story = {
args: {
title: "Apps",
},
};

export const WithOneAction: Story = {
args: {
title: "Apps",
children: (
<Button size="sm" kind="destructive" onClick={NOOP}>
End sessions
</Button>
),
},
};

export const WithMultipleActions: Story = {
args: {
title: "Apps",
children: (
<>
<Button size="sm" kind="secondary" onClick={NOOP}>
Deselect all
</Button>
<Button size="sm" kind="destructive" onClick={NOOP}>
End sessions
</Button>
</>
),
},
};
36 changes: 36 additions & 0 deletions frontend/src/components/SessionList/SessionListHeader.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// 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 { composeStory } from "@storybook/react";
import { render, cleanup } from "@testing-library/react";
import { describe, it, expect, afterEach } from "vitest";

import Meta, { Basic, WithOneAction } from "./SessionListHeader.stories";

describe("<SessionListHeader />", () => {
afterEach(cleanup);
it("renders a basic header", () => {
const Component = composeStory(Basic, Meta);
const { container } = render(<Component />);
expect(container).toMatchSnapshot();
});

it("renders a header with actions", () => {
const Component = composeStory(WithOneAction, Meta);
const { container } = render(<Component />);
expect(container).toMatchSnapshot();
});
});
30 changes: 30 additions & 0 deletions frontend/src/components/SessionList/SessionListHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// 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 { H5 } from "@vector-im/compound-web";
import { PropsWithChildren } from "react";

import styles from "./SessionListHeader.module.css";

type Props = PropsWithChildren<{
title: string;
}>;
const SessionListHeader: React.FC<Props> = ({ title, children }) => (
<header className={styles.sessionListHeader}>
<H5 className={styles.title}>{title}</H5>
{children}
</header>
);

export default SessionListHeader;
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`<SessionListHeader /> > renders a basic header 1`] = `
<div>
<div
style="width: 378px;"
>
<header
class="_sessionListHeader_5d8138"
>
<h5
class="_font-body-lg-semibold_1jx6b_83 _title_5d8138"
>
Apps
</h5>
</header>
</div>
</div>
`;

exports[`<SessionListHeader /> > renders a header with actions 1`] = `
<div>
<div
style="width: 378px;"
>
<header
class="_sessionListHeader_5d8138"
>
<h5
class="_font-body-lg-semibold_1jx6b_83 _title_5d8138"
>
Apps
</h5>
<button
class="_button_1ukgx_17"
data-kind="destructive"
data-size="sm"
role="button"
tabindex="0"
>
End sessions
</button>
</header>
</div>
</div>
`;

0 comments on commit a62aa87

Please sign in to comment.