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

Commita19539c

Browse files
refactor: improve app status and statuses (#18121)
#### 1. Gray out status icons when the workspace is not running. **Before:**<img width="1624" alt="Screenshot 2025-05-29 at 21 33 45"src="https://github.com/user-attachments/assets/7916e707-e5ae-4226-8234-39c42f0ec8c4"/>**After:**<img width="1624" alt="Screenshot 2025-05-29 at 21 35 07"src="https://github.com/user-attachments/assets/52fd8553-414d-4c49-a44e-7a530f0d522d"/>#### 2. Truncate long messages**Before**<img width="1213" alt="Screenshot 2025-05-29 at 21 28 50"src="https://github.com/user-attachments/assets/b76b7a4d-7ef0-41a0-822c-c32c98f997fc"/>**After**<img width="1206" alt="Screenshot 2025-05-29 at 21 25 42"src="https://github.com/user-attachments/assets/fb3f3916-a4a4-4697-b7d1-0b4873b6e528"/>#### 3. Disable "show more" button if there is one single status
1 parente5c2548 commita19539c

File tree

7 files changed

+180
-177
lines changed

7 files changed

+180
-177
lines changed

‎site/src/modules/apps/AppStatusIcon.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,22 +25,22 @@ export const AppStatusIcon: FC<AppStatusIconProps> = ({
2525
switch(status.state){
2626
case"complete":
2727
return(
28-
<CircleCheckIconclassName={cn([className,"text-content-success"])}/>
28+
<CircleCheckIconclassName={cn(["text-content-success",className])}/>
2929
);
3030
case"failure":
3131
return(
32-
<CircleAlertIconclassName={cn([className,"text-content-warning"])}/>
32+
<CircleAlertIconclassName={cn(["text-content-warning",className])}/>
3333
);
3434
case"working":
3535
returnlatest ?(
3636
<Spinnersize="sm"className="shrink-0"loading/>
3737
) :(
38-
<HourglassIconclassName={cn([className,"text-highlight-sky"])}/>
38+
<HourglassIconclassName={cn(["text-highlight-sky",className])}/>
3939
);
4040
default:
4141
return(
4242
<TriangleAlertIcon
43-
className={cn([className,"text-content-secondary"])}
43+
className={cn(["text-content-secondary",className])}
4444
/>
4545
);
4646
}

‎site/src/modules/workspaces/WorkspaceAppStatus/WorkspaceAppStatus.stories.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,10 @@ export const LongMessage: Story = {
4848
},
4949
},
5050
};
51+
52+
exportconstDisabled:Story={
53+
args:{
54+
status:MockWorkspaceAppStatus,
55+
disabled:true,
56+
},
57+
};

‎site/src/modules/workspaces/WorkspaceAppStatus/WorkspaceAppStatus.tsx

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,22 @@
1-
importtype{
2-
WorkspaceAppStatusasAPIWorkspaceAppStatus,
3-
WorkspaceAppStatusState,
4-
}from"api/typesGenerated";
5-
import{Spinner}from"components/Spinner/Spinner";
1+
importtype{WorkspaceAppStatusasAPIWorkspaceAppStatus}from"api/typesGenerated";
62
import{
73
Tooltip,
84
TooltipContent,
95
TooltipProvider,
106
TooltipTrigger,
117
}from"components/Tooltip/Tooltip";
12-
import{CircleAlertIcon,CircleCheckIcon}from"lucide-react";
13-
importtype{ReactNode}from"react";
8+
import{AppStatusIcon}from"modules/apps/AppStatusIcon";
9+
import{cn}from"utils/cn";
1410

15-
consticonByState:Record<WorkspaceAppStatusState,ReactNode>={
16-
complete:(
17-
<CircleCheckIconclassName="size-4 shrink-0 text-content-success"/>
18-
),
19-
failure:<CircleAlertIconclassName="size-4 shrink-0 text-content-warning"/>,
20-
working:<Spinnersize="sm"className="shrink-0"loading/>,
11+
typeWorkspaceAppStatusProps={
12+
status:APIWorkspaceAppStatus|null;
13+
disabled?:boolean;
2114
};
2215

2316
exportconstWorkspaceAppStatus=({
2417
status,
25-
}:{
26-
status:APIWorkspaceAppStatus|null;
27-
})=>{
18+
disabled,
19+
}:WorkspaceAppStatusProps)=>{
2820
if(!status){
2921
return(
3022
<spanclassName="text-content-disabled text-sm">
@@ -39,7 +31,13 @@ export const WorkspaceAppStatus = ({
3931
<Tooltip>
4032
<TooltipTriggerasChild>
4133
<divclassName="flex items-center gap-2">
42-
{iconByState[status.state]}
34+
<AppStatusIcon
35+
status={status}
36+
latest
37+
className={cn({
38+
"text-content-disabled":disabled,
39+
})}
40+
/>
4341
<spanclassName="whitespace-nowrap max-w-72 overflow-hidden text-ellipsis text-sm text-content-primary font-medium">
4442
{status.message}
4543
</span>
Lines changed: 62 additions & 150 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
importtype{Meta,StoryObj}from"@storybook/react";
2+
importtype{WorkspaceAppStatus}from"api/typesGenerated";
23
import{
34
MockWorkspace,
45
MockWorkspaceAgent,
56
MockWorkspaceApp,
67
MockWorkspaceAppStatus,
8+
MockWorkspaceAppStatuses,
9+
createTimestamp,
710
}from"testHelpers/entities";
811
import{withProxyProvider}from"testHelpers/storybook";
912
import{AppStatuses}from"./AppStatuses";
@@ -13,6 +16,8 @@ const meta: Meta<typeof AppStatuses> = {
1316
component:AppStatuses,
1417
args:{
1518
referenceDate:newDate("2024-03-26T15:15:00Z"),
19+
agent:mockAgent(MockWorkspaceAppStatuses),
20+
workspace:MockWorkspace,
1621
},
1722
decorators:[withProxyProvider()],
1823
};
@@ -21,163 +26,70 @@ export default meta;
2126

2227
typeStory=StoryObj<typeofAppStatuses>;
2328

24-
exportconstDefault:Story={
29+
exportconstDefault:Story={};
30+
31+
// Add a story with a "Working" status as the latest
32+
exportconstWorkingState:Story={
2533
args:{
26-
workspace:MockWorkspace,
27-
agent:{
28-
...MockWorkspaceAgent,
29-
apps:[
30-
{
31-
...MockWorkspaceApp,
32-
statuses:[
33-
{
34-
// This is the latest status chronologically (15:04:38)
35-
...MockWorkspaceAppStatus,
36-
id:"status-7",
37-
icon:"/emojis/1f4dd.png",// 📝
38-
message:"Creating PR with gh CLI",
39-
created_at:createTimestamp(4,38),// 15:04:38
40-
uri:"https://github.com/coder/coder/pull/5678",
41-
state:"complete"asconst,
42-
},
43-
{
44-
// (15:03:56)
45-
...MockWorkspaceAppStatus,
46-
id:"status-6",
47-
icon:"/emojis/1f680.png",// 🚀
48-
message:"Pushing branch to remote",
49-
created_at:createTimestamp(3,56),// 15:03:56
50-
uri:"",
51-
state:"complete"asconst,
52-
},
53-
{
54-
// (15:02:29)
55-
...MockWorkspaceAppStatus,
56-
id:"status-5",
57-
icon:"/emojis/1f527.png",// 🔧
58-
message:"Configuring git identity",
59-
created_at:createTimestamp(2,29),// 15:02:29
60-
uri:"",
61-
state:"complete"asconst,
62-
},
63-
{
64-
// (15:02:04)
65-
...MockWorkspaceAppStatus,
66-
id:"status-4",
67-
icon:"/emojis/1f4be.png",// 💾
68-
message:"Committing changes",
69-
created_at:createTimestamp(2,4),// 15:02:04
70-
uri:"",
71-
state:"complete"asconst,
72-
},
73-
{
74-
// (15:01:44)
75-
...MockWorkspaceAppStatus,
76-
id:"status-3",
77-
icon:"/emojis/2795.png",// +
78-
message:"Adding files to staging",
79-
created_at:createTimestamp(1,44),// 15:01:44
80-
uri:"",
81-
state:"complete"asconst,
82-
},
83-
{
84-
// (15:01:32)
85-
...MockWorkspaceAppStatus,
86-
id:"status-2",
87-
icon:"/emojis/1f33f.png",// 🌿
88-
message:"Creating a new branch for PR",
89-
created_at:createTimestamp(1,32),// 15:01:32
90-
uri:"",
91-
state:"complete"asconst,
92-
},
93-
{
94-
// (15:01:00) - Oldest
95-
...MockWorkspaceAppStatus,
96-
id:"status-1",
97-
icon:"/emojis/1f680.png",// 🚀
98-
message:"Starting to create a PR",
99-
created_at:createTimestamp(1,0),// 15:01:00
100-
uri:"",
101-
state:"complete"asconst,
102-
},
103-
].sort(
104-
(a,b)=>
105-
newDate(b.created_at).getTime()-
106-
newDate(a.created_at).getTime(),
107-
),// Ensure sorted correctly for component input if needed
108-
},
109-
],
110-
},
34+
agent:mockAgent([
35+
{
36+
// This is now the latest (15:05:15) and is "working"
37+
...MockWorkspaceAppStatus,
38+
id:"status-8",
39+
icon:"",// Let the component handle the spinner icon
40+
message:"Processing final checks...",
41+
created_at:createTimestamp(5,15),// 15:05:15 (after referenceDate)
42+
uri:"",
43+
state:"working"asconst,
44+
},
45+
...MockWorkspaceAppStatuses,
46+
]),
47+
},
48+
};
11149

112-
// Pass the reference date to the component for Storybook rendering
50+
exportconstLongStatusText:Story={
51+
args:{
52+
agent:mockAgent([
53+
{
54+
// This is now the latest (15:05:15) and is "working"
55+
...MockWorkspaceAppStatus,
56+
id:"status-8",
57+
icon:"",// Let the component handle the spinner icon
58+
message:
59+
"Processing final checks with a very long message that exceeds the usual length to test how the component handles overflow and truncation in the UI. This should be long enough to ensure it wraps correctly and doesn't break the layout.",
60+
created_at:createTimestamp(5,15),// 15:05:15 (after referenceDate)
61+
uri:"",
62+
state:"complete"asconst,
63+
},
64+
...MockWorkspaceAppStatuses,
65+
]),
11366
},
11467
};
11568

116-
// Add a story with a "Working" status as the latest
117-
exportconstWorkingState:Story={
69+
exportconstSingleStatus:Story={
11870
args:{
119-
workspace:MockWorkspace,
120-
agent:{
121-
...MockWorkspaceAgent,
122-
apps:[
123-
{
124-
...MockWorkspaceApp,
125-
statuses:[
126-
{
127-
// This is now the latest (15:05:15) and is "working"
128-
...MockWorkspaceAppStatus,
129-
id:"status-8",
130-
icon:"",// Let the component handle the spinner icon
131-
message:"Processing final checks...",
132-
created_at:createTimestamp(5,15),// 15:05:15 (after referenceDate)
133-
uri:"",
134-
state:"working"asconst,
135-
},
136-
{
137-
// Previous latest (15:04:38)
138-
...MockWorkspaceAppStatus,
139-
id:"status-7",
140-
icon:"/emojis/1f4dd.png",// 📝
141-
message:"Creating PR with gh CLI",
142-
created_at:createTimestamp(4,38),// 15:04:38
143-
uri:"https://github.com/coder/coder/pull/5678",
144-
state:"complete"asconst,
145-
},
146-
{
147-
// (15:03:56)
148-
...MockWorkspaceAppStatus,
149-
id:"status-6",
150-
icon:"/emojis/1f680.png",// 🚀
151-
message:"Pushing branch to remote",
152-
created_at:createTimestamp(3,56),// 15:03:56
153-
uri:"",
154-
state:"complete"asconst,
155-
},
156-
// ... include other older statuses if desired ...
157-
{
158-
// (15:01:00) - Oldest
159-
...MockWorkspaceAppStatus,
160-
id:"status-1",
161-
icon:"/emojis/1f680.png",// 🚀
162-
message:"Starting to create a PR",
163-
created_at:createTimestamp(1,0),// 15:01:00
164-
uri:"",
165-
state:"complete"asconst,
166-
},
167-
].sort(
168-
(a,b)=>
169-
newDate(b.created_at).getTime()-
170-
newDate(a.created_at).getTime(),
171-
),
172-
},
173-
],
174-
},
71+
agent:mockAgent([
72+
{
73+
...MockWorkspaceAppStatus,
74+
id:"status-1",
75+
icon:"",
76+
message:"Initial setup complete.",
77+
created_at:createTimestamp(5,10),// 15:05:10 (after referenceDate)
78+
uri:"",
79+
state:"complete"asconst,
80+
},
81+
]),
17582
},
17683
};
17784

178-
functioncreateTimestamp(minuteOffset:number,secondOffset:number){
179-
constbaseDate=newDate("2024-03-26T15:00:00Z");
180-
baseDate.setMinutes(baseDate.getMinutes()+minuteOffset);
181-
baseDate.setSeconds(baseDate.getSeconds()+secondOffset);
182-
returnbaseDate.toISOString();
85+
functionmockAgent(statuses:WorkspaceAppStatus[]){
86+
return{
87+
...MockWorkspaceAgent,
88+
apps:[
89+
{
90+
...MockWorkspaceApp,
91+
statuses,
92+
},
93+
],
94+
};
18395
}

‎site/src/pages/WorkspacePage/AppStatuses.tsx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -103,15 +103,17 @@ export const AppStatuses: FC<AppStatusesProps> = ({
103103
<divclassName="flex flex-col border border-solid border-border rounded-lg">
104104
<div
105105
className={`
106-
flex items-center justify-between px-4 py-3
106+
flex items-center justify-between px-4 py-3 gap-6
107107
border-0 [&:not(:last-child)]:border-b border-solid border-border
108108
`}
109109
>
110-
<divclassName="flex flex-col">
111-
<spanclassName="text-sm font-medium text-content-primary flex items-center gap-2">
110+
<divclassName="flex flex-col overflow-hidden">
111+
<divclassName="text-sm font-medium text-content-primary flex items-center gap-2">
112112
<AppStatusIconstatus={latestStatus}latest/>
113-
{latestStatus.message}
114-
</span>
113+
<spanclassName="block flex-1 whitespace-nowrap overflow-hidden text-ellipsis">
114+
{latestStatus.message}
115+
</span>
116+
</div>
115117
<spanclassName="text-xs text-content-secondary first-letter:uppercase block pl-[26px]">
116118
{timeFrom(newDate(latestStatus.created_at),comparisonDate)}
117119
</span>
@@ -154,6 +156,7 @@ export const AppStatuses: FC<AppStatusesProps> = ({
154156
<Tooltip>
155157
<TooltipTriggerasChild>
156158
<Button
159+
disabled={otherStatuses.length===0}
157160
size="icon"
158161
variant="subtle"
159162
onClick={()=>{

‎site/src/pages/WorkspacesPage/WorkspacesTable.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,10 @@ export const WorkspacesTable: FC<WorkspacesTableProps> = ({
297297

298298
{hasActivity&&(
299299
<TableCell>
300-
<WorkspaceAppStatusstatus={workspace.latest_app_status}/>
300+
<WorkspaceAppStatus
301+
status={workspace.latest_app_status}
302+
disabled={workspace.latest_build.status!=="running"}
303+
/>
301304
</TableCell>
302305
)}
303306

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp