Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit50ad2f8

Browse files
refactor: Improve the load state for the list pages (#1428)
1 parentf970829 commit50ad2f8

File tree

15 files changed

+413
-270
lines changed

15 files changed

+413
-270
lines changed

‎site/src/components/EmptyState/EmptyState.test.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,12 @@ describe("EmptyState", () => {
2121
awaitscreen.findByText("Friendly greeting")
2222
})
2323

24-
it("rendersdescription component",async()=>{
24+
it("renderscta component",async()=>{
2525
// Given
26-
constdescription=<buttontitle="Click me"/>
26+
constcta=<buttontitle="Click me"/>
2727

2828
// When
29-
render(<EmptyStatemessage="Hello, world"description={description}/>)
29+
render(<EmptyStatemessage="Hello, world"cta={cta}/>)
3030

3131
// Then
3232
awaitscreen.findByText("Hello, world")

‎site/src/components/EmptyState/EmptyState.tsx

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
importBoxfrom"@material-ui/core/Box"
2-
importButton,{ButtonProps}from"@material-ui/core/Button"
32
import{makeStyles}from"@material-ui/core/styles"
43
importTypographyfrom"@material-ui/core/Typography"
54
importReactfrom"react"
@@ -8,8 +7,8 @@ export interface EmptyStateProps {
87
/** Text Message to display, placed inside Typography component */
98
message:string
109
/** Longer optional description to display below the message */
11-
description?:React.ReactNode
12-
button?:ButtonProps
10+
description?:string
11+
cta?:React.ReactNode
1312
}
1413

1514
/**
@@ -21,17 +20,22 @@ export interface EmptyStateProps {
2120
* that you can directly pass props through to to customize the shape and layout of it.
2221
*/
2322
exportconstEmptyState:React.FC<EmptyStateProps>=(props)=>{
24-
const{ message, description,button, ...boxProps}=props
23+
const{ message, description,cta, ...boxProps}=props
2524
conststyles=useStyles()
26-
constbuttonClassName=`${styles.button}${button&&button.className ?button.className :""}`
2725

2826
return(
2927
<BoxclassName={styles.root}{...boxProps}>
30-
<Typographyvariant="h5"color="textSecondary"className={styles.header}>
31-
{message}
32-
</Typography>
33-
{description&&<divclassName={styles.description}>{description}</div>}
34-
{button&&<Buttonvariant="contained"color="primary"{...button}className={buttonClassName}/>}
28+
<divclassName={styles.header}>
29+
<Typographyvariant="h5"className={styles.title}>
30+
{message}
31+
</Typography>
32+
{description&&(
33+
<Typographyvariant="body2"color="textSecondary"className={styles.description}>
34+
{description}
35+
</Typography>
36+
)}
37+
</div>
38+
{cta}
3539
</Box>
3640
)
3741
}
@@ -48,22 +52,13 @@ const useStyles = makeStyles(
4852
padding:theme.spacing(3),
4953
},
5054
header:{
55+
marginBottom:theme.spacing(3),
56+
},
57+
title:{
5158
fontWeight:400,
5259
},
5360
description:{
54-
marginTop:theme.spacing(2),
55-
marginBottom:theme.spacing(1),
56-
color:theme.palette.text.secondary,
57-
fontSize:theme.typography.body2.fontSize,
58-
},
59-
button:{
60-
marginTop:theme.spacing(2),
61-
},
62-
icon:{
63-
fontSize:theme.typography.h2.fontSize,
64-
color:theme.palette.text.secondary,
65-
marginBottom:theme.spacing(1),
66-
opacity:0.5,
61+
marginTop:theme.spacing(1),
6762
},
6863
}),
6964
{name:"EmptyState"},

‎site/src/components/Loader/FullScreenLoader.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import CircularProgress from "@material-ui/core/CircularProgress"
22
import{makeStyles}from"@material-ui/core/styles"
33
importReactfrom"react"
44

5-
exportconstuseStyles=makeStyles(()=>({
5+
exportconstuseStyles=makeStyles((theme)=>({
66
root:{
77
position:"absolute",
88
top:"0",
@@ -12,6 +12,7 @@ export const useStyles = makeStyles(() => ({
1212
display:"flex",
1313
justifyContent:"center",
1414
alignItems:"center",
15+
background:theme.palette.background.default,
1516
},
1617
}))
1718

‎site/src/components/NavbarView/NavbarView.stories.tsx

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import{Story}from"@storybook/react"
22
importReactfrom"react"
3+
import{MockUser,MockUser2}from"../../testHelpers/entities"
34
import{NavbarView,NavbarViewProps}from"./NavbarView"
45

56
exportdefault{
@@ -14,33 +15,15 @@ const Template: Story<NavbarViewProps> = (args: NavbarViewProps) => <NavbarView
1415

1516
exportconstForAdmin=Template.bind({})
1617
ForAdmin.args={
17-
user:{
18-
id:"1",
19-
username:"Administrator",
20-
email:"admin@coder.com",
21-
created_at:"dawn",
22-
status:"active",
23-
organization_ids:[],
24-
roles:[],
25-
},
26-
displayAdminDropdown:true,
18+
user:MockUser,
2719
onSignOut:()=>{
2820
returnPromise.resolve()
2921
},
3022
}
3123

3224
exportconstForMember=Template.bind({})
3325
ForMember.args={
34-
user:{
35-
id:"1",
36-
username:"CathyCoder",
37-
email:"cathy@coder.com",
38-
created_at:"dawn",
39-
status:"active",
40-
organization_ids:[],
41-
roles:[],
42-
},
43-
displayAdminDropdown:false,
26+
user:MockUser2,
4427
onSignOut:()=>{
4528
returnPromise.resolve()
4629
},
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
importBoxfrom"@material-ui/core/Box"
2+
importCircularProgressfrom"@material-ui/core/CircularProgress"
3+
import{makeStyles}from"@material-ui/core/styles"
4+
importTableCellfrom"@material-ui/core/TableCell"
5+
importTableRowfrom"@material-ui/core/TableRow"
6+
importReactfrom"react"
7+
8+
exportconstTableLoader:React.FC=()=>{
9+
conststyles=useStyles()
10+
11+
return(
12+
<TableRow>
13+
<TableCellcolSpan={999}className={styles.cell}>
14+
<Boxp={4}>
15+
<CircularProgresssize={26}/>
16+
</Box>
17+
</TableCell>
18+
</TableRow>
19+
)
20+
}
21+
22+
constuseStyles=makeStyles((theme)=>({
23+
cell:{
24+
textAlign:"center",
25+
height:theme.spacing(20),
26+
},
27+
}))
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import{ComponentMeta,Story}from"@storybook/react"
2+
importReactfrom"react"
3+
import{MockOrganization,MockTemplate}from"../../testHelpers/entities"
4+
import{TemplatesTable,TemplatesTableProps}from"./TemplatesTable"
5+
6+
exportdefault{
7+
title:"components/TemplatesTable",
8+
component:TemplatesTable,
9+
}asComponentMeta<typeofTemplatesTable>
10+
11+
constTemplate:Story<TemplatesTableProps>=(args)=><TemplatesTable{...args}/>
12+
13+
exportconstExample=Template.bind({})
14+
Example.args={
15+
templates:[MockTemplate],
16+
organizations:[MockOrganization],
17+
}
18+
19+
exportconstEmpty=Template.bind({})
20+
Empty.args={
21+
templates:[],
22+
organizations:[],
23+
}
24+
25+
exportconstLoading=Template.bind({})
26+
Loading.args={
27+
templates:undefined,
28+
organizations:[],
29+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
importBoxfrom"@material-ui/core/Box"
2+
importTablefrom"@material-ui/core/Table"
3+
importTableBodyfrom"@material-ui/core/TableBody"
4+
importTableCellfrom"@material-ui/core/TableCell"
5+
importTableHeadfrom"@material-ui/core/TableHead"
6+
importTableRowfrom"@material-ui/core/TableRow"
7+
importReactfrom"react"
8+
import{Link}from"react-router-dom"
9+
import*asTypesGenfrom"../../api/typesGenerated"
10+
import{CodeExample}from"../../components/CodeExample/CodeExample"
11+
import{EmptyState}from"../../components/EmptyState/EmptyState"
12+
import{TableHeaderRow}from"../../components/TableHeaders/TableHeaders"
13+
import{TableLoader}from"../../components/TableLoader/TableLoader"
14+
import{TableTitle}from"../../components/TableTitle/TableTitle"
15+
16+
exportconstLanguage={
17+
title:"Templates",
18+
tableTitle:"All templates",
19+
nameLabel:"Name",
20+
emptyMessage:"No templates have been created yet",
21+
emptyDescription:"Run the following command to get started:",
22+
totalLabel:"total",
23+
}
24+
25+
exportinterfaceTemplatesTableProps{
26+
templates?:TypesGen.Template[]
27+
organizations?:TypesGen.Organization[]
28+
}
29+
30+
exportconstTemplatesTable:React.FC<TemplatesTableProps>=({ templates, organizations})=>{
31+
constisLoading=!templates||!organizations
32+
33+
// Create a dictionary of organization ID -> organization Name
34+
// Needed to properly construct links to dive into a template
35+
constorgDictionary=
36+
organizations&&
37+
organizations.reduce((acc:Record<string,string>,curr:TypesGen.Organization)=>{
38+
return{
39+
...acc,
40+
[curr.id]:curr.name,
41+
}
42+
},{})
43+
44+
return(
45+
<Table>
46+
<TableHead>
47+
<TableTitletitle={Language.tableTitle}/>
48+
<TableHeaderRow>
49+
<TableCellsize="small">{Language.nameLabel}</TableCell>
50+
</TableHeaderRow>
51+
</TableHead>
52+
<TableBody>
53+
{isLoading&&<TableLoader/>}
54+
{templates&&
55+
organizations&&
56+
orgDictionary&&
57+
templates.map((t)=>(
58+
<TableRowkey={t.id}>
59+
<TableCell>
60+
<Linkto={`/templates/${orgDictionary[t.organization_id]}/${t.name}`}>{t.name}</Link>
61+
</TableCell>
62+
</TableRow>
63+
))}
64+
65+
{templates&&templates.length===0&&(
66+
<TableRow>
67+
<TableCellcolSpan={999}>
68+
<Boxp={4}>
69+
<EmptyState
70+
message={Language.emptyMessage}
71+
description={Language.emptyDescription}
72+
cta={<CodeExamplecode="coder templates create"/>}
73+
/>
74+
</Box>
75+
</TableCell>
76+
</TableRow>
77+
)}
78+
</TableBody>
79+
</Table>
80+
)
81+
}

‎site/src/components/UsersTable/UsersTable.tsx

Lines changed: 40 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import * as TypesGen from "../../api/typesGenerated"
99
import{EmptyState}from"../EmptyState/EmptyState"
1010
import{RoleSelect}from"../RoleSelect/RoleSelect"
1111
import{TableHeaderRow}from"../TableHeaders/TableHeaders"
12+
import{TableLoader}from"../TableLoader/TableLoader"
1213
import{TableRowMenu}from"../TableRowMenu/TableRowMenu"
1314
import{TableTitle}from"../TableTitle/TableTitle"
1415
import{UserCell}from"../UserCell/UserCell"
@@ -24,12 +25,12 @@ export const Language = {
2425
}
2526

2627
exportinterfaceUsersTableProps{
27-
users:TypesGen.User[]
28+
users?:TypesGen.User[]
29+
roles?:TypesGen.Role[]
30+
isUpdatingUserRoles?:boolean
2831
onSuspendUser:(user:TypesGen.User)=>void
2932
onResetUserPassword:(user:TypesGen.User)=>void
3033
onUpdateUserRoles:(user:TypesGen.User,roles:TypesGen.Role["name"][])=>void
31-
roles:TypesGen.Role[]
32-
isUpdatingUserRoles?:boolean
3334
}
3435

3536
exportconstUsersTable:React.FC<UsersTableProps>=({
@@ -40,6 +41,8 @@ export const UsersTable: React.FC<UsersTableProps> = ({
4041
onUpdateUserRoles,
4142
isUpdatingUserRoles,
4243
})=>{
44+
constisLoading=!users||!roles
45+
4346
return(
4447
<Table>
4548
<TableHead>
@@ -52,38 +55,41 @@ export const UsersTable: React.FC<UsersTableProps> = ({
5255
</TableHeaderRow>
5356
</TableHead>
5457
<TableBody>
55-
{users.map((u)=>(
56-
<TableRowkey={u.id}>
57-
<TableCell>
58-
<UserCellAvatar={{username:u.username}}primaryText={u.username}caption={u.email}/>{" "}
59-
</TableCell>
60-
<TableCell>
61-
<RoleSelect
62-
roles={roles}
63-
selectedRoles={u.roles}
64-
loading={isUpdatingUserRoles}
65-
onChange={(roles)=>onUpdateUserRoles(u,roles)}
66-
/>
67-
</TableCell>
68-
<TableCell>
69-
<TableRowMenu
70-
data={u}
71-
menuItems={[
72-
{
73-
label:Language.suspendMenuItem,
74-
onClick:onSuspendUser,
75-
},
76-
{
77-
label:Language.resetPasswordMenuItem,
78-
onClick:onResetUserPassword,
79-
},
80-
]}
81-
/>
82-
</TableCell>
83-
</TableRow>
84-
))}
58+
{isLoading&&<TableLoader/>}
59+
{users&&
60+
roles&&
61+
users.map((u)=>(
62+
<TableRowkey={u.id}>
63+
<TableCell>
64+
<UserCellAvatar={{username:u.username}}primaryText={u.username}caption={u.email}/>{" "}
65+
</TableCell>
66+
<TableCell>
67+
<RoleSelect
68+
roles={roles}
69+
selectedRoles={u.roles}
70+
loading={isUpdatingUserRoles}
71+
onChange={(roles)=>onUpdateUserRoles(u,roles)}
72+
/>
73+
</TableCell>
74+
<TableCell>
75+
<TableRowMenu
76+
data={u}
77+
menuItems={[
78+
{
79+
label:Language.suspendMenuItem,
80+
onClick:onSuspendUser,
81+
},
82+
{
83+
label:Language.resetPasswordMenuItem,
84+
onClick:onResetUserPassword,
85+
},
86+
]}
87+
/>
88+
</TableCell>
89+
</TableRow>
90+
))}
8591

86-
{users.length===0&&(
92+
{users&&users.length===0&&(
8793
<TableRow>
8894
<TableCellcolSpan={999}>
8995
<Boxp={4}>

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp