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

Commit9abf6ec

Browse files
authored
feat(site): show favorite workspaces in ui (#11875)
* Add Star beside workspace name to indicate favorite status in WorkspacesList* Add button in workspace top row to toggle workspace favorite status
1 parentacd22b2 commit9abf6ec

File tree

13 files changed

+149
-1
lines changed

13 files changed

+149
-1
lines changed

‎site/src/api/api.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1688,3 +1688,11 @@ export const updateHealthSettings = async (
16881688
);
16891689
returnresponse.data;
16901690
};
1691+
1692+
exportconstputFavoriteWorkspace=async(workspaceID:string)=>{
1693+
awaitaxios.put(`/api/v2/workspaces/${workspaceID}/favorite`);
1694+
};
1695+
1696+
exportconstdeleteFavoriteWorkspace=async(workspaceID:string)=>{
1697+
awaitaxios.delete(`/api/v2/workspaces/${workspaceID}/favorite`);
1698+
};

‎site/src/api/queries/workspaces.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,3 +265,30 @@ const updateWorkspaceBuild = async (
265265
queryKey:workspaceBuildsKey(build.workspace_id),
266266
});
267267
};
268+
269+
exportconsttoggleFavorite=(
270+
workspace:Workspace,
271+
queryClient:QueryClient,
272+
)=>{
273+
return{
274+
mutationFn:()=>{
275+
if(workspace.favorite){
276+
returnAPI.deleteFavoriteWorkspace(workspace.id);
277+
}else{
278+
returnAPI.putFavoriteWorkspace(workspace.id);
279+
}
280+
},
281+
onSuccess:async()=>{
282+
queryClient.setQueryData(
283+
workspaceByOwnerAndNameKey(workspace.owner_name,workspace.name),
284+
{ ...workspace,favorite:!workspace.favorite},
285+
);
286+
awaitqueryClient.invalidateQueries({
287+
queryKey:workspaceByOwnerAndNameKey(
288+
workspace.owner_name,
289+
workspace.name,
290+
),
291+
});
292+
},
293+
};
294+
};

‎site/src/pages/WorkspacePage/Workspace.stories.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,13 @@ export const Running: Story = {
9090
},
9191
};
9292

