Skip to content

Commit 3338f32

Browse files
authored
fix: improve provisioner details layout and show count line (#14749)
* きれい * とても大きい * improve storybook test * ボタン * アイコンの名前 * ジェ
1 parent 3501782 commit 3338f32

File tree

3 files changed

+118
-44
lines changed

3 files changed

+118
-44
lines changed

site/src/modules/provisioners/ProvisionerGroup.tsx

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { type Interpolation, type Theme, useTheme } from "@emotion/react";
2-
import Business from "@mui/icons-material/Business";
3-
import Person from "@mui/icons-material/Person";
2+
import BusinessIcon from "@mui/icons-material/Business";
3+
import PersonIcon from "@mui/icons-material/Person";
4+
import TagIcon from "@mui/icons-material/Sell";
45
import Button from "@mui/material/Button";
56
import Link from "@mui/material/Link";
67
import Tooltip from "@mui/material/Tooltip";
@@ -21,6 +22,7 @@ import {
2122
} from "components/Popover/Popover";
2223
import { Stack } from "components/Stack/Stack";
2324
import { StatusIndicator } from "components/StatusIndicator/StatusIndicator";
25+
import isEqual from "lodash/isEqual";
2426
import { type FC, useState } from "react";
2527
import { createDayString } from "utils/createDayString";
2628
import { docs } from "utils/docs";
@@ -30,14 +32,16 @@ type ProvisionerGroupType = "builtin" | "psk" | "key";
3032

3133
interface ProvisionerGroupProps {
3234
readonly buildInfo?: BuildInfoResponse;
33-
readonly keyName?: string;
35+
readonly keyName: string;
36+
readonly keyTags: Record<string, string>;
3437
readonly type: ProvisionerGroupType;
3538
readonly provisioners: readonly ProvisionerDaemon[];
3639
}
3740

3841
export const ProvisionerGroup: FC<ProvisionerGroupProps> = ({
3942
buildInfo,
4043
keyName,
44+
keyTags,
4145
type,
4246
provisioners,
4347
}) => {
@@ -61,7 +65,7 @@ export const ProvisionerGroup: FC<ProvisionerGroupProps> = ({
6165
provisioners.length === 1
6266
? "1 provisioner"
6367
: `${provisioners.length} provisioners`;
64-
const extraTags = Object.entries(firstProvisioner.tags).filter(
68+
const extraTags = Object.entries(keyTags).filter(
6569
([key]) => key !== "scope" && key !== "owner",
6670
);
6771

@@ -90,6 +94,10 @@ export const ProvisionerGroup: FC<ProvisionerGroupProps> = ({
9094
? "1 provisioner"
9195
: `${provisionersWithWarnings} provisioners`;
9296

97+
const hasMultipleTagVariants =
98+
type === "psk" &&
99+
provisioners.some((it) => !isEqual(it.tags, { scope: "organization" }));
100+
93101
return (
94102
<div
95103
css={[
@@ -153,14 +161,26 @@ export const ProvisionerGroup: FC<ProvisionerGroupProps> = ({
153161
justifyContent: "right",
154162
}}
155163
>
156-
<Tooltip title="Scope">
157-
<Pill
158-
size="lg"
159-
icon={daemonScope === "organization" ? <Business /> : <Person />}
160-
>
161-
<span css={{ textTransform: "capitalize" }}>{daemonScope}</span>
164+
{!hasMultipleTagVariants ? (
165+
<Tooltip title="Scope">
166+
<Pill
167+
size="lg"
168+
icon={
169+
daemonScope === "organization" ? (
170+
<BusinessIcon />
171+
) : (
172+
<PersonIcon />
173+
)
174+
}
175+
>
176+
<span css={{ textTransform: "capitalize" }}>{daemonScope}</span>
177+
</Pill>
178+
</Tooltip>
179+
) : (
180+
<Pill size="lg" icon={<TagIcon />}>
181+
Multiple tags
162182
</Pill>
163-
</Tooltip>
183+
)}
164184
{type === "key" &&
165185
extraTags.map(([key, value]) => (
166186
<ProvisionerTag key={key} tagName={key} tagValue={value} />
@@ -172,9 +192,9 @@ export const ProvisionerGroup: FC<ProvisionerGroupProps> = ({
172192
<div
173193
css={{
174194
padding: "0 24px 24px",
175-
display: "flex",
195+
display: "grid",
176196
gap: 12,
177-
flexWrap: "wrap",
197+
gridTemplateColumns: "repeat(auto-fill, minmax(385px, 1fr))",
178198
}}
179199
>
180200
{provisionersWithWarningInfo.map((provisioner) => (
@@ -186,7 +206,6 @@ export const ProvisionerGroup: FC<ProvisionerGroupProps> = ({
186206
border: `1px solid ${theme.palette.divider}`,
187207
fontSize: 14,
188208
padding: "14px 18px",
189-
width: 375,
190209
},
191210
provisioner.warningCount > 0 && styles.warningBorder,
192211
]}
@@ -222,7 +241,7 @@ export const ProvisionerGroup: FC<ProvisionerGroupProps> = ({
222241
)}
223242
</span>
224243
</div>
225-
{type === "psk" && (
244+
{hasMultipleTagVariants && (
226245
<PskProvisionerTags tags={provisioner.tags} />
227246
)}
228247
</Stack>
@@ -317,7 +336,8 @@ interface PskProvisionerTagsProps {
317336

318337
const PskProvisionerTags: FC<PskProvisionerTagsProps> = ({ tags }) => {
319338
const daemonScope = tags.scope || "organization";
320-
const iconScope = daemonScope === "organization" ? <Business /> : <Person />;
339+
const iconScope =
340+
daemonScope === "organization" ? <BusinessIcon /> : <PersonIcon />;
321341

322342
const extraTags = Object.entries(tags).filter(
323343
([tag]) => tag !== "scope" && tag !== "owner",
@@ -343,6 +363,7 @@ const PskProvisionerTags: FC<PskProvisionerTagsProps> = ({ tags }) => {
343363
css={{
344364
"& .MuiPaper-root": {
345365
padding: 20,
366+
minWidth: "unset",
346367
maxWidth: 340,
347368
width: "fit-content",
348369
},

site/src/pages/ManagementSettingsPage/OrganizationProvisionersPageView.stories.tsx

Lines changed: 46 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { Meta, StoryObj } from "@storybook/react";
2+
import { screen, userEvent } from "@storybook/test";
23
import {
34
MockBuildInfo,
45
MockProvisioner,
@@ -38,7 +39,11 @@ export const Provisioners: Story = {
3839
],
3940
},
4041
{
41-
key: { ...MockProvisionerKey, id: "ジャイデン", name: "ジャイデン" },
42+
key: MockProvisionerPskKey,
43+
daemons: [MockProvisioner, MockProvisioner2],
44+
},
45+
{
46+
key: { ...MockProvisionerKey, id: "ジェイデン", name: "ジェイデン" },
4247
daemons: [MockProvisioner, MockProvisioner2],
4348
},
4449
{
@@ -53,21 +58,50 @@ export const Provisioners: Story = {
5358
],
5459
},
5560
{
56-
key: { ...MockProvisionerKey, id: "ケイラ", name: "ケイラ" },
57-
daemons: [
58-
{
59-
...MockProvisioner,
60-
tags: {
61-
...MockProvisioner.tags,
62-
都市: "ユタ",
63-
きっぷ: "yes",
64-
ちいさい: "no",
65-
},
61+
key: {
62+
...MockProvisionerKey,
63+
id: "ケイラ",
64+
name: "ケイラ",
65+
tags: {
66+
...MockProvisioner.tags,
67+
都市: "ユタ",
68+
きっぷ: "yes",
69+
ちいさい: "no",
6670
},
67-
],
71+
},
72+
daemons: Array.from({ length: 117 }, (_, i) => ({
73+
...MockProvisioner,
74+
id: `ケイラ-${i}`,
75+
name: `ケイラ-${i}`,
76+
})),
6877
},
6978
],
7079
},
80+
play: async ({ step }) => {
81+
await step("open all details", async () => {
82+
const expandButtons = await screen.findAllByRole("button", {
83+
name: "Show provisioner details",
84+
});
85+
for (const it of expandButtons) {
86+
await userEvent.click(it);
87+
}
88+
});
89+
90+
await step("close uninteresting/large details", async () => {
91+
const collapseButtons = await screen.findAllByRole("button", {
92+
name: "Hide provisioner details",
93+
});
94+
95+
await userEvent.click(collapseButtons[2]);
96+
await userEvent.click(collapseButtons[3]);
97+
await userEvent.click(collapseButtons[5]);
98+
});
99+
100+
await step("show version popover", async () => {
101+
const outOfDate = await screen.findByText("Out of date");
102+
await userEvent.hover(outOfDate);
103+
});
104+
},
71105
};
72106

73107
export const Empty: Story = {

site/src/pages/ManagementSettingsPage/OrganizationProvisionersPageView.tsx

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,17 @@ export const OrganizationProvisionersPageView: FC<
2525
> = ({ buildInfo, provisioners }) => {
2626
const isEmpty = provisioners.every((group) => group.daemons.length === 0);
2727

28+
const provisionerGroupsCount = provisioners.length;
29+
const provisionersCount = provisioners.reduce(
30+
(a, group) => a + group.daemons.length,
31+
0,
32+
);
33+
2834
return (
2935
<div>
3036
<PageHeader
3137
// The deployment settings layout already has padding.
32-
css={{ paddingTop: 0 }}
38+
css={{ paddingTop: 0, paddingBottom: 12 }}
3339
actions={
3440
<Button
3541
endIcon={<OpenInNewIcon />}
@@ -42,22 +48,34 @@ export const OrganizationProvisionersPageView: FC<
4248
>
4349
<PageHeaderTitle>Provisioners</PageHeaderTitle>
4450
</PageHeader>
51+
{isEmpty ? (
52+
<EmptyState
53+
message="No provisioners"
54+
description="A provisioner is required before you can create templates and workspaces. You can connect your first provisioner by following our documentation."
55+
cta={
56+
<Button
57+
endIcon={<OpenInNewIcon />}
58+
target="_blank"
59+
href={docs("/admin/provisioners")}
60+
>
61+
Show me how to create a provisioner
62+
</Button>
63+
}
64+
/>
65+
) : (
66+
<div
67+
css={(theme) => ({
68+
margin: 0,
69+
fontSize: 12,
70+
paddingBottom: 18,
71+
color: theme.palette.text.secondary,
72+
})}
73+
>
74+
Showing {provisionerGroupsCount} groups and {provisionersCount}{" "}
75+
provisioners
76+
</div>
77+
)}
4578
<Stack spacing={4.5}>
46-
{isEmpty && (
47-
<EmptyState
48-
message="No provisioners"
49-
description="A provisioner is required before you can create templates and workspaces. You can connect your first provisioner by following our documentation."
50-
cta={
51-
<Button
52-
endIcon={<OpenInNewIcon />}
53-
target="_blank"
54-
href={docs("/admin/provisioners")}
55-
>
56-
Show me how to create a provisioner
57-
</Button>
58-
}
59-
/>
60-
)}
6179
{provisioners.map((group) => {
6280
const type = getGroupType(group.key);
6381

@@ -74,6 +92,7 @@ export const OrganizationProvisionersPageView: FC<
7492
key={group.key.id}
7593
buildInfo={buildInfo}
7694
keyName={group.key.name}
95+
keyTags={group.key.tags}
7796
type={type}
7897
provisioners={group.daemons}
7998
/>

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy