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

Commit6498464

Browse files
refactor: rollback provisioners page to its previous version (#16699)
There is still some points to be aligned related to provisioners. I'mgoing to rollback the latest changes until we are more confident on thedesign changes so we don't block releases.<img width="1512" alt="Screenshot 2025-02-25 at 13 46 35"src="https://github.com/user-attachments/assets/4bb3719c-4659-4442-b7b7-b647a9c0a916"/>
1 parent33c9aa0 commit6498464

File tree

4 files changed

+339
-4
lines changed

4 files changed

+339
-4
lines changed
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import{buildInfo}from"api/queries/buildInfo";
2+
import{provisionerDaemonGroups}from"api/queries/organizations";
3+
import{EmptyState}from"components/EmptyState/EmptyState";
4+
import{useEmbeddedMetadata}from"hooks/useEmbeddedMetadata";
5+
import{useDashboard}from"modules/dashboard/useDashboard";
6+
import{useOrganizationSettings}from"modules/management/OrganizationSettingsLayout";
7+
importtype{FC}from"react";
8+
import{Helmet}from"react-helmet-async";
9+
import{useQuery}from"react-query";
10+
import{useParams}from"react-router-dom";
11+
import{pageTitle}from"utils/page";
12+
import{OrganizationProvisionersPageView}from"./OrganizationProvisionersPageView";
13+
14+
constOrganizationProvisionersPage:FC=()=>{
15+
const{organization:organizationName}=useParams()as{
16+
organization:string;
17+
};
18+
const{ organization}=useOrganizationSettings();
19+
const{ entitlements}=useDashboard();
20+
const{ metadata}=useEmbeddedMetadata();
21+
constbuildInfoQuery=useQuery(buildInfo(metadata["build-info"]));
22+
constprovisionersQuery=useQuery(provisionerDaemonGroups(organizationName));
23+
24+
if(!organization){
25+
return<EmptyStatemessage="Organization not found"/>;
26+
}
27+
28+
return(
29+
<>
30+
<Helmet>
31+
<title>
32+
{pageTitle(
33+
"Provisioners",
34+
organization.display_name||organization.name,
35+
)}
36+
</title>
37+
</Helmet>
38+
<OrganizationProvisionersPageView
39+
showPaywall={!entitlements.features.multiple_organizations.enabled}
40+
error={provisionersQuery.error}
41+
buildInfo={buildInfoQuery.data}
42+
provisioners={provisionersQuery.data}
43+
/>
44+
</>
45+
);
46+
};
47+
48+
exportdefaultOrganizationProvisionersPage;
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
importtype{Meta,StoryObj}from"@storybook/react";
2+
import{screen,userEvent}from"@storybook/test";
3+
import{
4+
MockBuildInfo,
5+
MockProvisioner,
6+
MockProvisioner2,
7+
MockProvisionerBuiltinKey,
8+
MockProvisionerKey,
9+
MockProvisionerPskKey,
10+
MockProvisionerUserAuthKey,
11+
MockProvisionerWithTags,
12+
MockUserProvisioner,
13+
mockApiError,
14+
}from"testHelpers/entities";
15+
import{OrganizationProvisionersPageView}from"./OrganizationProvisionersPageView";
16+
17+
constmeta:Meta<typeofOrganizationProvisionersPageView>={
18+
title:"pages/OrganizationProvisionersPage",
19+
component:OrganizationProvisionersPageView,
20+
args:{
21+
buildInfo:MockBuildInfo,
22+
},
23+
};
24+
25+
exportdefaultmeta;
26+
typeStory=StoryObj<typeofOrganizationProvisionersPageView>;
27+
28+
exportconstProvisioners:Story={
29+
args:{
30+
provisioners:[
31+
{
32+
key:MockProvisionerBuiltinKey,
33+
daemons:[MockProvisioner,MockProvisioner2],
34+
},
35+
{
36+
key:MockProvisionerPskKey,
37+
daemons:[
38+
MockProvisioner,
39+
MockUserProvisioner,
40+
MockProvisionerWithTags,
41+
],
42+
},
43+
{
44+
key:MockProvisionerPskKey,
45+
daemons:[MockProvisioner,MockProvisioner2],
46+
},
47+
{
48+
key:{ ...MockProvisionerKey,id:"ジェイデン",name:"ジェイデン"},
49+
daemons:[
50+
MockProvisioner,
51+
{ ...MockProvisioner2,tags:{scope:"organization",owner:""}},
52+
],
53+
},
54+
{
55+
key:{ ...MockProvisionerKey,id:"ベン",name:"ベン"},
56+
daemons:[
57+
MockProvisioner,
58+
{
59+
...MockProvisioner2,
60+
version:"2.0.0",
61+
api_version:"1.0",
62+
},
63+
],
64+
},
65+
{
66+
key:{
67+
...MockProvisionerKey,
68+
id:"ケイラ",
69+
name:"ケイラ",
70+
tags:{
71+
...MockProvisioner.tags,
72+
都市:"ユタ",
73+
きっぷ:"yes",
74+
ちいさい:"no",
75+
},
76+
},
77+
daemons:Array.from({length:117},(_,i)=>({
78+
...MockProvisioner,
79+
id:`ケイラ-${i}`,
80+
name:`ケイラ-${i}`,
81+
})),
82+
},
83+
{
84+
key:MockProvisionerUserAuthKey,
85+
daemons:[
86+
MockUserProvisioner,
87+
{
88+
...MockUserProvisioner,
89+
id:"mock-user-provisioner-2",
90+
name:"Test User Provisioner 2",
91+
},
92+
],
93+
},
94+
],
95+
},
96+
play:async({ step})=>{
97+
awaitstep("open all details",async()=>{
98+
constexpandButtons=awaitscreen.findAllByRole("button",{
99+
name:"Show provisioner details",
100+
});
101+
for(constitofexpandButtons){
102+
awaituserEvent.click(it);
103+
}
104+
});
105+
106+
awaitstep("close uninteresting/large details",async()=>{
107+
constcollapseButtons=awaitscreen.findAllByRole("button",{
108+
name:"Hide provisioner details",
109+
});
110+
111+
awaituserEvent.click(collapseButtons[2]);
112+
awaituserEvent.click(collapseButtons[3]);
113+
awaituserEvent.click(collapseButtons[5]);
114+
});
115+
116+
awaitstep("show version popover",async()=>{
117+
constoutOfDate=awaitscreen.findByText("Out of date");
118+
awaituserEvent.hover(outOfDate);
119+
});
120+
},
121+
};
122+
123+
exportconstEmpty:Story={
124+
args:{
125+
provisioners:[],
126+
},
127+
};
128+
129+
exportconstWithError:Story={
130+
args:{
131+
error:mockApiError({
132+
message:"Fern is mad",
133+
detail:"Frieren slept in and didn't get groceries",
134+
}),
135+
},
136+
};
137+
138+
exportconstPaywall:Story={
139+
args:{
140+
showPaywall:true,
141+
},
142+
};
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
importOpenInNewIconfrom"@mui/icons-material/OpenInNew";
2+
importButtonfrom"@mui/material/Button";
3+
importtype{
4+
BuildInfoResponse,
5+
ProvisionerKey,
6+
ProvisionerKeyDaemons,
7+
}from"api/typesGenerated";
8+
import{ErrorAlert}from"components/Alert/ErrorAlert";
9+
import{EmptyState}from"components/EmptyState/EmptyState";
10+
import{Loader}from"components/Loader/Loader";
11+
import{Paywall}from"components/Paywall/Paywall";
12+
import{SettingsHeader}from"components/SettingsHeader/SettingsHeader";
13+
import{Stack}from"components/Stack/Stack";
14+
import{ProvisionerGroup}from"modules/provisioners/ProvisionerGroup";
15+
importtype{FC}from"react";
16+
import{docs}from"utils/docs";
17+
18+
interfaceOrganizationProvisionersPageViewProps{
19+
/** Determines if the paywall will be shown or not */
20+
showPaywall?:boolean;
21+
22+
/** An error to display instead of the page content */
23+
error?:unknown;
24+
25+
/** Info about the version of coderd */
26+
buildInfo?:BuildInfoResponse;
27+
28+
/** Groups of provisioners, along with their key information */
29+
provisioners?:readonlyProvisionerKeyDaemons[];
30+
}
31+
32+
exportconstOrganizationProvisionersPageView:FC<
33+
OrganizationProvisionersPageViewProps
34+
>=({ showPaywall, error, buildInfo, provisioners})=>{
35+
return(
36+
<div>
37+
<Stack
38+
alignItems="baseline"
39+
direction="row"
40+
justifyContent="space-between"
41+
>
42+
<SettingsHeadertitle="Provisioners"/>
43+
{!showPaywall&&(
44+
<Button
45+
endIcon={<OpenInNewIcon/>}
46+
target="_blank"
47+
href={docs("/admin/provisioners")}
48+
>
49+
Create a provisioner
50+
</Button>
51+
)}
52+
</Stack>
53+
{showPaywall ?(
54+
<Paywall
55+
message="Provisioners"
56+
description="Provisioners run your Terraform to create templates and workspaces. You need a Premium license to use this feature for multiple organizations."
57+
documentationLink={docs("/")}
58+
/>
59+
) :error ?(
60+
<ErrorAlerterror={error}/>
61+
) :!buildInfo||!provisioners ?(
62+
<Loader/>
63+
) :(
64+
<ViewContentbuildInfo={buildInfo}provisioners={provisioners}/>
65+
)}
66+
</div>
67+
);
68+
};
69+
70+
typeViewContentProps=Required<
71+
Pick<OrganizationProvisionersPageViewProps,"buildInfo"|"provisioners">
72+
>;
73+
74+
constViewContent:FC<ViewContentProps>=({ buildInfo, provisioners})=>{
75+
constisEmpty=provisioners.every((group)=>group.daemons.length===0);
76+
77+
constprovisionerGroupsCount=provisioners.length;
78+
constprovisionersCount=provisioners.reduce(
79+
(a,group)=>a+group.daemons.length,
80+
0,
81+
);
82+
83+
return(
84+
<>
85+
{isEmpty ?(
86+
<EmptyState
87+
message="No provisioners"
88+
description="A provisioner is required before you can create templates and workspaces. You can connect your first provisioner by following our documentation."
89+
cta={
90+
<Button
91+
endIcon={<OpenInNewIcon/>}
92+
target="_blank"
93+
href={docs("/admin/provisioners")}
94+
>
95+
Create a provisioner
96+
</Button>
97+
}
98+
/>
99+
) :(
100+
<div
101+
css={(theme)=>({
102+
margin:0,
103+
fontSize:12,
104+
paddingBottom:18,
105+
color:theme.palette.text.secondary,
106+
})}
107+
>
108+
Showing{provisionerGroupsCount} groups and{provisionersCount}{" "}
109+
provisioners
110+
</div>
111+
)}
112+
<Stackspacing={4.5}>
113+
{provisioners.map((group)=>(
114+
<ProvisionerGroup
115+
key={group.key.id}
116+
buildInfo={buildInfo}
117+
keyName={group.key.name}
118+
keyTags={group.key.tags}
119+
type={getGroupType(group.key)}
120+
provisioners={group.daemons}
121+
/>
122+
))}
123+
</Stack>
124+
</>
125+
);
126+
};
127+
128+
// Ideally these would be generated and appear in typesGenerated.ts, but that is
129+
// not currently the case. In the meantime, these are taken from verbatim from
130+
// the corresponding codersdk declarations. The names remain unchanged to keep
131+
// usage of these special values "grep-able".
132+
// https://github.com/coder/coder/blob/7c77a3cc832fb35d9da4ca27df163c740f786137/codersdk/provisionerdaemons.go#L291-L295
133+
constProvisionerKeyIDBuiltIn="00000000-0000-0000-0000-000000000001";
134+
constProvisionerKeyIDUserAuth="00000000-0000-0000-0000-000000000002";
135+
constProvisionerKeyIDPSK="00000000-0000-0000-0000-000000000003";
136+
137+
functiongetGroupType(key:ProvisionerKey){
138+
switch(key.id){
139+
caseProvisionerKeyIDBuiltIn:
140+
return"builtin";
141+
caseProvisionerKeyIDUserAuth:
142+
return"userAuth";
143+
caseProvisionerKeyIDPSK:
144+
return"psk";
145+
default:
146+
return"key";
147+
}
148+
}

‎site/src/router.tsx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -267,10 +267,7 @@ const CreateEditRolePage = lazy(
267267
),
268268
);
269269
constProvisionersPage=lazy(
270-
()=>
271-
import(
272-
"./pages/OrganizationSettingsPage/ProvisionersPage/ProvisionersPage"
273-
),
270+
()=>import("./pages/OrganizationSettingsPage/OrganizationProvisionersPage"),
274271
);
275272
constTemplateEmbedPage=lazy(
276273
()=>import("./pages/TemplatePage/TemplateEmbedPage/TemplateEmbedPage"),

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp