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

Commit84922e2

Browse files
authored
feat: add provisioners view to organization settings (#14501)
1 parentc3f0db3 commit84922e2

16 files changed

+443
-205
lines changed

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,13 @@ export const organizationsPermissions = (
223223
},
224224
action:"create",
225225
},
226+
viewProvisioners:{
227+
object:{
228+
resource_type:"provisioner_daemon",
229+
organization_id:organizationId,
230+
},
231+
action:"read",
232+
},
226233
});
227234

228235
// The endpoint takes a flat array, so to avoid collisions prepend each

‎site/src/components/Pill/Pill.tsx

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import type { ThemeRole } from "theme/roles";
1414
exporttypePillProps=HTMLAttributes<HTMLDivElement>&{
1515
icon?:ReactNode;
1616
type?:ThemeRole;
17+
size?:"md"|"lg";
1718
};
1819

1920
constthemeStyles=(type:ThemeRole)=>(theme:Theme)=>{
@@ -30,13 +31,25 @@ const PILL_ICON_SPACING = (PILL_HEIGHT - PILL_ICON_SIZE) / 2;
3031

3132
exportconstPill:FC<PillProps>=forwardRef<HTMLDivElement,PillProps>(
3233
(props,ref)=>{
33-
const{ icon, type="inactive", children, ...divProps}=props;
34+
const{
35+
icon,
36+
type="inactive",
37+
children,
38+
size="md",
39+
...divProps
40+
}=props;
3441
consttypeStyles=useMemo(()=>themeStyles(type),[type]);
3542

3643
return(
3744
<div
3845
ref={ref}
39-
css={[styles.pill,icon&&styles.pillWithIcon,typeStyles]}
46+
css={[
47+
styles.pill,
48+
icon&&size==="md"&&styles.pillWithIcon,
49+
size==="lg"&&styles.pillLg,
50+
icon&&size==="lg"&&styles.pillLgWithIcon,
51+
typeStyles,
52+
]}
4053
{...divProps}
4154
>
4255
{icon}
@@ -80,6 +93,15 @@ const styles = {
8093
paddingLeft:PILL_ICON_SPACING,
8194
},
8295

96+
pillLg:{
97+
gap:PILL_ICON_SPACING*2,
98+
padding:"14px 16px",
99+
},
100+
101+
pillLgWithIcon:{
102+
paddingLeft:PILL_ICON_SPACING*2,
103+
},
104+
83105
spinner:(theme)=>({
84106
color:theme.experimental.l1.text,
85107
// It is necessary to align it with the MUI Icons internal padding
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
import{useTheme}from"@emotion/react";
2+
importBusinessfrom"@mui/icons-material/Business";
3+
importPersonfrom"@mui/icons-material/Person";
4+
importTooltipfrom"@mui/material/Tooltip";
5+
importtype{HealthMessage,ProvisionerDaemon}from"api/typesGenerated";
6+
import{Pill}from"components/Pill/Pill";
7+
importtype{FC}from"react";
8+
import{createDayString}from"utils/createDayString";
9+
import{ProvisionerTag}from"./ProvisionerTag";
10+
11+
interfaceProvisionerProps{
12+
readonlyprovisioner:ProvisionerDaemon;
13+
readonlywarnings?:readonlyHealthMessage[];
14+
}
15+
16+
exportconstProvisioner:FC<ProvisionerProps>=({
17+
provisioner,
18+
warnings,
19+
})=>{
20+
consttheme=useTheme();
21+
constdaemonScope=provisioner.tags.scope||"organization";
22+
consticonScope=daemonScope==="organization" ?<Business/> :<Person/>;
23+
24+
constextraTags=Object.entries(provisioner.tags).filter(
25+
([key])=>key!=="scope"&&key!=="owner",
26+
);
27+
constisWarning=warnings&&warnings.length>0;
28+
return(
29+
<div
30+
key={provisioner.name}
31+
css={[
32+
{
33+
borderRadius:8,
34+
border:`1px solid${theme.palette.divider}`,
35+
fontSize:14,
36+
},
37+
isWarning&&{borderColor:theme.palette.warning.light},
38+
]}
39+
>
40+
<header
41+
css={{
42+
padding:24,
43+
display:"flex",
44+
alignItems:"center",
45+
justifyContenxt:"space-between",
46+
gap:24,
47+
}}
48+
>
49+
<div
50+
css={{
51+
display:"flex",
52+
alignItems:"center",
53+
gap:24,
54+
objectFit:"fill",
55+
}}
56+
>
57+
<divcss={{lineHeight:"160%"}}>
58+
<h4css={{fontWeight:500,margin:0}}>{provisioner.name}</h4>
59+
<spancss={{color:theme.palette.text.secondary}}>
60+
<code>{provisioner.version}</code>
61+
</span>
62+
</div>
63+
</div>
64+
<div
65+
css={{
66+
marginLeft:"auto",
67+
display:"flex",
68+
flexWrap:"wrap",
69+
gap:12,
70+
}}
71+
>
72+
<Tooltiptitle="Scope">
73+
<Pillsize="lg"icon={iconScope}>
74+
<span
75+
css={{
76+
":first-letter":{textTransform:"uppercase"},
77+
}}
78+
>
79+
{daemonScope}
80+
</span>
81+
</Pill>
82+
</Tooltip>
83+
{extraTags.map(([key,value])=>(
84+
<ProvisionerTagkey={key}tagName={key}tagValue={value}/>
85+
))}
86+
</div>
87+
</header>
88+
89+
<div
90+
css={{
91+
borderTop:`1px solid${theme.palette.divider}`,
92+
display:"flex",
93+
alignItems:"center",
94+
justifyContent:"space-between",
95+
padding:"8px 24px",
96+
fontSize:12,
97+
color:theme.palette.text.secondary,
98+
}}
99+
>
100+
{warnings&&warnings.length>0 ?(
101+
<divcss={{display:"flex",flexDirection:"column"}}>
102+
{warnings.map((warning)=>(
103+
<spankey={warning.code}>{warning.message}</span>
104+
))}
105+
</div>
106+
) :(
107+
<span>No warnings</span>
108+
)}
109+
{provisioner.last_seen_at&&(
110+
<spancss={{color:theme.roles.info.text}}data-chromatic="ignore">
111+
Last seen{createDayString(provisioner.last_seen_at)}
112+
</span>
113+
)}
114+
</div>
115+
</div>
116+
);
117+
};
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
importtype{Interpolation,Theme}from"@emotion/react";
2+
importCheckCircleOutlinedfrom"@mui/icons-material/CheckCircleOutlined";
3+
importCloseIconfrom"@mui/icons-material/Close";
4+
importDoNotDisturbOnOutlinedfrom"@mui/icons-material/DoNotDisturbOnOutlined";
5+
importSellfrom"@mui/icons-material/Sell";
6+
importIconButtonfrom"@mui/material/IconButton";
7+
import{Pill}from"components/Pill/Pill";
8+
importtype{ComponentProps,FC}from"react";
9+
10+
constparseBool=(s:string):{valid:boolean;value:boolean}=>{
11+
switch(s.toLowerCase()){
12+
case"true":
13+
case"yes":
14+
case"1":
15+
return{valid:true,value:true};
16+
case"false":
17+
case"no":
18+
case"0":
19+
case"":
20+
return{valid:true,value:false};
21+
default:
22+
return{valid:false,value:false};
23+
}
24+
};
25+
26+
interfaceProvisionerTagProps{
27+
tagName:string;
28+
tagValue:string;
29+
/** Only used in the TemplateVersionEditor */
30+
onDelete?:(tagName:string)=>void;
31+
}
32+
33+
exportconstProvisionerTag:FC<ProvisionerTagProps>=({
34+
tagName,
35+
tagValue,
36+
onDelete,
37+
})=>{
38+
const{ valid,value:boolValue}=parseBool(tagValue);
39+
constkv=(
40+
<>
41+
<spancss={{fontWeight:600}}>{tagName}</span><span>{tagValue}</span>
42+
</>
43+
);
44+
constcontent=onDelete ?(
45+
<>
46+
{kv}
47+
<IconButton
48+
aria-label={`delete-${tagName}`}
49+
size="small"
50+
color="secondary"
51+
onClick={()=>{
52+
onDelete(tagName);
53+
}}
54+
>
55+
<CloseIconfontSize="inherit"css={{width:14,height:14}}/>
56+
</IconButton>
57+
</>
58+
) :(
59+
kv
60+
);
61+
if(valid){
62+
return<BooleanPillvalue={boolValue}>{content}</BooleanPill>;
63+
}
64+
return(
65+
<Pillsize="lg"icon={<Sell/>}>
66+
{content}
67+
</Pill>
68+
);
69+
};
70+
71+
typeBooleanPillProps=Omit<ComponentProps<typeofPill>,"icon"|"value">&{
72+
value:boolean;
73+
};
74+
75+
exportconstBooleanPill:FC<BooleanPillProps>=({
76+
value,
77+
children,
78+
...divProps
79+
})=>{
80+
return(
81+
<Pill
82+
type={value ?"active" :"danger"}
83+
size="lg"
84+
icon={
85+
value ?(
86+
<CheckCircleOutlinedcss={styles.truePill}/>
87+
) :(
88+
<DoNotDisturbOnOutlinedcss={styles.falsePill}/>
89+
)
90+
}
91+
{...divProps}
92+
>
93+
{children}
94+
</Pill>
95+
);
96+
};
97+
98+
conststyles={
99+
truePill:(theme)=>({
100+
color:theme.roles.active.outline,
101+
}),
102+
falsePill:(theme)=>({
103+
color:theme.roles.danger.outline,
104+
}),
105+
}satisfiesRecord<string,Interpolation<Theme>>;

‎site/src/pages/HealthPage/Content.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ export const BooleanPill: FC<BooleanPillProps> = ({
195195
...divProps
196196
})=>{
197197
consttheme=useTheme();
198-
constcolor=value ?theme.palette.success.light :theme.palette.error.light;
198+
constcolor=value ?theme.roles.success.outline :theme.roles.error.outline;
199199

200200
return(
201201
<Pill

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp