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

Commit81d11dd

Browse files
committed
Add authorization, dismissal and fetch after login
1 parentb80de3c commit81d11dd

File tree

6 files changed

+168
-48
lines changed

6 files changed

+168
-48
lines changed

‎site/src/components/AlertBanner/AlertBanner.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@ import { AlertBannerCtas } from "./AlertBannerCtas"
1616
*@param text: default text to be displayed to the user; useful for warnings or as a fallback error message
1717
*@param error: should be passed in if the severity is 'Error'; warnings can use 'text' instead
1818
*@param actions: an array of CTAs passed in by the consumer
19-
*@param dismissible: determines whether or not the banner should have a `Dismiss` CTA
2019
*@param retry: a handler to retry the action that spawned the error
20+
*@param dismissible: determines whether or not the banner should have a `Dismiss` CTA
21+
*@param onDismiss: a handler that is called when the `Dismiss` CTA is clicked, after the animation has finished
2122
*/
2223
exportconstAlertBanner:FC<React.PropsWithChildren<AlertBannerProps>>=({
2324
children,
@@ -27,6 +28,7 @@ export const AlertBanner: FC<React.PropsWithChildren<AlertBannerProps>> = ({
2728
actions=[],
2829
retry,
2930
dismissible=false,
31+
onDismiss,
3032
})=>{
3133
const{ t}=useTranslation("common")
3234

@@ -50,7 +52,7 @@ export const AlertBanner: FC<React.PropsWithChildren<AlertBannerProps>> = ({
5052
const[showDetails,setShowDetails]=useState(false)
5153

5254
return(
53-
<Collapsein={open}>
55+
<Collapsein={open}onExited={()=>onDismiss&&onDismiss()}>
5456
<Stack
5557
className={classes.alertContainer}
5658
direction="row"

‎site/src/components/AlertBanner/alertTypes.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@ export interface AlertBannerProps {
99
error?:ApiError|Error|unknown
1010
actions?:ReactElement[]
1111
dismissible?:boolean
12+
onDismiss?:()=>void
1213
retry?:()=>void
1314
}

‎site/src/components/AuthAndFrame/AuthAndFrame.tsx

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import{makeStyles}from"@material-ui/core/styles"
22
import{useActor}from"@xstate/react"
33
import{Loader}from"components/Loader/Loader"
4-
import{FC,Suspense,useContext}from"react"
4+
import{FC,Suspense,useContext,useEffect}from"react"
55
import{XServiceContext}from"../../xServices/StateContext"
66
import{Footer}from"../Footer/Footer"
77
import{Navbar}from"../Navbar/Navbar"
@@ -19,20 +19,35 @@ interface AuthAndFrameProps {
1919
exportconstAuthAndFrame:FC<AuthAndFrameProps>=({ children})=>{
2020
conststyles=useStyles({})
2121
constxServices=useContext(XServiceContext)
22+
const[authState]=useActor(xServices.authXService)
2223
const[buildInfoState]=useActor(xServices.buildInfoXService)
23-
const[updateCheckState]=useActor(xServices.updateCheckXService)
24+
const[updateCheckState,updateCheckSend]=useActor(
25+
xServices.updateCheckXService,
26+
)
27+
28+
useEffect(()=>{
29+
if(authState.matches("signedIn")){
30+
updateCheckSend("CHECK")
31+
}else{
32+
updateCheckSend("CLEAR")
33+
}
34+
},[authState,updateCheckSend])
2435

2536
return(
2637
<RequireAuth>
2738
<divclassName={styles.site}>
2839
<Navbar/>
29-
<divclassName={styles.siteBanner}>
30-
<Margins>
31-
<UpdateCheckBanner
32-
updateCheck={updateCheckState.context.updateCheck}
33-
/>
34-
</Margins>
35-
</div>
40+
{updateCheckState.context.show&&(
41+
<divclassName={styles.updateCheckBanner}>
42+
<Margins>
43+
<UpdateCheckBanner
44+
updateCheck={updateCheckState.context.updateCheck}
45+
error={updateCheckState.context.error}
46+
onDismiss={()=>updateCheckSend("DISMISS")}
47+
/>
48+
</Margins>
49+
</div>
50+
)}
3651
<divclassName={styles.siteContent}>
3752
<Suspensefallback={<Loader/>}>{children}</Suspense>
3853
</div>
@@ -48,12 +63,15 @@ const useStyles = makeStyles((theme) => ({
4863
minHeight:"100vh",
4964
flexDirection:"column",
5065
},
51-
siteBanner:{
66+
updateCheckBanner:{
67+
// Add spacing at the top and remove some from the bottom. Removal
68+
// is necessary to avoid a visual jerk when the banner is dismissed.
69+
// It also give a more pleasant distance to the site content when
70+
// the banner is visible.
5271
marginTop:theme.spacing(2),
72+
marginBottom:-theme.spacing(2),
5373
},
5474
siteContent:{
5575
flex:1,
56-
// Accommodate for banner margin since it is dismissible.
57-
marginTop:-theme.spacing(2),
5876
},
5977
}))

‎site/src/components/UpdateCheckBanner/UpdateCheckBanner.tsx

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,19 @@ import * as TypesGen from "api/typesGenerated"
55

66
exportinterfaceUpdateCheckBannerProps{
77
updateCheck?:TypesGen.UpdateCheckResponse
8+
error?:Error|unknown
9+
onDismiss?:()=>void
810
}
911

1012
exportconstUpdateCheckBanner:React.FC<
1113
React.PropsWithChildren<UpdateCheckBannerProps>
12-
>=({ updateCheck})=>{
14+
>=({ updateCheck, error, onDismiss})=>{
1315
const{ t}=useTranslation("common")
1416

1517
return(
1618
<>
17-
{updateCheck&&!updateCheck.current&&(
18-
<AlertBannerseverity="info"dismissible>
19+
{!error&&updateCheck&&!updateCheck.current&&(
20+
<AlertBannerseverity="info"onDismiss={onDismiss}dismissible>
1921
<div>
2022
<Trans
2123
t={t}
@@ -32,6 +34,15 @@ export const UpdateCheckBanner: React.FC<
3234
</div>
3335
</AlertBanner>
3436
)}
37+
{error&&(
38+
<AlertBanner
39+
severity="error"
40+
error={error}
41+
text={t("updateCheck.error")}
42+
onDismiss={onDismiss}
43+
dismissible
44+
/>
45+
)}
3546
</>
3647
)
3748
}

‎site/src/i18n/en/common.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
"select":"Select emoji"
3838
},
3939
"updateCheck": {
40-
"message":"Coder {{version}} is now available. View the <4>release notes</4> and <7>upgrade instructions</7> for more information."
40+
"message":"Coder {{version}} is now available. View the <4>release notes</4> and <7>upgrade instructions</7> for more information.",
41+
"error":"Coder update check failed."
4142
}
4243
}
Lines changed: 117 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,85 +1,172 @@
11
import{assign,createMachine}from"xstate"
2-
import*asAPIfrom"api/api"
3-
import*asTypesGenfrom"api/typesGenerated"
2+
import{checkAuthorization,getUpdateCheck}from"api/api"
3+
import{AuthorizationResponse,UpdateCheckResponse}from"api/typesGenerated"
44

5-
exportconstLanguage={
6-
updateAvailable:"New version available",
7-
updateAvailableMessage:(
8-
version:string,
9-
url:string,
10-
upgrade_instructions_url:string,
11-
):string=>
12-
`Coder${version} is now available at${url}. See${upgrade_instructions_url} for information on how to upgrade.`,
13-
}
5+
exportconstchecks={
6+
viewUpdateCheck:"viewUpdateCheck",
7+
}asconst
8+
9+
exportconstpermissionsToCheck={
10+
[checks.viewUpdateCheck]:{
11+
object:{
12+
resource_type:"update_check",
13+
},
14+
action:"read",
15+
},
16+
}asconst
17+
18+
exporttypePermissions=Record<keyoftypeofpermissionsToCheck,boolean>
1419

1520
exportinterfaceUpdateCheckContext{
16-
getUpdateCheckError?:Error|unknown
17-
updateCheck?:TypesGen.UpdateCheckResponse
21+
show:boolean
22+
updateCheck?:UpdateCheckResponse
23+
permissions?:Permissions
24+
error?:Error|unknown
1825
}
1926

27+
exporttypeUpdateCheckEvent=
28+
|{type:"CHECK"}
29+
|{type:"CLEAR"}
30+
|{type:"DISMISS"}
31+
2032
exportconstupdateCheckMachine=createMachine(
2133
{
2234
id:"updateCheckState",
2335
predictableActionArguments:true,
2436
tsTypes:{}asimport("./updateCheckXService.typegen").Typegen0,
2537
schema:{
2638
context:{}asUpdateCheckContext,
39+
events:{}asUpdateCheckEvent,
2740
services:{}as{
41+
checkPermissions:{
42+
data:AuthorizationResponse
43+
}
2844
getUpdateCheck:{
29-
data:TypesGen.UpdateCheckResponse
45+
data:UpdateCheckResponse
3046
}
3147
},
3248
},
3349
context:{
34-
updateCheck:undefined,
50+
show:false,
3551
},
36-
initial:"gettingUpdateCheck",
52+
initial:"idle",
3753
states:{
38-
gettingUpdateCheck:{
54+
idle:{
55+
on:{
56+
CHECK:{
57+
target:"fetchingPermissions",
58+
},
59+
},
60+
},
61+
fetchingPermissions:{
62+
invoke:{
63+
src:"checkPermissions",
64+
id:"checkPermissions",
65+
onDone:[
66+
{
67+
actions:["assignPermissions"],
68+
target:"checkingPermissions",
69+
},
70+
],
71+
onError:[
72+
{
73+
actions:["assignError"],
74+
target:"show",
75+
},
76+
],
77+
},
78+
},
79+
checkingPermissions:{
80+
always:[
81+
{
82+
target:"fetchingUpdateCheck",
83+
cond:"canViewUpdateCheck",
84+
},
85+
{
86+
target:"dismissOrClear",
87+
cond:"canNotViewUpdateCheck",
88+
},
89+
],
90+
},
91+
fetchingUpdateCheck:{
3992
invoke:{
4093
src:"getUpdateCheck",
4194
id:"getUpdateCheck",
4295
onDone:[
4396
{
44-
actions:["assignUpdateCheck","clearGetUpdateCheckError"],
45-
target:"#updateCheckState.success",
97+
actions:["assignUpdateCheck","clearError"],
98+
target:"show",
4699
},
47100
],
48101
onError:[
49102
{
50-
actions:["assignGetUpdateCheckError","clearUpdateCheck"],
51-
target:"#updateCheckState.failure",
103+
actions:["assignError","clearUpdateCheck"],
104+
target:"show",
52105
},
53106
],
54107
},
55108
},
56-
success:{
57-
type:"final",
109+
show:{
110+
entry:"assignShow",
111+
always:[
112+
{
113+
target:"dismissOrClear",
114+
},
115+
],
116+
},
117+
dismissOrClear:{
118+
on:{
119+
DISMISS:{
120+
actions:["assignHide"],
121+
target:"dismissed",
122+
},
123+
CLEAR:{
124+
actions:["clearUpdateCheck","clearError","assignHide"],
125+
target:"idle",
126+
},
127+
},
58128
},
59-
failure:{
129+
dismissed:{
60130
type:"final",
61131
},
62132
},
63133
},
64134
{
65135
services:{
66-
getUpdateCheck:API.getUpdateCheck,
136+
checkPermissions:async()=>
137+
checkAuthorization({checks:permissionsToCheck}),
138+
getUpdateCheck:getUpdateCheck,
67139
},
68140
actions:{
141+
assignPermissions:assign({
142+
permissions:(_,event)=>event.dataasPermissions,
143+
}),
144+
assignShow:assign({
145+
show:true,
146+
}),
147+
assignHide:assign({
148+
show:false,
149+
}),
69150
assignUpdateCheck:assign({
70151
updateCheck:(_,event)=>event.data,
71152
}),
72-
clearUpdateCheck:assign((context:UpdateCheckContext)=>({
153+
clearUpdateCheck:assign((context)=>({
73154
...context,
74155
updateCheck:undefined,
75156
})),
76-
assignGetUpdateCheckError:assign({
77-
getUpdateCheckError:(_,event)=>event.data,
157+
assignError:assign({
158+
error:(_,event)=>event.data,
78159
}),
79-
clearGetUpdateCheckError:assign((context:UpdateCheckContext)=>({
160+
clearError:assign((context)=>({
80161
...context,
81-
getUpdateCheckError:undefined,
162+
error:undefined,
82163
})),
83164
},
165+
guards:{
166+
canViewUpdateCheck:(context)=>
167+
context.permissions?.[checks.viewUpdateCheck]||false,
168+
canNotViewUpdateCheck:(context)=>
169+
!context.permissions?.[checks.viewUpdateCheck],
170+
},
84171
},
85172
)

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp