|
| 1 | +importAvatarfrom"@material-ui/core/Avatar" |
| 2 | +importButtonfrom"@material-ui/core/Button" |
| 3 | +importLinkfrom"@material-ui/core/Link" |
| 4 | +import{makeStyles}from"@material-ui/core/styles" |
| 5 | +importAddCircleOutlinefrom"@material-ui/icons/AddCircleOutline" |
| 6 | +importSettingsOutlinedfrom"@material-ui/icons/SettingsOutlined" |
| 7 | +import{useMachine,useSelector}from"@xstate/react" |
| 8 | +import{DeleteDialog}from"components/Dialogs/DeleteDialog/DeleteDialog" |
| 9 | +import{DeleteButton}from"components/DropdownButton/ActionCtas" |
| 10 | +import{DropdownButton}from"components/DropdownButton/DropdownButton" |
| 11 | +import{Loader}from"components/Loader/Loader" |
| 12 | +import{PageHeader,PageHeaderSubtitle,PageHeaderTitle}from"components/PageHeader/PageHeader" |
| 13 | +import{useOrganizationId}from"hooks/useOrganizationId" |
| 14 | +import{FC,useContext}from"react" |
| 15 | +import{useTranslation}from"react-i18next" |
| 16 | +import{LinkasRouterLink,Navigate,NavLink,Outlet,useParams}from"react-router-dom" |
| 17 | +import{combineClasses}from"util/combineClasses" |
| 18 | +import{firstLetter}from"util/firstLetter" |
| 19 | +import{selectPermissions}from"xServices/auth/authSelectors" |
| 20 | +import{XServiceContext}from"xServices/StateContext" |
| 21 | +import{templateMachine}from"xServices/template/templateXService" |
| 22 | +import{Margins}from"../../components/Margins/Margins" |
| 23 | +import{Stack}from"../../components/Stack/Stack" |
| 24 | + |
| 25 | +constuseTemplateName=()=>{ |
| 26 | +const{ template}=useParams() |
| 27 | + |
| 28 | +if(!template){ |
| 29 | +thrownewError("No template found in the URL") |
| 30 | +} |
| 31 | + |
| 32 | +returntemplate |
| 33 | +} |
| 34 | + |
| 35 | +constLanguage={ |
| 36 | +settingsButton:"Settings", |
| 37 | +createButton:"Create workspace", |
| 38 | +noDescription:"", |
| 39 | +} |
| 40 | + |
| 41 | +exportconstTemplateLayout:FC=()=>{ |
| 42 | +conststyles=useStyles() |
| 43 | +constorganizationId=useOrganizationId() |
| 44 | +consttemplateName=useTemplateName() |
| 45 | +const{ t}=useTranslation("templatePage") |
| 46 | +const[templateState,templateSend]=useMachine(templateMachine,{ |
| 47 | +context:{ |
| 48 | + templateName, |
| 49 | + organizationId, |
| 50 | +}, |
| 51 | +}) |
| 52 | +const{ template, activeTemplateVersion, templateResources, templateDAUs}=templateState.context |
| 53 | +constxServices=useContext(XServiceContext) |
| 54 | +constpermissions=useSelector(xServices.authXService,selectPermissions) |
| 55 | +constisLoading= |
| 56 | +!template||!activeTemplateVersion||!templateResources||!permissions||!templateDAUs |
| 57 | + |
| 58 | +if(isLoading){ |
| 59 | +return<Loader/> |
| 60 | +} |
| 61 | + |
| 62 | +if(templateState.matches("deleted")){ |
| 63 | +return<Navigateto="/templates"/> |
| 64 | +} |
| 65 | + |
| 66 | +consthasIcon=template.icon&&template.icon!=="" |
| 67 | + |
| 68 | +constcreateWorkspaceButton=(className?:string)=>( |
| 69 | +<Linkunderline="none"component={RouterLink}to={`/templates/${template.name}/workspace`}> |
| 70 | +<ButtonclassName={className??""}startIcon={<AddCircleOutline/>}> |
| 71 | +{Language.createButton} |
| 72 | +</Button> |
| 73 | +</Link> |
| 74 | +) |
| 75 | + |
| 76 | +consthandleDeleteTemplate=()=>{ |
| 77 | +templateSend("DELETE") |
| 78 | +} |
| 79 | + |
| 80 | +return( |
| 81 | +<> |
| 82 | +<Margins> |
| 83 | +<PageHeader |
| 84 | +actions={ |
| 85 | +<> |
| 86 | +<Link |
| 87 | +underline="none" |
| 88 | +component={RouterLink} |
| 89 | +to={`/templates/${template.name}/settings`} |
| 90 | +> |
| 91 | +<Buttonvariant="outlined"startIcon={<SettingsOutlined/>}> |
| 92 | +{Language.settingsButton} |
| 93 | +</Button> |
| 94 | +</Link> |
| 95 | + |
| 96 | +{permissions.deleteTemplates ?( |
| 97 | +<DropdownButton |
| 98 | +primaryAction={createWorkspaceButton(styles.actionButton)} |
| 99 | +secondaryActions={[ |
| 100 | +{ |
| 101 | +action:"delete", |
| 102 | +button:<DeleteButtonhandleAction={handleDeleteTemplate}/>, |
| 103 | +}, |
| 104 | +]} |
| 105 | +canCancel={false} |
| 106 | +/> |
| 107 | +) :( |
| 108 | +createWorkspaceButton() |
| 109 | +)} |
| 110 | +</> |
| 111 | +} |
| 112 | +> |
| 113 | +<Stackdirection="row"spacing={3}className={styles.pageTitle}> |
| 114 | +<div> |
| 115 | +{hasIcon ?( |
| 116 | +<divclassName={styles.iconWrapper}> |
| 117 | +<imgsrc={template.icon}alt=""/> |
| 118 | +</div> |
| 119 | +) :( |
| 120 | +<AvatarclassName={styles.avatar}>{firstLetter(template.name)}</Avatar> |
| 121 | +)} |
| 122 | +</div> |
| 123 | +<div> |
| 124 | +<PageHeaderTitle>{template.name}</PageHeaderTitle> |
| 125 | +<PageHeaderSubtitlecondensed> |
| 126 | +{template.description==="" ?Language.noDescription :template.description} |
| 127 | +</PageHeaderSubtitle> |
| 128 | +</div> |
| 129 | +</Stack> |
| 130 | +</PageHeader> |
| 131 | +</Margins> |
| 132 | + |
| 133 | +<divclassName={styles.tabs}> |
| 134 | +<Margins> |
| 135 | +<Stackdirection="row"spacing={0.25}> |
| 136 | +<NavLink |
| 137 | +end |
| 138 | +to={`/templates/${template.name}`} |
| 139 | +className={({ isActive})=> |
| 140 | +combineClasses([styles.tabItem,isActive ?styles.tabItemActive :undefined]) |
| 141 | +} |
| 142 | +> |
| 143 | + Summary |
| 144 | +</NavLink> |
| 145 | +<NavLink |
| 146 | +to={`/templates/${template.name}/collaborators`} |
| 147 | +className={({ isActive})=> |
| 148 | +combineClasses([styles.tabItem,isActive ?styles.tabItemActive :undefined]) |
| 149 | +} |
| 150 | +> |
| 151 | + Collaborators |
| 152 | +</NavLink> |
| 153 | +</Stack> |
| 154 | +</Margins> |
| 155 | +</div> |
| 156 | + |
| 157 | +<Margins> |
| 158 | +<Outletcontext={{templateContext:templateState.context, permissions}}/> |
| 159 | +</Margins> |
| 160 | + |
| 161 | +<DeleteDialog |
| 162 | +isOpen={templateState.matches("confirmingDelete")} |
| 163 | +confirmLoading={templateState.matches("deleting")} |
| 164 | +title={t("deleteDialog.title")} |
| 165 | +description={t("deleteDialog.description")} |
| 166 | +onConfirm={()=>{ |
| 167 | +templateSend("CONFIRM_DELETE") |
| 168 | +}} |
| 169 | +onCancel={()=>{ |
| 170 | +templateSend("CANCEL_DELETE") |
| 171 | +}} |
| 172 | +/> |
| 173 | +</> |
| 174 | +) |
| 175 | +} |
| 176 | + |
| 177 | +exportconstuseStyles=makeStyles((theme)=>{ |
| 178 | +return{ |
| 179 | +actionButton:{ |
| 180 | +border:"none", |
| 181 | +borderRadius:`${theme.shape.borderRadius}px 0px 0px${theme.shape.borderRadius}px`, |
| 182 | +}, |
| 183 | +pageTitle:{ |
| 184 | +alignItems:"center", |
| 185 | +}, |
| 186 | +avatar:{ |
| 187 | +width:theme.spacing(6), |
| 188 | +height:theme.spacing(6), |
| 189 | +fontSize:theme.spacing(3), |
| 190 | +}, |
| 191 | +iconWrapper:{ |
| 192 | +width:theme.spacing(6), |
| 193 | +height:theme.spacing(6), |
| 194 | +"& img":{ |
| 195 | +width:"100%", |
| 196 | +}, |
| 197 | +}, |
| 198 | + |
| 199 | +tabs:{ |
| 200 | +borderBottom:`1px solid${theme.palette.divider}`, |
| 201 | +marginBottom:theme.spacing(5), |
| 202 | +}, |
| 203 | + |
| 204 | +tabItem:{ |
| 205 | +textDecoration:"none", |
| 206 | +color:theme.palette.text.secondary, |
| 207 | +fontSize:14, |
| 208 | +display:"block", |
| 209 | +padding:theme.spacing(0,2,2), |
| 210 | + |
| 211 | +"&:hover":{ |
| 212 | +color:theme.palette.text.primary, |
| 213 | +}, |
| 214 | +}, |
| 215 | + |
| 216 | +tabItemActive:{ |
| 217 | +color:theme.palette.text.primary, |
| 218 | +position:"relative", |
| 219 | + |
| 220 | +"&:before":{ |
| 221 | +content:`""`, |
| 222 | +left:0, |
| 223 | +bottom:0, |
| 224 | +height:2, |
| 225 | +width:"100%", |
| 226 | +background:theme.palette.secondary.dark, |
| 227 | +position:"absolute", |
| 228 | +}, |
| 229 | +}, |
| 230 | +} |
| 231 | +}) |