93+
exportconstFavorite:Story={
94+
args:{
95+
...Running.args,
96+
workspace:Mocks.MockFavoriteWorkspace,
97+
},
98+
};
99+
93100
exportconstWithoutUpdateAccess:Story={
94101
args:{
95102
...Running.args,

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export interface WorkspaceProps {
3333
handleSettings:()=>void;
3434
handleChangeVersion:()=>void;
3535
handleDormantActivate:()=>void;
36+
handleToggleFavorite:()=>void;
3637
isUpdating:boolean;
3738
isRestarting:boolean;
3839
workspace:TypesGen.Workspace;
@@ -64,6 +65,7 @@ export const Workspace: FC<WorkspaceProps> = ({
6465
handleSettings,
6566
handleChangeVersion,
6667
handleDormantActivate,
68+
handleToggleFavorite,
6769
workspace,
6870
isUpdating,
6971
isRestarting,
@@ -131,6 +133,7 @@ export const Workspace: FC<WorkspaceProps> = ({
131133
handleBuildRetryDebug={handleBuildRetryDebug}
132134
handleChangeVersion={handleChangeVersion}
133135
handleDormantActivate={handleDormantActivate}
136+
handleToggleFavorite={handleToggleFavorite}
134137
canRetryDebugMode={canRetryDebugMode}
135138
canChangeVersions={canChangeVersions}
136139
isUpdating={isUpdating}

‎site/src/pages/WorkspacePage/WorkspaceActions/Buttons.tsx

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import OutlinedBlockIcon from "@mui/icons-material/BlockOutlined";
99
importPowerSettingsNewIconfrom"@mui/icons-material/PowerSettingsNew";
1010
importRetryIconfrom"@mui/icons-material/BuildOutlined";
1111
importRetryDebugIconfrom"@mui/icons-material/BugReportOutlined";
12+
importStarfrom"@mui/icons-material/Star";
13+
importStarBorderfrom"@mui/icons-material/StarBorder";
1214
import{typeFC}from"react";
1315
importtype{Workspace,WorkspaceBuildParameter}from"api/typesGenerated";
1416
import{BuildParametersPopover}from"./BuildParametersPopover";
@@ -190,3 +192,24 @@ export const RetryButton: FC<RetryButtonProps> = ({
190192
</TopbarButton>
191193
);
192194
};
195+
196+
interfaceFavoriteButtonProps{
197+
onToggle:(workspaceID:string)=>void;
198+
workspaceID:string;
199+
isFavorite:boolean;
200+
}
201+
202+
exportconstFavoriteButton:FC<FavoriteButtonProps>=({
203+
onToggle:onToggle,
204+
workspaceID,
205+
isFavorite,
206+
})=>{
207+
return(
208+
<TopbarButton
209+
startIcon={isFavorite ?<Star/> :<StarBorder/>}
210+
onClick={()=>onToggle(workspaceID)}
211+
>
212+
{isFavorite ?"Unfavorite" :"Favorite"}
213+
</TopbarButton>
214+
);
215+
};

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
UpdateButton,
1313
ActivateButton,
1414
RetryButton,
15+
FavoriteButton,
1516
}from"./Buttons";
1617

1718
importDividerfrom"@mui/material/Divider";
@@ -30,6 +31,7 @@ import MoreVertOutlined from "@mui/icons-material/MoreVertOutlined";
3031

3132
exportinterfaceWorkspaceActionsProps{
3233
workspace:Workspace;
34+
handleToggleFavorite:()=>void;
3335
handleStart:(buildParameters?:WorkspaceBuildParameter[])=>void;
3436
handleStop:()=>void;
3537
handleRestart:(buildParameters?:WorkspaceBuildParameter[])=>void;
@@ -51,6 +53,7 @@ export interface WorkspaceActionsProps {
5153

5254
exportconstWorkspaceActions:FC<WorkspaceActionsProps>=({
5355
workspace,
56+
handleToggleFavorite,
5457
handleStart,
5558
handleStop,
5659
handleRestart,
@@ -131,6 +134,13 @@ export const WorkspaceActions: FC<WorkspaceActionsProps> = ({
131134
activating:<ActivateButtonloadinghandleAction={handleDormantActivate}/>,
132135
retry:<RetryButtonhandleAction={handleRetry}/>,
133136
retryDebug:<RetryButtondebughandleAction={handleRetryDebug}/>,
137+
toggleFavorite:(
138+
<FavoriteButton
139+
workspaceID={workspace.id}
140+
isFavorite={workspace.favorite}
141+
onToggle={handleToggleFavorite}
142+
/>
143+
),
134144
};
135145

136146
return(
@@ -150,6 +160,8 @@ export const WorkspaceActions: FC<WorkspaceActionsProps> = ({
150160

151161
{showCancel&&<CancelButtonhandleAction={handleCancel}/>}
152162

163+
{buttonMapping.toggleFavorite}
164+
153165
<MoreMenu>
154166
<MoreMenuTrigger>
155167
<TopbarIconButton

‎site/src/pages/WorkspacePage/WorkspaceActions/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export const actionTypes = [
1515
"updating",
1616
"activate",
1717
"activating",
18+
"toggleFavorite",
1819

1920
// There's no need for a retrying state because retrying starts a transition
2021
// into one of the starting, stopping, or deleting states (based on the

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
updateWorkspace,
2121
stopWorkspace,
2222
startWorkspace,
23+
toggleFavorite,
2324
cancelBuild,
2425
}from"api/queries/workspaces";
2526
import{Alert}from"components/Alert/Alert";
@@ -144,6 +145,11 @@ export const WorkspaceReadyPage: FC<WorkspaceReadyPageProps> = ({
144145
startWorkspace(workspace,queryClient),
145146
);
146147

148+
// Toggle workspace favorite
149+
consttoggleFavoriteMutation=useMutation(
150+
toggleFavorite(workspace,queryClient),
151+
);
152+
147153
// Cancel build
148154
constcancelBuildMutation=useMutation(cancelBuild(workspace,queryClient));
149155

@@ -217,6 +223,9 @@ export const WorkspaceReadyPage: FC<WorkspaceReadyPageProps> = ({
217223
displayError(message);
218224
}
219225
}}
226+
handleToggleFavorite={()=>{
227+
toggleFavoriteMutation.mutate();
228+
}}
220229
latestVersion={latestVersion}
221230
canChangeVersions={canChangeVersions}
222231
hideSSHButton={featureVisibility["browser_only"]}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ export interface WorkspaceProps {
6363
template:TypesGen.Template;
6464
permissions:WorkspacePermissions;
6565
latestVersion?:TypesGen.TemplateVersion;
66+
handleToggleFavorite:()=>void;
6667
}
6768

6869
exportconstWorkspaceTopbar:FC<WorkspaceProps>=({
@@ -75,6 +76,7 @@ export const WorkspaceTopbar: FC<WorkspaceProps> = ({
7576
handleSettings,
7677
handleChangeVersion,
7778
handleDormantActivate,
79+
handleToggleFavorite,
7880
workspace,
7981
isUpdating,
8082
isRestarting,
@@ -278,6 +280,7 @@ export const WorkspaceTopbar: FC<WorkspaceProps> = ({
278280
handleRetryDebug={handleBuildRetryDebug}
279281
handleChangeVersion={handleChangeVersion}
280282
handleDormantActivate={handleDormantActivate}
283+
handleToggleFavorite={handleToggleFavorite}
281284
canRetryDebug={canRetryDebugMode}
282285
canChangeVersions={canChangeVersions}
283286
isUpdating={isUpdating}

‎site/src/pages/WorkspacesPage/WorkspacesPageView.stories.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,17 @@ export const AllStates: Story = {
165165
},
166166
};
167167

168+
exportconstAllStatesWithFavorites:Story={
169+
args:{
170+
workspaces:allWorkspaces.map((workspace,i)=>({
171+
...workspace,
172+
// NOTE: testing sort order is not relevant here.
173+
favorite:i%2===0,
174+
})),
175+
count:allWorkspaces.length,
176+
},
177+
};
178+
168179
consticons=[
169180
"/icon/code.svg",
170181
"/icon/aws.svg",

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import TableRow from "@mui/material/TableRow";
77
importCheckboxfrom"@mui/material/Checkbox";
88
importSkeletonfrom"@mui/material/Skeleton";
99
importKeyboardArrowRightfrom"@mui/icons-material/KeyboardArrowRight";
10+
importStarfrom"@mui/icons-material/Star";
1011
import{useTheme}from"@emotion/react";
1112
import{typeFC,typeReactNode}from"react";
1213
import{useNavigate}from"react-router-dom";
@@ -150,6 +151,9 @@ export const WorkspacesTable: FC<WorkspacesTableProps> = ({
150151
alignItems="center"
151152
>
152153
{workspace.name}
154+
{workspace.favorite&&(
155+
<Starcss={{width:16,height:16}}/>
156+
)}
153157
{workspace.outdated&&(
154158
<WorkspaceOutdatedTooltip
155159
templateName={workspace.template_name}

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

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import{useMutation}from"react-query";
22
import{
33
deleteWorkspace,
4+
deleteFavoriteWorkspace,
5+
putFavoriteWorkspace,
46
startWorkspace,
57
stopWorkspace,
68
updateWorkspace,
@@ -63,12 +65,44 @@ export function useBatchActions(options: UseBatchActionsProps) {
6365
},
6466
});
6567

68+
constfavoriteAllMutation=useMutation({
69+
mutationFn:(workspaces:Workspace[])=>{
70+
returnPromise.all(
71+
workspaces
72+
.filter((w)=>!w.favorite)
73+
.map((w)=>putFavoriteWorkspace(w.id)),
74+
);
75+
},
76+
onSuccess,
77+
onError:()=>{
78+
displayError("Failed to favorite some workspaces");
79+
},
80+
});
81+
82+
constunfavoriteAllMutation=useMutation({
83+
mutationFn:(workspaces:Workspace[])=>{
84+
returnPromise.all(
85+
workspaces
86+
.filter((w)=>w.favorite)
87+
.map((w)=>deleteFavoriteWorkspace(w.id)),
88+
);
89+
},
90+
onSuccess,
91+
onError:()=>{
92+
displayError("Failed to unfavorite some workspaces");
93+
},
94+
});
95+
6696
return{
97+
favoriteAll:favoriteAllMutation.mutateAsync,
98+
unfavoriteAll:unfavoriteAllMutation.mutateAsync,
6799
startAll:startAllMutation.mutateAsync,
68100
stopAll:stopAllMutation.mutateAsync,
69101
deleteAll:deleteAllMutation.mutateAsync,
70102
updateAll:updateAllMutation.mutateAsync,
71103
isLoading:
104+
favoriteAllMutation.isLoading||
105+
unfavoriteAllMutation.isLoading||
72106
startAllMutation.isLoading||
73107
stopAllMutation.isLoading||
74108
deleteAllMutation.isLoading,

‎site/src/testHelpers/entities.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {
44
typeDeploymentConfig,
55
}from"api/api";
66
import{FieldError}from"api/errors";
7-
importtype*asTypesGenfrom"api/typesGenerated";
7+
import*asTypesGenfrom"api/typesGenerated";
88
importrangefrom"lodash/range";
99
importtype{Permissions}from"contexts/auth/permissions";
1010
import{TemplateVersionFiles}from"utils/templateVersion";
@@ -1020,6 +1020,12 @@ export const MockWorkspace: TypesGen.Workspace = {
10201020
},
10211021
automatic_updates:"never",
10221022
allow_renames:true,
1023+
favorite:false,
1024+
};
1025+
1026+
exportconstMockFavoriteWorkspace:TypesGen.Workspace={
1027+
...MockWorkspace,
1028+
id:"test-favorite-workspace",
10231029
favorite:true,
10241030
};
10251031

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp