diff --git a/Changelog.md b/Changelog.md index e7623cf4357a857700a9a800a1541a7ecbf58a71..1fcd23f18db925799a15aea64bc8f4e0a9a43d75 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2,6 +2,10 @@ All notable changes to this project will be documented in this file. +## [0.32] - 2023-08-27 +- Send an email to the user on first login +- Change NREN to (N)REN on the landing page + ## [0.31] - 2023-08-24 - Fixed applying CSS class to all questions - Increased width of the service name input fields in the services section diff --git a/compendium_v2/auth/session_management.py b/compendium_v2/auth/session_management.py index 4c713edee2e8ad21e6222c7a9226e117b0296519..a244f0a1ad9b587368a372ea82526fed8a8fc213 100644 --- a/compendium_v2/auth/session_management.py +++ b/compendium_v2/auth/session_management.py @@ -5,7 +5,7 @@ from datetime import datetime from flask_login import LoginManager, current_user # type: ignore from compendium_v2.db import session_scope from compendium_v2.db.auth_model import User, ROLES -from compendium_v2.email import send_mail +from compendium_v2.email import send_admin_signup_notification, send_user_signup_notification def admin_required(func): @@ -33,20 +33,22 @@ def admin_required(func): return wraps(func)(wrapper) -def create_user(email: str, fullname: str, oidc_sub: str): +def create_user(email: str, fullname: str, oidc_sub: str, given_name: str): """ Function used to create a new user in the database. :param email: The email of the user :param fullname: The full name of the user :param oidc_sub: The OIDC subject identifier (ID) of the user + :param given_name: The given name of the user :return: The user object """ with session_scope() as session: user = User(email=email, fullname=fullname, oidc_sub=oidc_sub) session.add(user) - send_mail(f'{fullname} has just signed up with the email {email} and provider ID {oidc_sub}') + send_admin_signup_notification(user) + send_user_signup_notification(user, given_name) return user diff --git a/compendium_v2/email/__init__.py b/compendium_v2/email/__init__.py index 85008856d3ed82198cc90d888846ec746295bf89..be3349efdb0a72d165cc5caa7a8615bfd0bd6ac5 100644 --- a/compendium_v2/email/__init__.py +++ b/compendium_v2/email/__init__.py @@ -10,6 +10,18 @@ from compendium_v2.db.auth_model import User, ROLES logger = logging.getLogger(__name__) +USER_NOTIFICATION_TEMPLATE = """Hello{name}, + +Thank you for registering for the new GÉANT Compendium Survey site. + +The Compendium team have been notified and will assign you to your NREN shortly. If you are a long-time contributor this should be fairly quick (same working day). For new users, we will have to check with your colleagues first to make sure you are authorised to answer on behalf of your NREN. + +Best regards, + +Daniel and Jennifer (the Compendium admins) +""" # noqa: E501 + + def _send_mail(smtp_server, port, sender_email, recipients, message): try: @@ -22,7 +34,7 @@ def _send_mail(smtp_server, port, sender_email, recipients, message): def send_mail( contents: str, - subject: str = 'New user signed up for Compendium', + subject: str, recipients: Union[str, Sequence[str]] = '' ): if not current_app.config['MAIL_ENABLE']: @@ -52,3 +64,20 @@ def send_mail( logger.debug('Sending email') thread = threading.Thread(target=_send_mail, args=(smtp_server, port, sender_email, recipients, message)) thread.start() + + +def send_admin_signup_notification(user: User): + fullname = user.fullname + email = user.email + oidc_sub = user.oidc_sub + + contents = f"""{fullname} has just signed up with the email {email} and provider ID {oidc_sub}""" + send_mail(contents=contents, subject='New user signed up for Compendium') + + +def send_user_signup_notification(user: User, given_name: str): + email = user.email + name = f' {given_name}' if given_name else '' + + contents = USER_NOTIFICATION_TEMPLATE.format(name=name) + send_mail(contents=contents, subject='You have signed up for the Compendium Survey', recipients=email) diff --git a/compendium_v2/routes/authentication.py b/compendium_v2/routes/authentication.py index aec7d330a40ba5837ce3b168e6177af965bb1d5b..f16360657ac50139f01b56d7ca821b9d3cce061a 100644 --- a/compendium_v2/routes/authentication.py +++ b/compendium_v2/routes/authentication.py @@ -36,7 +36,7 @@ def authorize(): user = fetch_user(profile) if user is None: # create a new user - user = create_user(profile['email'], profile['name'], profile['sub']) + user = create_user(profile['email'], profile['name'], profile['sub'], profile['given_name']) login_user(user) # redirect to / diff --git a/compendium_v2/static/survey-bundle.js b/compendium_v2/static/survey-bundle.js index ed7896612210abe135249404932e0ab380ed76b0..94203e8702446653febdfe6aa8076b545c1afd0a 100644 --- a/compendium_v2/static/survey-bundle.js +++ b/compendium_v2/static/survey-bundle.js @@ -169,4 +169,4 @@ to { > * { pointer-events: auto; } -`,Ur=({reverseOrder:e,position:n="top-center",toastOptions:r,gutter:o,children:i,containerStyle:s,containerClassName:a})=>{let{toasts:l,handlers:u}=(e=>{let{toasts:n,pausedAt:r}=((e={})=>{let[n,r]=(0,t.useState)(yr);(0,t.useEffect)((()=>(mr.push(r),()=>{let e=mr.indexOf(r);e>-1&&mr.splice(e,1)})),[n]);let o=n.toasts.map((t=>{var n,r;return{...e,...e[t.type],...t,duration:t.duration||(null==(n=e[t.type])?void 0:n.duration)||(null==e?void 0:e.duration)||br[t.type],style:{...e.style,...null==(r=e[t.type])?void 0:r.style,...t.style}}}));return{...n,toasts:o}})(e);(0,t.useEffect)((()=>{if(r)return;let e=Date.now(),t=n.map((t=>{if(t.duration===1/0)return;let n=(t.duration||0)+t.pauseDuration-(e-t.createdAt);if(!(n<0))return setTimeout((()=>wr.dismiss(t.id)),n);t.visible&&wr.dismiss(t.id)}));return()=>{t.forEach((e=>e&&clearTimeout(e)))}}),[n,r]);let o=(0,t.useCallback)((()=>{r&&vr({type:6,time:Date.now()})}),[r]),i=(0,t.useCallback)(((e,t)=>{let{reverseOrder:r=!1,gutter:o=8,defaultPosition:i}=t||{},s=n.filter((t=>(t.position||i)===(e.position||i)&&t.height)),a=s.findIndex((t=>t.id===e.id)),l=s.filter(((e,t)=>t<a&&e.visible)).length;return s.filter((e=>e.visible)).slice(...r?[l+1]:[0,l]).reduce(((e,t)=>e+(t.height||0)+o),0)}),[n]);return{toasts:n,handlers:{updateHeight:xr,startPause:Pr,endPause:o,calculateOffset:i}}})(r);return t.createElement("div",{style:{position:"fixed",zIndex:9999,top:16,left:16,right:16,bottom:16,pointerEvents:"none",...s},className:a,onMouseEnter:u.startPause,onMouseLeave:u.endPause},l.map((r=>{let s=r.position||n,a=((e,t)=>{let n=e.includes("top"),r=n?{top:0}:{bottom:0},o=e.includes("center")?{justifyContent:"center"}:e.includes("right")?{justifyContent:"flex-end"}:{};return{left:0,right:0,display:"flex",position:"absolute",transition:dr()?void 0:"all 230ms cubic-bezier(.21,1.02,.73,1)",transform:`translateY(${t*(n?1:-1)}px)`,...r,...o}})(s,u.calculateOffset(r,{reverseOrder:e,gutter:o,defaultPosition:n}));return t.createElement(zr,{id:r.id,key:r.id,onHeightUpdate:u.updateHeight,className:r.visible?Hr:"",style:a},"custom"===r.type?cr(r.message,r):i?i(r):t.createElement(Qr,{toast:r,position:s}))})))},Wr=wr,Jr=n(535),$r=n(352);function Gr(e,t){if(0==t.column.indexValue&&"item"in t.row){var n,r,o=t.row.item;void 0!==o.customDescription&&(null===(n=t.htmlElement.parentElement)||void 0===n||n.children[0].children[0].setAttribute("description",o.customDescription),null===(r=t.htmlElement.parentElement)||void 0===r||r.children[0].children[0].classList.add("survey-tooltip"))}}function Kr(e){var t=e[0];if(void 0===t||null==t||""==t)return!0;try{var n=new URL(t);return"http:"===n.protocol||"https:"===n.protocol}catch(e){return!1}}function Zr(e,t){t.question.hideCheckboxLabels&&(t.cssClasses.root+=" hidden-checkbox-labels")}function Yr(e,t){var n,r='[data-name="'+t.question.name+'"]',o=null===(n=document.querySelector(r))||void 0===n?void 0:n.querySelector("h5");o&&!o.classList.contains("sv-header-flex")&&t.question.updateElementCss()}function Xr(e,t,n){var r;n.verificationStatus.set(e.name,t);var o=document.createElement("button");o.type="button",o.className="sv-action-bar-item verification",o.innerHTML=t,t==En.Unverified?(o.innerHTML="No change from previous year",o.className+=" verification-required",o.onclick=function(){"display"!=n.mode&&(e.validate(),Xr(e,En.Verified,n))}):(o.innerHTML="Answer updated",o.className+=" verification-ok");var i='[data-name="'+e.name+'"]',s=null===(r=document.querySelector(i))||void 0===r?void 0:r.querySelector("h5"),a=null==s?void 0:s.querySelector(".verification");a?a.replaceWith(o):null==s||s.appendChild(o)}const eo=function(e){var n=e.surveyModel,r=(0,t.useCallback)((function(e,t){var r=n.verificationStatus.get(t.question.name);r&&Xr(t.question,r,n)}),[n]),o=(0,t.useCallback)((function(e,t){n.verificationStatus.get(t.question.name)==En.Unverified&&Xr(t.question,En.Edited,n)}),[n]);return Jr.FunctionFactory.Instance.hasFunction("validateWebsiteUrl")||Jr.FunctionFactory.Instance.register("validateWebsiteUrl",Kr),n.css.question.title.includes("sv-header-flex")||(n.css.question.title="sv-title sv-question__title sv-header-flex",n.css.question.titleOnError="sv-question__title--error sv-error-color-fix"),n.onAfterRenderQuestion.hasFunc(r)||(n.onAfterRenderQuestion.add(r),n.onAfterRenderQuestion.add(Yr)),n.onValueChanged.hasFunc(o)||n.onValueChanged.add(o),n.onUpdateQuestionCssClasses.hasFunc(Zr)||n.onUpdateQuestionCssClasses.add(Zr),n.onMatrixAfterCellRender.hasFunc(Gr)||n.onMatrixAfterCellRender.add(Gr),t.createElement($r.Survey,{model:n})},to=t.forwardRef(((e,t)=>{const[{className:n,...r},{as:o="div",bsPrefix:i,spans:s}]=function({as:e,bsPrefix:t,className:n,...r}){t=wt(t,"col");const o=xt(),i=Pt(),s=[],a=[];return o.forEach((e=>{const n=r[e];let o,l,u;delete r[e],"object"==typeof n&&null!=n?({span:o,offset:l,order:u}=n):o=n;const c=e!==i?`-${e}`:"";o&&s.push(!0===o?`${t}${c}`:`${t}${c}-${o}`),null!=u&&a.push(`order${c}-${u}`),null!=l&&a.push(`offset${c}-${l}`)})),[{...r,className:dt()(n,...s,...a)},{as:e,bsPrefix:t,spans:s}]}(e);return(0,yt.jsx)(o,{...r,ref:t,className:dt()(n,!s.length&&i)})}));to.displayName="Col";const no=to;function ro(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function oo(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?ro(Object(n),!0).forEach((function(t){jn(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):ro(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}const io=function(e){var n=e.surveyModel,r=e.pageNoSetter,o=st((0,t.useState)([]),2),i=o[0],s=o[1],a=function(e){return!(null===e.value||void 0===e.value||""===e.value||"checkbox"===e.getType()&&0==e.value.length||"multipletext"===e.getType()&&(1===Object.keys(e.value).length&&void 0===Object.values(e.value)[0]||0===Object.keys(e.value).length))};(0,t.useEffect)((function(){var e=function(e){if(e&&e.pages){var t=[];e.pages.forEach((function(n){var r=n.questions.filter((function(e){return e.startWithNewLine})),o=r.length,i=r.filter(a).length,s=o-i,l=i/o;t.push({completionPercentage:100*l,unansweredPercentage:s/o*100,totalPages:e.pages.length,pageTitle:n.title})})),s(t)}};n.onValueChanged.add((function(t){e(t)})),e(n)}),[n]);var l={height:"0.5rem",transition:"width 0.3s ease"};return t.createElement(Mn,{className:"survey-progress"},t.createElement(qn,null,i.map((function(e,o){return t.createElement(no,{xs:12,md:!0,key:o,onClick:function(){return r(o)},style:{cursor:"pointer",margin:"0.5rem"}},t.createElement("div",null,t.createElement("span",{style:{whiteSpace:"nowrap",fontSize:"1.5rem",marginRight:"0.25rem",fontWeight:"bold",color:"#2db394"}},o+1),t.createElement("span",{style:oo({whiteSpace:"nowrap"},n.currentPageNo==o&&{fontWeight:"bold"})},e.pageTitle),t.createElement("div",{style:{display:"flex",flexWrap:"wrap"}},t.createElement("div",{style:oo(oo({},l),{},{width:"".concat(e.completionPercentage,"%"),backgroundColor:"#262261"})}),t.createElement("div",{style:oo(oo({},l),{},{width:"".concat(e.unansweredPercentage,"%"),backgroundColor:"#cdcdcd"})}))))}))))},so=function(e){var n=e.surveyModel,r=e.surveyActions,o=e.year,i=e.nren,s=e.children,a=st((0,t.useState)(0),2),l=a[0],u=a[1],c=st((0,t.useState)(!1),2),p=c[0],d=c[1],h=st((0,t.useState)(""),2),f=h[0],g=h[1],m=st((0,t.useState)(""),2),y=m[0],v=m[1],b=(0,t.useContext)(Bn).user,C=(0,t.useCallback)((function(){d("edit"==n.mode),g(n.lockedBy),u(n.currentPageNo),v(n.status)}),[n]);(0,t.useEffect)((function(){C()}),[C]);var w=function(e){u(e),n.currentPageNo=e},x=function(){w(n.currentPageNo+1)},P=function(){var e=lt(ct().mark((function e(t){return ct().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return e.next=2,r[t]();case 2:C();case 3:case"end":return e.stop()}}),e)})));return function(t){return e.apply(this,arguments)}}(),S=function(e,t){return V(e,(function(){return P(t)}))},V=function(e,n){return t.createElement("button",{className:"sv-btn sv-btn--navigation",onClick:n},e)},E="Save and stop editing",O="Save progress",T="Start editing",_="Complete Survey",R=function(){return t.createElement("div",{className:"survey-edit-buttons-block"},!p&&!f&&n.editAllowed&&S(T,"startEdit"),!p&&f&&f==b.name&&S("Discard any unsaved changes and release your lock","releaseLock"),p&&y==On.started&&S(O,"save"),p&&y==On.started&&S(E,"saveAndStopEdit"),p&&l===n.visiblePages.length-1&&S(_,"complete"),l!==n.visiblePages.length-1&&V("Next Section",x))},I=parseInt(o);return t.createElement(Mn,null,t.createElement(qn,{className:"survey-content"},t.createElement("h2",null,t.createElement("span",{className:"survey-title"},o," Compendium Survey "),t.createElement("span",{className:"survey-title-nren"}," ",i," "),t.createElement("span",null," - ",y)),t.createElement("p",{style:{marginTop:"1rem"}},"To get started, click “",T,"” to end read-only mode. This is only possible when nobody else from your NREN is currently working on the survey.",t.createElement("br",null),"Where available, the survey questions are pre-filled with answers from the previous year. The survey asks about the past year, i.e. the ",o," survey asks about data from ",I-1," (or ",I-1,"/",o," if your NRENs financial year does not match the calendar year). You can edit the prefilled answer to provide new information, or press the “no change from previous year” button.",t.createElement("br",null),"Press the “",O,"“ or “",E,"“ button to save all answers in the survey. When you reach the last section of the survey (Services), you will find a “",_,"“ button which saves all answers in the survey and lets the Compendium team know that your answers are ready to be published.",t.createElement("br",null),"As long as the survey remains open, any Compendium administrator from your NREN can add answers or amend existing ones, even after using the “",_,"“ button. Different people from your NREN can contribute to the survey if needed.",t.createElement("br",null),"Some fields require specific data, such as numerical data, valid http-addresses, and in some questions, the answer has to add up to 100%. If an answer does not fulfil the set criteria, the question will turn pink and an error message will appear. Fields can be left blank if you prefer not to answer a question.",t.createElement("br",null),"If you notice any errors after the survey was closed, please contact us for correcting those."),t.createElement("p",null,"Thank you for taking the time to fill in the ",o," Compendium Survey. Any questions or requests can be sent to ",t.createElement("a",{href:"mailto:Partner-Relations@geant.org"},t.createElement("span",null,"Partner-Relations@geant.org"))),p&&t.createElement(t.Fragment,null,t.createElement("br",null),t.createElement("b",null,"Remember to click “",E,"” before leaving the page."))),t.createElement(qn,null,R()),t.createElement(qn,{className:"survey-content"},!p&&t.createElement("div",{className:"survey-edit-explainer"},!f&&n.editAllowed&&"The survey is in read-only mode; click the “Start editing“ button to begin editing the answers.",!f&&!n.editAllowed&&"The survey is in read-only mode and can not be edited by you.",f&&f!=b.name&&"The survey is in read-only mode and currently being edited by: "+f+". To start editing the survey, ask them to complete their edits.",f&&f==b.name&&'The survey is in read-only mode because you started editing in another tab, browser or device. To start editing the survey, either complete those edits or click the "Discard any unsaved changes" button.')),t.createElement(qn,null,t.createElement(io,{surveyModel:n,pageNoSetter:w}),s),t.createElement(qn,null,R()))},ao=function(e){var n=e.when,r=e.onPageExit;return function(e){let{router:n}=Qe(Be.UseBlocker),r=ze(Fe.UseBlocker),[o]=t.useState((()=>String(++Ue))),i=t.useCallback((t=>!!e()),[e]);n.getBlocker(o,i);t.useEffect((()=>()=>n.deleteBlocker(o)),[n,o]),r.blockers.get(o)}((function(){if(n()){var t=window.confirm(e.message);return t&&r(),!t}return!1})),t.createElement("div",null)};Jr.Serializer.addProperty("itemvalue","customDescription:text"),Jr.Serializer.addProperty("question","hideCheckboxLabels:boolean");const lo=function(e){var n=e.loadFrom,r=st((0,t.useState)(),2),o=r[0],i=r[1],s=function(){let{matches:e}=t.useContext(Te),n=e[e.length-1];return n?n.params:{}}(),a=s.year,l=s.nren,u=st((0,t.useState)("loading survey..."),2),c=u[0],p=u[1],d=(0,t.useCallback)((function(e){return e.preventDefault(),e.returnValue=""}),[]),h=(0,t.useCallback)((function(){window.navigator.sendBeacon("/api/response/unlock/"+a+"/"+l)}),[]),f=(0,t.useCallback)((function(){window.navigator.sendBeacon("/api/response/unlock/"+a+"/"+l),removeEventListener("beforeunload",d,{capture:!0}),removeEventListener("pagehide",h)}),[]);if((0,t.useEffect)((function(){function e(){return(e=lt(ct().mark((function e(){var t,r,o,s;return ct().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return e.next=2,fetch(n+a+(l?"/"+l:""));case 2:return t=e.sent,e.next=5,t.json();case 5:if(r=e.sent,t.ok){e.next=12;break}if(!("message"in r)){e.next=11;break}throw new Error(r.message);case 11:throw new Error("Request failed with status ".concat(t.status));case 12:for(s in(o=new Jr.Model(r.model)).setVariable("surveyyear",a),o.setVariable("previousyear",parseInt(a)-1),o.showNavigationButtons=!1,o.requiredText="",o.verificationStatus=new Map,r.verification_status)o.verificationStatus.set(s,r.verification_status[s]);o.data=r.data,o.clearIncorrectValues(!0),o.currentPageNo=r.page,o.mode=r.mode,o.lockedBy=r.locked_by,o.status=r.status,o.editAllowed=r.edit_allowed,i(o);case 27:case"end":return e.stop()}}),e)})))).apply(this,arguments)}(function(){return e.apply(this,arguments)})().catch((function(e){return p("Error when loading survey: "+e.message)}))}),[]),!o)return c;var g,m,y,v,b,C=function(){var e=lt(ct().mark((function e(t,n){var r,i,s;return ct().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:if(l){e.next=2;break}return e.abrupt("return","Saving not available in inpect/try mode");case 2:return r={lock_uuid:t.lockUUID,new_state:n,data:t.data,page:t.currentPageNo,verification_status:Object.fromEntries(t.verificationStatus)},e.prev=3,e.next=6,fetch("/api/response/save/"+a+"/"+l,{method:"POST",headers:{"Content-Type":"application/json; charset=utf-8"},body:JSON.stringify(r)});case 6:return i=e.sent,e.next=9,i.json();case 9:if(s=e.sent,i.ok){e.next=12;break}return e.abrupt("return",s.message);case 12:o.mode=s.mode,o.lockedBy=s.locked_by,o.status=s.status,e.next=20;break;case 17:return e.prev=17,e.t0=e.catch(3),e.abrupt("return","Unknown Error: "+e.t0.message);case 20:case"end":return e.stop()}}),e,null,[[3,17]])})));return function(t,n){return e.apply(this,arguments)}}(),w=function(e){var t="",n=function(e,n){e.verificationStatus.get(n.name)==En.Unverified&&(""==t&&(t=n.name),n.error='Please verify that last years data is correct by editing the answer or pressing the "No change from previous year" button!')};o.onValidateQuestion.add(n);var r=e();return o.onValidateQuestion.remove(n),r||Wr("Validation failed!"),r},x={save:(b=lt(ct().mark((function e(){var t;return ct().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return e.next=2,C(o,"editing");case 2:t=e.sent,Wr(t?"Failed saving survey: "+t:"Survey saved!");case 4:case"end":return e.stop()}}),e)}))),function(){return b.apply(this,arguments)}),complete:(v=lt(ct().mark((function e(){var t;return ct().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:if(!w(o.validate.bind(o,!0,!0))){e.next=6;break}return e.next=4,C(o,"completed");case 4:(t=e.sent)?Wr("Failed completing survey: "+t):(Wr("Survey completed!"),removeEventListener("beforeunload",d,{capture:!0}),removeEventListener("pagehide",h));case 6:case"end":return e.stop()}}),e)}))),function(){return v.apply(this,arguments)}),saveAndStopEdit:(y=lt(ct().mark((function e(){var t;return ct().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return e.next=2,C(o,"readonly");case 2:(t=e.sent)?Wr("Failed saving survey: "+t):(Wr("Survey saved!"),removeEventListener("beforeunload",d,{capture:!0}),removeEventListener("pagehide",h));case 4:case"end":return e.stop()}}),e)}))),function(){return y.apply(this,arguments)}),startEdit:(m=lt(ct().mark((function e(){var t,n,r;return ct().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return e.next=2,fetch("/api/response/lock/"+a+"/"+l,{method:"POST"});case 2:return t=e.sent,e.next=5,t.json();case 5:if(n=e.sent,t.ok){e.next=9;break}return Wr("Failed starting edit: "+n.message),e.abrupt("return");case 9:for(r in addEventListener("pagehide",h),addEventListener("beforeunload",d,{capture:!0}),n.verification_status)o.verificationStatus.set(r,n.verification_status[r]);o.data=n.data,o.clearIncorrectValues(!0),o.mode=n.mode,o.lockedBy=n.locked_by,o.lockUUID=n.lock_uuid,o.status=n.status;case 18:case"end":return e.stop()}}),e)}))),function(){return m.apply(this,arguments)}),releaseLock:(g=lt(ct().mark((function e(){var t,n;return ct().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return e.next=2,fetch("/api/response/unlock/"+a+"/"+l,{method:"POST"});case 2:return t=e.sent,e.next=5,t.json();case 5:if(n=e.sent,t.ok){e.next=9;break}return Wr("Failed releasing lock: "+n.message),e.abrupt("return");case 9:o.mode=n.mode,o.lockedBy=n.locked_by,o.status=n.status;case 12:case"end":return e.stop()}}),e)}))),function(){return g.apply(this,arguments)}),validatePage:function(){w(o.validatePage.bind(o))&&Wr("Page validation successful!")}};return t.createElement(Mn,{className:"survey-container"},t.createElement(Ur,null),t.createElement(ao,{message:"Are you sure you want to leave this page? Information you've entered may not be saved.",when:function(){return"edit"==o.mode&&!!l},onPageExit:f}),t.createElement(so,{surveyModel:o,surveyActions:x,year:a,nren:l},t.createElement(eo,{surveyModel:o})))},uo=n.p+"9ab20ac1d835b50b2e01.svg",co=function(){return t.createElement("div",{className:"external-page-nav-bar"},t.createElement(Mn,null,t.createElement(qn,null,t.createElement(no,{xs:10},t.createElement("div",{className:"nav-wrapper"},t.createElement("nav",{className:"header-nav"},t.createElement("a",{href:"https://geant.org/"},t.createElement("img",{src:uo})),t.createElement("ul",null,t.createElement("li",null,t.createElement("a",{className:"nav-link-entry",href:"https://network.geant.org/"},"NETWORK")),t.createElement("li",null,t.createElement("a",{className:"nav-link-entry",href:"https://geant.org/services/"},"SERVICES")),t.createElement("li",null,t.createElement("a",{className:"nav-link-entry",href:"https://community.geant.org/"},"COMMUNITY")),t.createElement("li",null,t.createElement("a",{className:"nav-link-entry",href:"https://tnc23.geant.org/"},"TNC")),t.createElement("li",null,t.createElement("a",{className:"nav-link-entry",href:"https://geant.org/projects/"},"PROJECTS")),t.createElement("li",null,t.createElement("a",{className:"nav-link-entry",href:"https://connect.geant.org/"},"CONNECT")),t.createElement("li",null,t.createElement("a",{className:"nav-link-entry",href:"https://impact.geant.org/"},"IMPACT")),t.createElement("li",null,t.createElement("a",{className:"nav-link-entry",href:"https://careers.geant.org/"},"CAREERS")),t.createElement("li",null,t.createElement("a",{className:"nav-link-entry",href:"https://about.geant.org/"},"ABOUT")),t.createElement("li",null,t.createElement("a",{className:"nav-link-entry",href:"https://connect.geant.org/community-news"},"NEWS")),t.createElement("li",null,t.createElement("a",{className:"nav-link-entry",href:"https://resources.geant.org/"},"RESOURCES")))))))))},po=function(){var e,n=(0,t.useContext)(Bn).user,r=je(),o=!!n.id,i=!!o&&!!n.nrens.length,s=i?n.nrens[0]:"",a=!!o&&n.permissions.admin;return t.createElement(Mn,{className:"py-5 grey-container"},t.createElement(qn,null,t.createElement("div",{className:"center-text"},t.createElement("h1",{className:"geant-header"},"THE GÉANT COMPENDIUM OF NRENS SURVEY"),t.createElement("div",{className:"wordwrap pt-4",style:{maxWidth:"75rem"}},t.createElement("p",{style:{textAlign:"left"}},"Hello,",t.createElement("br",null),"Welcome to the GÉANT Compendium Survey. NREN Compendium administrators can login via Single Sign On (SSO) ",t.createElement("a",{href:"/login"},"here"),", which will complete their registration to fill in the 2023 Compendium survey. This will send a notification to the Compendium administration team and they will assign you to your NREN.",t.createElement("br",null),"Once this step has been completed, you will receive an email from the administration team. We aim to get back to you the same working day, but sometimes may take a little longer.",t.createElement("br",null),"If you are not sure whether you are a Compendium Administrator for your NREN, please contact your GÉANT Partner Relations relationship manager.",t.createElement("br",null),"Thank you."),t.createElement("span",null,"Current registration status:"),t.createElement("br",null),t.createElement("br",null),a?t.createElement("ul",null,t.createElement("li",null,t.createElement("span",null,"You are logged in as a Compendium Administrator")),t.createElement("li",null,t.createElement("span",null,"Click ",t.createElement(tt,{to:"/survey/admin/surveys"},"here")," to access the survey management page.")),t.createElement("li",null,t.createElement("span",null,"Click ",t.createElement(tt,{to:"/survey/admin/users"},"here")," to access the user management page."))):t.createElement("ul",null,!a&&i&&(e=(new Date).getFullYear(),r("/survey/response/".concat(e,"/").concat(s)),t.createElement(t.Fragment,null)),o?t.createElement("li",null,t.createElement("span",null,"You are logged in")):t.createElement("li",null,t.createElement("span",null,"You are not logged in")),o&&!i&&t.createElement("li",null,t.createElement("span",null,"Your access to the survey has not yet been approved")),o&&!i&&t.createElement("li",null,t.createElement("span",null,"Once you have been approved, you will immediately be directed to the relevant survey upon visiting this page")))))))};var ho,fo=(ho=[{path:"survey/admin/surveys",element:t.createElement(In,null)},{path:"survey/admin/users",element:t.createElement(Jn,null)},{path:"survey/admin/inspect/:year",element:t.createElement(lo,{loadFrom:"/api/response/inspect/"})},{path:"survey/admin/try/:year",element:t.createElement(lo,{loadFrom:"/api/response/try/"})},{path:"survey/response/:year/:nren",element:t.createElement(lo,{loadFrom:"/api/response/load/"})},{path:"*",element:t.createElement(po,null)}],function(t){let n;if(s(t.routes.length>0,"You must provide a non-empty routes array to createRouter"),t.mapRouteProperties)n=t.mapRouteProperties;else if(t.detectErrorBoundary){let e=t.detectErrorBoundary;n=t=>({hasErrorBoundary:e(t)})}else n=Z;let r,i={},l=f(t.routes,n,void 0,i),c=t.basename||"/",p=o({v7_normalizeFormMethod:!1,v7_prependBasename:!1},t.future),h=null,m=new Set,y=null,v=null,b=null,C=null!=t.hydrationData,w=g(l,t.history.location,c),x=null;if(null==w){let e=pe(404,{pathname:t.history.location.pathname}),{matches:n,route:r}=ce(l);w=n,x={[r.id]:e}}let P,S,V=!(w.some((e=>e.route.lazy))||w.some((e=>e.route.loader))&&null==t.hydrationData),E={historyAction:t.history.action,location:t.history.location,matches:w,initialized:V,navigation:U,restoreScrollPosition:null==t.hydrationData&&null,preventScrollReset:!1,revalidation:"idle",loaderData:t.hydrationData&&t.hydrationData.loaderData||{},actionData:t.hydrationData&&t.hydrationData.actionData||null,errors:t.hydrationData&&t.hydrationData.errors||x,fetchers:new Map,blockers:new Map},O=e.Pop,T=!1,R=!1,I=!1,D=[],j=[],k=new Map,M=0,L=-1,q=new Map,N=new Set,A=new Map,B=new Map,F=new Map,Q=!1;function z(e){E=o({},E,e),m.forEach((e=>e(E)))}function te(n,i){var s,a;let u,c=null!=E.actionData&&null!=E.navigation.formMethod&&ye(E.navigation.formMethod)&&"loading"===E.navigation.state&&!0!==(null==(s=n.state)?void 0:s._isRedirect);u=i.actionData?Object.keys(i.actionData).length>0?i.actionData:null:c?E.actionData:null;let p=i.loaderData?le(E.loaderData,i.loaderData,i.matches||[],i.errors):E.loaderData;for(let[e]of F)_e(e);let d=!0===T||null!=E.navigation.formMethod&&ye(E.navigation.formMethod)&&!0!==(null==(a=n.state)?void 0:a._isRedirect);r&&(l=r,r=void 0),z(o({},i,{actionData:u,loaderData:p,historyAction:O,location:n,initialized:!0,navigation:U,revalidation:"idle",restoreScrollPosition:je(n,i.matches||E.matches),preventScrollReset:d,blockers:new Map(E.blockers)})),R||O===e.Pop||(O===e.Push?t.history.push(n,n.state):O===e.Replace&&t.history.replace(n,n.state)),O=e.Pop,T=!1,R=!1,I=!1,D=[],j=[]}async function ne(s,a,u){S&&S.abort(),S=null,O=s,R=!0===(u&&u.startUninterruptedRevalidation),function(e,t){if(y&&v&&b){let n=t.map((e=>we(e,E.loaderData))),r=v(e,n)||e.key;y[r]=b()}}(E.location,E.matches),T=!0===(u&&u.preventScrollReset);let p=r||l,h=u&&u.overrideNavigation,f=g(p,a,c);if(!f){let e=pe(404,{pathname:a.pathname}),{matches:t,route:n}=ce(p);return De(),void te(a,{matches:t,loaderData:{},errors:{[n.id]:e}})}if(E.initialized&&function(e,t){return e.pathname===t.pathname&&e.search===t.search&&(""===e.hash?""!==t.hash:e.hash===t.hash||""!==t.hash)}(E.location,a)&&!(u&&u.submission&&ye(u.submission.formMethod)))return void te(a,{matches:f});S=new AbortController;let m,C,w=ie(t.history,a,S.signal,u&&u.submission);if(u&&u.pendingError)C={[ue(f).route.id]:u.pendingError};else if(u&&u.submission&&ye(u.submission.formMethod)){let t=await async function(t,r,s,a,l){let u;Ce(),z({navigation:o({state:"submitting",location:r},s)});let p=xe(a,r);if(p.route.action||p.route.lazy){if(u=await oe("action",t,p,a,i,n,c),t.signal.aborted)return{shortCircuited:!0}}else u={type:d.error,error:pe(405,{method:t.method,pathname:r.pathname,routeId:p.route.id})};if(me(u)){let e;return e=l&&null!=l.replace?l.replace:u.location===E.location.pathname+E.location.search,await se(E,u,{submission:s,replace:e}),{shortCircuited:!0}}if(ge(u)){let t=ue(a,p.route.id);return!0!==(l&&l.replace)&&(O=e.Push),{pendingActionData:{},pendingActionError:{[t.route.id]:u.error}}}if(fe(u))throw pe(400,{type:"defer-action"});return{pendingActionData:{[p.route.id]:u.data}}}(w,a,u.submission,f,{replace:u.replace});if(t.shortCircuited)return;m=t.pendingActionData,C=t.pendingActionError,h=o({state:"loading",location:a},u.submission),w=new Request(w.url,{signal:w.signal})}let{shortCircuited:x,loaderData:P,errors:V}=await async function(e,n,i,s,a,u,p,d,h){let f=s;f||(f=o({state:"loading",location:n,formMethod:void 0,formAction:void 0,formEncType:void 0,formData:void 0},a));let g=a||u?a||u:f.formMethod&&f.formAction&&f.formData&&f.formEncType?{formMethod:f.formMethod,formAction:f.formAction,formData:f.formData,formEncType:f.formEncType}:void 0,m=r||l,[y,v]=ee(t.history,E,i,g,n,I,D,j,A,m,c,d,h);if(De((e=>!(i&&i.some((t=>t.route.id===e)))||y&&y.some((t=>t.route.id===e)))),0===y.length&&0===v.length){let e=Oe();return te(n,o({matches:i,loaderData:{},errors:h||null},d?{actionData:d}:{},e?{fetchers:new Map(E.fetchers)}:{})),{shortCircuited:!0}}if(!R){v.forEach((e=>{let t=E.fetchers.get(e.key),n={state:"loading",data:t&&t.data,formMethod:void 0,formAction:void 0,formEncType:void 0,formData:void 0," _hasFetcherDoneAnything ":!0};E.fetchers.set(e.key,n)}));let e=d||E.actionData;z(o({navigation:f},e?0===Object.keys(e).length?{actionData:null}:{actionData:e}:{},v.length>0?{fetchers:new Map(E.fetchers)}:{}))}L=++M,v.forEach((e=>{e.controller&&k.set(e.key,e.controller)}));let b=()=>v.forEach((e=>Ve(e.key)));S&&S.signal.addEventListener("abort",b);let{results:C,loaderResults:w,fetcherResults:x}=await he(E.matches,i,y,v,e);if(e.signal.aborted)return{shortCircuited:!0};S&&S.signal.removeEventListener("abort",b),v.forEach((e=>k.delete(e.key)));let P=de(C);if(P)return await se(E,P,{replace:p}),{shortCircuited:!0};let{loaderData:V,errors:O}=ae(E,i,y,w,h,v,x,B);B.forEach(((e,t)=>{e.subscribe((n=>{(n||e.done)&&B.delete(t)}))}));let T=Oe(),_=Te(L);return o({loaderData:V,errors:O},T||_||v.length>0?{fetchers:new Map(E.fetchers)}:{})}(w,a,f,h,u&&u.submission,u&&u.fetcherSubmission,u&&u.replace,m,C);x||(S=null,te(a,o({matches:f},m?{actionData:m}:{},{loaderData:P,errors:V})))}function re(e){return E.fetchers.get(e)||W}async function se(n,r,i){var a;let{submission:l,replace:p,isFetchActionRedirect:d}=void 0===i?{}:i;r.revalidate&&(I=!0);let h=u(n.location,r.location,o({_isRedirect:!0},d?{_isFetchActionRedirect:!0}:{}));if(s(h,"Expected a location on the redirect navigation"),$.test(r.location)&&G&&void 0!==(null==(a=window)?void 0:a.location)){let e=t.history.createURL(r.location),n=null==_(e.pathname,c);if(window.location.origin!==e.origin||n)return void(p?window.location.replace(r.location):window.location.assign(r.location))}S=null;let f=!0===p?e.Replace:e.Push,{formMethod:g,formAction:m,formEncType:y,formData:v}=n.navigation;!l&&g&&m&&v&&y&&(l={formMethod:g,formAction:m,formEncType:y,formData:v}),H.has(r.status)&&l&&ye(l.formMethod)?await ne(f,h,{submission:o({},l,{formAction:r.location}),preventScrollReset:T}):d?await ne(f,h,{overrideNavigation:{state:"loading",location:h,formMethod:void 0,formAction:void 0,formEncType:void 0,formData:void 0},fetcherSubmission:l,preventScrollReset:T}):await ne(f,h,{overrideNavigation:{state:"loading",location:h,formMethod:l?l.formMethod:void 0,formAction:l?l.formAction:void 0,formEncType:l?l.formEncType:void 0,formData:l?l.formData:void 0},preventScrollReset:T})}async function he(e,r,o,s,a){let l=await Promise.all([...o.map((e=>oe("loader",a,e,r,i,n,c))),...s.map((e=>e.matches&&e.match&&e.controller?oe("loader",ie(t.history,e.path,e.controller.signal),e.match,e.matches,i,n,c):{type:d.error,error:pe(404,{pathname:e.path})}))]),u=l.slice(0,o.length),p=l.slice(o.length);return await Promise.all([ve(e,o,u,u.map((()=>a.signal)),!1,E.loaderData),ve(e,s.map((e=>e.match)),p,s.map((e=>e.controller?e.controller.signal:null)),!0)]),{results:l,loaderResults:u,fetcherResults:p}}function Ce(){I=!0,D.push(...De()),A.forEach(((e,t)=>{k.has(t)&&(j.push(t),Ve(t))}))}function Pe(e,t,n){let r=ue(E.matches,t);Se(e),z({errors:{[r.route.id]:n},fetchers:new Map(E.fetchers)})}function Se(e){k.has(e)&&Ve(e),A.delete(e),q.delete(e),N.delete(e),E.fetchers.delete(e)}function Ve(e){let t=k.get(e);s(t,"Expected fetch controller: "+e),t.abort(),k.delete(e)}function Ee(e){for(let t of e){let e={state:"idle",data:re(t).data,formMethod:void 0,formAction:void 0,formEncType:void 0,formData:void 0," _hasFetcherDoneAnything ":!0};E.fetchers.set(t,e)}}function Oe(){let e=[],t=!1;for(let n of N){let r=E.fetchers.get(n);s(r,"Expected fetcher: "+n),"loading"===r.state&&(N.delete(n),e.push(n),t=!0)}return Ee(e),t}function Te(e){let t=[];for(let[n,r]of q)if(r<e){let e=E.fetchers.get(n);s(e,"Expected fetcher: "+n),"loading"===e.state&&(Ve(n),q.delete(n),t.push(n))}return Ee(t),t.length>0}function _e(e){E.blockers.delete(e),F.delete(e)}function Re(e,t){let n=E.blockers.get(e)||J;s("unblocked"===n.state&&"blocked"===t.state||"blocked"===n.state&&"blocked"===t.state||"blocked"===n.state&&"proceeding"===t.state||"blocked"===n.state&&"unblocked"===t.state||"proceeding"===n.state&&"unblocked"===t.state,"Invalid blocker state transition: "+n.state+" -> "+t.state),E.blockers.set(e,t),z({blockers:new Map(E.blockers)})}function Ie(e){let{currentLocation:t,nextLocation:n,historyAction:r}=e;if(0===F.size)return;F.size>1&&a(!1,"A router only supports one blocker at a time");let o=Array.from(F.entries()),[i,s]=o[o.length-1],l=E.blockers.get(i);return l&&"proceeding"===l.state?void 0:s({currentLocation:t,nextLocation:n,historyAction:r})?i:void 0}function De(e){let t=[];return B.forEach(((n,r)=>{e&&!e(r)||(n.cancel(),t.push(r),B.delete(r))})),t}function je(e,t){if(y&&v&&b){let n=t.map((e=>we(e,E.loaderData))),r=v(e,n)||e.key,o=y[r];if("number"==typeof o)return o}return null}return P={get basename(){return c},get state(){return E},get routes(){return l},initialize:function(){return h=t.history.listen((e=>{let{action:n,location:r,delta:o}=e;if(Q)return void(Q=!1);a(0===F.size||null!=o,"You are trying to use a blocker on a POP navigation to a location that was not created by @remix-run/router. This will fail silently in production. This can happen if you are navigating outside the router via `window.history.pushState`/`window.location.hash` instead of using router navigation APIs. This can also happen if you are using createHashRouter and the user manually changes the URL.");let i=Ie({currentLocation:E.location,nextLocation:r,historyAction:n});return i&&null!=o?(Q=!0,t.history.go(-1*o),void Re(i,{state:"blocked",location:r,proceed(){Re(i,{state:"proceeding",proceed:void 0,reset:void 0,location:r}),t.history.go(o)},reset(){_e(i),z({blockers:new Map(P.state.blockers)})}})):ne(n,r)})),E.initialized||ne(e.Pop,E.location),P},subscribe:function(e){return m.add(e),()=>m.delete(e)},enableScrollRestoration:function(e,t,n){if(y=e,b=t,v=n||(e=>e.key),!C&&E.navigation===U){C=!0;let e=je(E.location,E.matches);null!=e&&z({restoreScrollPosition:e})}return()=>{y=null,b=null,v=null}},navigate:async function n(r,i){if("number"==typeof r)return void t.history.go(r);let s=Y(E.location,E.matches,c,p.v7_prependBasename,r,null==i?void 0:i.fromRouteId,null==i?void 0:i.relative),{path:a,submission:l,error:d}=X(p.v7_normalizeFormMethod,!1,s,i),h=E.location,f=u(E.location,a,i&&i.state);f=o({},f,t.history.encodeLocation(f));let g=i&&null!=i.replace?i.replace:void 0,m=e.Push;!0===g?m=e.Replace:!1===g||null!=l&&ye(l.formMethod)&&l.formAction===E.location.pathname+E.location.search&&(m=e.Replace);let y=i&&"preventScrollReset"in i?!0===i.preventScrollReset:void 0,v=Ie({currentLocation:h,nextLocation:f,historyAction:m});if(!v)return await ne(m,f,{submission:l,pendingError:d,preventScrollReset:y,replace:i&&i.replace});Re(v,{state:"blocked",location:f,proceed(){Re(v,{state:"proceeding",proceed:void 0,reset:void 0,location:f}),n(r,i)},reset(){_e(v),z({blockers:new Map(E.blockers)})}})},fetch:function(e,a,u,d){if(K)throw new Error("router.fetch() was called during the server render, but it shouldn't be. You are likely calling a useFetcher() method in the body of your component. Try moving it to a useEffect or a callback.");k.has(e)&&Ve(e);let h=r||l,f=Y(E.location,E.matches,c,p.v7_prependBasename,u,a,null==d?void 0:d.relative),m=g(h,f,c);if(!m)return void Pe(e,a,pe(404,{pathname:f}));let{path:y,submission:v}=X(p.v7_normalizeFormMethod,!0,f,d),b=xe(m,y);T=!0===(d&&d.preventScrollReset),v&&ye(v.formMethod)?async function(e,a,u,p,d,h){if(Ce(),A.delete(e),!p.route.action&&!p.route.lazy){let t=pe(405,{method:h.formMethod,pathname:u,routeId:a});return void Pe(e,a,t)}let f=E.fetchers.get(e),m=o({state:"submitting"},h,{data:f&&f.data," _hasFetcherDoneAnything ":!0});E.fetchers.set(e,m),z({fetchers:new Map(E.fetchers)});let y=new AbortController,v=ie(t.history,u,y.signal,h);k.set(e,y);let b=await oe("action",v,p,d,i,n,c);if(v.signal.aborted)return void(k.get(e)===y&&k.delete(e));if(me(b)){k.delete(e),N.add(e);let t=o({state:"loading"},h,{data:void 0," _hasFetcherDoneAnything ":!0});return E.fetchers.set(e,t),z({fetchers:new Map(E.fetchers)}),se(E,b,{submission:h,isFetchActionRedirect:!0})}if(ge(b))return void Pe(e,a,b.error);if(fe(b))throw pe(400,{type:"defer-action"});let C=E.navigation.location||E.location,w=ie(t.history,C,y.signal),x=r||l,P="idle"!==E.navigation.state?g(x,E.navigation.location,c):E.matches;s(P,"Didn't find any matches after fetcher action");let V=++M;q.set(e,V);let T=o({state:"loading",data:b.data},h,{" _hasFetcherDoneAnything ":!0});E.fetchers.set(e,T);let[_,R]=ee(t.history,E,P,h,C,I,D,j,A,x,c,{[p.route.id]:b.data},void 0);R.filter((t=>t.key!==e)).forEach((e=>{let t=e.key,n=E.fetchers.get(t),r={state:"loading",data:n&&n.data,formMethod:void 0,formAction:void 0,formEncType:void 0,formData:void 0," _hasFetcherDoneAnything ":!0};E.fetchers.set(t,r),e.controller&&k.set(t,e.controller)})),z({fetchers:new Map(E.fetchers)});let F=()=>R.forEach((e=>Ve(e.key)));y.signal.addEventListener("abort",F);let{results:Q,loaderResults:H,fetcherResults:U}=await he(E.matches,P,_,R,w);if(y.signal.aborted)return;y.signal.removeEventListener("abort",F),q.delete(e),k.delete(e),R.forEach((e=>k.delete(e.key)));let W=de(Q);if(W)return se(E,W);let{loaderData:J,errors:$}=ae(E,E.matches,_,H,void 0,R,U,B),G={state:"idle",data:b.data,formMethod:void 0,formAction:void 0,formEncType:void 0,formData:void 0," _hasFetcherDoneAnything ":!0};E.fetchers.set(e,G);let K=Te(V);"loading"===E.navigation.state&&V>L?(s(O,"Expected pending action"),S&&S.abort(),te(E.navigation.location,{matches:P,loaderData:J,errors:$,fetchers:new Map(E.fetchers)})):(z(o({errors:$,loaderData:le(E.loaderData,J,P,$)},K?{fetchers:new Map(E.fetchers)}:{})),I=!1)}(e,a,y,b,m,v):(A.set(e,{routeId:a,path:y}),async function(e,r,a,l,u,p){let d=E.fetchers.get(e),h=o({state:"loading",formMethod:void 0,formAction:void 0,formEncType:void 0,formData:void 0},p,{data:d&&d.data," _hasFetcherDoneAnything ":!0});E.fetchers.set(e,h),z({fetchers:new Map(E.fetchers)});let f=new AbortController,g=ie(t.history,a,f.signal);k.set(e,f);let m=await oe("loader",g,l,u,i,n,c);if(fe(m)&&(m=await be(m,g.signal,!0)||m),k.get(e)===f&&k.delete(e),g.signal.aborted)return;if(me(m))return N.add(e),void await se(E,m);if(ge(m)){let t=ue(E.matches,r);return E.fetchers.delete(e),void z({fetchers:new Map(E.fetchers),errors:{[t.route.id]:m.error}})}s(!fe(m),"Unhandled fetcher deferred data");let y={state:"idle",data:m.data,formMethod:void 0,formAction:void 0,formEncType:void 0,formData:void 0," _hasFetcherDoneAnything ":!0};E.fetchers.set(e,y),z({fetchers:new Map(E.fetchers)})}(e,a,y,b,m,v))},revalidate:function(){Ce(),z({revalidation:"loading"}),"submitting"!==E.navigation.state&&("idle"!==E.navigation.state?ne(O||E.historyAction,E.navigation.location,{overrideNavigation:E.navigation}):ne(E.historyAction,E.location,{startUninterruptedRevalidation:!0}))},createHref:e=>t.history.createHref(e),encodeLocation:e=>t.history.encodeLocation(e),getFetcher:re,deleteFetcher:Se,dispose:function(){h&&h(),m.clear(),S&&S.abort(),E.fetchers.forEach(((e,t)=>Se(t))),E.blockers.forEach(((e,t)=>_e(t)))},getBlocker:function(e,t){let n=E.blockers.get(e)||J;return F.get(e)!==t&&F.set(e,t),n},deleteBlocker:_e,_internalFetchControllers:k,_internalActiveDeferreds:B,_internalSetRoutes:function(e){i={},r=f(e,n,void 0,i)}},P}({basename:void 0,future:Ke({},void 0,{v7_prependBasename:!0}),history:function(t){return void 0===t&&(t={}),function(t,n,r,a){void 0===a&&(a={});let{window:p=document.defaultView,v5Compat:d=!1}=a,h=p.history,f=e.Pop,g=null,m=y();function y(){return(h.state||{idx:null}).idx}function v(){f=e.Pop;let t=y(),n=null==t?null:t-m;m=t,g&&g({action:f,location:C.location,delta:n})}function b(e){let t="null"!==p.location.origin?p.location.origin:p.location.href,n="string"==typeof e?e:c(e);return s(t,"No window.location.(origin|href) available to create URL for href: "+n),new URL(n,t)}null==m&&(m=0,h.replaceState(o({},h.state,{idx:m}),""));let C={get action(){return f},get location(){return t(p,h)},listen(e){if(g)throw new Error("A history only accepts one active listener");return p.addEventListener(i,v),g=e,()=>{p.removeEventListener(i,v),g=null}},createHref:e=>n(p,e),createURL:b,encodeLocation(e){let t=b(e);return{pathname:t.pathname,search:t.search,hash:t.hash}},push:function(t,n){f=e.Push;let o=u(C.location,t,n);r&&r(o,t),m=y()+1;let i=l(o,m),s=C.createHref(o);try{h.pushState(i,"",s)}catch(e){p.location.assign(s)}d&&g&&g({action:f,location:C.location,delta:1})},replace:function(t,n){f=e.Replace;let o=u(C.location,t,n);r&&r(o,t),m=y();let i=l(o,m),s=C.createHref(o);h.replaceState(i,"",s),d&&g&&g({action:f,location:C.location,delta:0})},go:e=>h.go(e)};return C}((function(e,t){let{pathname:n,search:r,hash:o}=e.location;return u("",{pathname:n,search:r,hash:o},t.state&&t.state.usr||null,t.state&&t.state.key||"default")}),(function(e,t){return"string"==typeof t?t:c(t)}),null,t)}({window:void 0}),hydrationData:function(){var e;let t=null==(e=window)?void 0:e.__staticRouterHydrationData;return t&&t.errors&&(t=Ke({},t,{errors:Ye(t.errors)})),t}(),routes:ho,mapRouteProperties:function(e){let n={hasErrorBoundary:null!=e.ErrorBoundary||null!=e.errorElement};return e.Component&&Object.assign(n,{element:t.createElement(e.Component),Component:void 0}),e.ErrorBoundary&&Object.assign(n,{errorElement:t.createElement(e.ErrorBoundary),ErrorBoundary:void 0}),n}}).initialize());const go=function(){return t.createElement("div",{className:"app"},t.createElement(Fn,null,t.createElement(co,null),t.createElement(We,{router:fo})))};var mo=document.getElementById("root");(0,r.s)(mo).render(t.createElement(t.StrictMode,null,t.createElement(go,null)))})()})(); \ No newline at end of file +`,Ur=({reverseOrder:e,position:n="top-center",toastOptions:r,gutter:o,children:i,containerStyle:s,containerClassName:a})=>{let{toasts:l,handlers:u}=(e=>{let{toasts:n,pausedAt:r}=((e={})=>{let[n,r]=(0,t.useState)(yr);(0,t.useEffect)((()=>(mr.push(r),()=>{let e=mr.indexOf(r);e>-1&&mr.splice(e,1)})),[n]);let o=n.toasts.map((t=>{var n,r;return{...e,...e[t.type],...t,duration:t.duration||(null==(n=e[t.type])?void 0:n.duration)||(null==e?void 0:e.duration)||br[t.type],style:{...e.style,...null==(r=e[t.type])?void 0:r.style,...t.style}}}));return{...n,toasts:o}})(e);(0,t.useEffect)((()=>{if(r)return;let e=Date.now(),t=n.map((t=>{if(t.duration===1/0)return;let n=(t.duration||0)+t.pauseDuration-(e-t.createdAt);if(!(n<0))return setTimeout((()=>wr.dismiss(t.id)),n);t.visible&&wr.dismiss(t.id)}));return()=>{t.forEach((e=>e&&clearTimeout(e)))}}),[n,r]);let o=(0,t.useCallback)((()=>{r&&vr({type:6,time:Date.now()})}),[r]),i=(0,t.useCallback)(((e,t)=>{let{reverseOrder:r=!1,gutter:o=8,defaultPosition:i}=t||{},s=n.filter((t=>(t.position||i)===(e.position||i)&&t.height)),a=s.findIndex((t=>t.id===e.id)),l=s.filter(((e,t)=>t<a&&e.visible)).length;return s.filter((e=>e.visible)).slice(...r?[l+1]:[0,l]).reduce(((e,t)=>e+(t.height||0)+o),0)}),[n]);return{toasts:n,handlers:{updateHeight:xr,startPause:Pr,endPause:o,calculateOffset:i}}})(r);return t.createElement("div",{style:{position:"fixed",zIndex:9999,top:16,left:16,right:16,bottom:16,pointerEvents:"none",...s},className:a,onMouseEnter:u.startPause,onMouseLeave:u.endPause},l.map((r=>{let s=r.position||n,a=((e,t)=>{let n=e.includes("top"),r=n?{top:0}:{bottom:0},o=e.includes("center")?{justifyContent:"center"}:e.includes("right")?{justifyContent:"flex-end"}:{};return{left:0,right:0,display:"flex",position:"absolute",transition:dr()?void 0:"all 230ms cubic-bezier(.21,1.02,.73,1)",transform:`translateY(${t*(n?1:-1)}px)`,...r,...o}})(s,u.calculateOffset(r,{reverseOrder:e,gutter:o,defaultPosition:n}));return t.createElement(zr,{id:r.id,key:r.id,onHeightUpdate:u.updateHeight,className:r.visible?Hr:"",style:a},"custom"===r.type?cr(r.message,r):i?i(r):t.createElement(Qr,{toast:r,position:s}))})))},Wr=wr,Jr=n(535),$r=n(352);function Gr(e,t){if(0==t.column.indexValue&&"item"in t.row){var n,r,o=t.row.item;void 0!==o.customDescription&&(null===(n=t.htmlElement.parentElement)||void 0===n||n.children[0].children[0].setAttribute("description",o.customDescription),null===(r=t.htmlElement.parentElement)||void 0===r||r.children[0].children[0].classList.add("survey-tooltip"))}}function Kr(e){var t=e[0];if(void 0===t||null==t||""==t)return!0;try{var n=new URL(t);return"http:"===n.protocol||"https:"===n.protocol}catch(e){return!1}}function Zr(e,t){t.question.hideCheckboxLabels&&(t.cssClasses.root+=" hidden-checkbox-labels")}function Yr(e,t){var n,r='[data-name="'+t.question.name+'"]',o=null===(n=document.querySelector(r))||void 0===n?void 0:n.querySelector("h5");o&&!o.classList.contains("sv-header-flex")&&t.question.updateElementCss()}function Xr(e,t,n){var r;n.verificationStatus.set(e.name,t);var o=document.createElement("button");o.type="button",o.className="sv-action-bar-item verification",o.innerHTML=t,t==En.Unverified?(o.innerHTML="No change from previous year",o.className+=" verification-required",o.onclick=function(){"display"!=n.mode&&(e.validate(),Xr(e,En.Verified,n))}):(o.innerHTML="Answer updated",o.className+=" verification-ok");var i='[data-name="'+e.name+'"]',s=null===(r=document.querySelector(i))||void 0===r?void 0:r.querySelector("h5"),a=null==s?void 0:s.querySelector(".verification");a?a.replaceWith(o):null==s||s.appendChild(o)}const eo=function(e){var n=e.surveyModel,r=(0,t.useCallback)((function(e,t){var r=n.verificationStatus.get(t.question.name);r&&Xr(t.question,r,n)}),[n]),o=(0,t.useCallback)((function(e,t){n.verificationStatus.get(t.question.name)==En.Unverified&&Xr(t.question,En.Edited,n)}),[n]);return Jr.FunctionFactory.Instance.hasFunction("validateWebsiteUrl")||Jr.FunctionFactory.Instance.register("validateWebsiteUrl",Kr),n.css.question.title.includes("sv-header-flex")||(n.css.question.title="sv-title sv-question__title sv-header-flex",n.css.question.titleOnError="sv-question__title--error sv-error-color-fix"),n.onAfterRenderQuestion.hasFunc(r)||(n.onAfterRenderQuestion.add(r),n.onAfterRenderQuestion.add(Yr)),n.onValueChanged.hasFunc(o)||n.onValueChanged.add(o),n.onUpdateQuestionCssClasses.hasFunc(Zr)||n.onUpdateQuestionCssClasses.add(Zr),n.onMatrixAfterCellRender.hasFunc(Gr)||n.onMatrixAfterCellRender.add(Gr),t.createElement($r.Survey,{model:n})},to=t.forwardRef(((e,t)=>{const[{className:n,...r},{as:o="div",bsPrefix:i,spans:s}]=function({as:e,bsPrefix:t,className:n,...r}){t=wt(t,"col");const o=xt(),i=Pt(),s=[],a=[];return o.forEach((e=>{const n=r[e];let o,l,u;delete r[e],"object"==typeof n&&null!=n?({span:o,offset:l,order:u}=n):o=n;const c=e!==i?`-${e}`:"";o&&s.push(!0===o?`${t}${c}`:`${t}${c}-${o}`),null!=u&&a.push(`order${c}-${u}`),null!=l&&a.push(`offset${c}-${l}`)})),[{...r,className:dt()(n,...s,...a)},{as:e,bsPrefix:t,spans:s}]}(e);return(0,yt.jsx)(o,{...r,ref:t,className:dt()(n,!s.length&&i)})}));to.displayName="Col";const no=to;function ro(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function oo(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?ro(Object(n),!0).forEach((function(t){jn(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):ro(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}const io=function(e){var n=e.surveyModel,r=e.pageNoSetter,o=st((0,t.useState)([]),2),i=o[0],s=o[1],a=function(e){return!(null===e.value||void 0===e.value||""===e.value||"checkbox"===e.getType()&&0==e.value.length||"multipletext"===e.getType()&&(1===Object.keys(e.value).length&&void 0===Object.values(e.value)[0]||0===Object.keys(e.value).length))};(0,t.useEffect)((function(){var e=function(e){if(e&&e.pages){var t=[];e.pages.forEach((function(n){var r=n.questions.filter((function(e){return e.startWithNewLine})),o=r.length,i=r.filter(a).length,s=o-i,l=i/o;t.push({completionPercentage:100*l,unansweredPercentage:s/o*100,totalPages:e.pages.length,pageTitle:n.title})})),s(t)}};n.onValueChanged.add((function(t){e(t)})),e(n)}),[n]);var l={height:"0.5rem",transition:"width 0.3s ease"};return t.createElement(Mn,{className:"survey-progress"},t.createElement(qn,null,i.map((function(e,o){return t.createElement(no,{xs:12,md:!0,key:o,onClick:function(){return r(o)},style:{cursor:"pointer",margin:"0.5rem"}},t.createElement("div",null,t.createElement("span",{style:{whiteSpace:"nowrap",fontSize:"1.5rem",marginRight:"0.25rem",fontWeight:"bold",color:"#2db394"}},o+1),t.createElement("span",{style:oo({whiteSpace:"nowrap"},n.currentPageNo==o&&{fontWeight:"bold"})},e.pageTitle),t.createElement("div",{style:{display:"flex",flexWrap:"wrap"}},t.createElement("div",{style:oo(oo({},l),{},{width:"".concat(e.completionPercentage,"%"),backgroundColor:"#262261"})}),t.createElement("div",{style:oo(oo({},l),{},{width:"".concat(e.unansweredPercentage,"%"),backgroundColor:"#cdcdcd"})}))))}))))},so=function(e){var n=e.surveyModel,r=e.surveyActions,o=e.year,i=e.nren,s=e.children,a=st((0,t.useState)(0),2),l=a[0],u=a[1],c=st((0,t.useState)(!1),2),p=c[0],d=c[1],h=st((0,t.useState)(""),2),f=h[0],g=h[1],m=st((0,t.useState)(""),2),y=m[0],v=m[1],b=(0,t.useContext)(Bn).user,C=(0,t.useCallback)((function(){d("edit"==n.mode),g(n.lockedBy),u(n.currentPageNo),v(n.status)}),[n]);(0,t.useEffect)((function(){C()}),[C]);var w=function(e){u(e),n.currentPageNo=e},x=function(){w(n.currentPageNo+1)},P=function(){var e=lt(ct().mark((function e(t){return ct().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return e.next=2,r[t]();case 2:C();case 3:case"end":return e.stop()}}),e)})));return function(t){return e.apply(this,arguments)}}(),S=function(e,t){return V(e,(function(){return P(t)}))},V=function(e,n){return t.createElement("button",{className:"sv-btn sv-btn--navigation",onClick:n},e)},E="Save and stop editing",O="Save progress",T="Start editing",_="Complete Survey",R=function(){return t.createElement("div",{className:"survey-edit-buttons-block"},!p&&!f&&n.editAllowed&&S(T,"startEdit"),!p&&f&&f==b.name&&S("Discard any unsaved changes and release your lock","releaseLock"),p&&y==On.started&&S(O,"save"),p&&y==On.started&&S(E,"saveAndStopEdit"),p&&l===n.visiblePages.length-1&&S(_,"complete"),l!==n.visiblePages.length-1&&V("Next Section",x))},I=parseInt(o);return t.createElement(Mn,null,t.createElement(qn,{className:"survey-content"},t.createElement("h2",null,t.createElement("span",{className:"survey-title"},o," Compendium Survey "),t.createElement("span",{className:"survey-title-nren"}," ",i," "),t.createElement("span",null," - ",y)),t.createElement("p",{style:{marginTop:"1rem"}},"To get started, click “",T,"” to end read-only mode. This is only possible when nobody else from your NREN is currently working on the survey.",t.createElement("br",null),"Where available, the survey questions are pre-filled with answers from the previous year. The survey asks about the past year, i.e. the ",o," survey asks about data from ",I-1," (or ",I-1,"/",o," if your NRENs financial year does not match the calendar year). You can edit the prefilled answer to provide new information, or press the “no change from previous year” button.",t.createElement("br",null),"Press the “",O,"“ or “",E,"“ button to save all answers in the survey. When you reach the last section of the survey (Services), you will find a “",_,"“ button which saves all answers in the survey and lets the Compendium team know that your answers are ready to be published.",t.createElement("br",null),"As long as the survey remains open, any Compendium administrator from your NREN can add answers or amend existing ones, even after using the “",_,"“ button. Different people from your NREN can contribute to the survey if needed.",t.createElement("br",null),"Some fields require specific data, such as numerical data, valid http-addresses, and in some questions, the answer has to add up to 100%. If an answer does not fulfil the set criteria, the question will turn pink and an error message will appear. Fields can be left blank if you prefer not to answer a question.",t.createElement("br",null),"If you notice any errors after the survey was closed, please contact us for correcting those."),t.createElement("p",null,"Thank you for taking the time to fill in the ",o," Compendium Survey. Any questions or requests can be sent to ",t.createElement("a",{href:"mailto:Partner-Relations@geant.org"},t.createElement("span",null,"Partner-Relations@geant.org"))),p&&t.createElement(t.Fragment,null,t.createElement("br",null),t.createElement("b",null,"Remember to click “",E,"” before leaving the page."))),t.createElement(qn,null,R()),t.createElement(qn,{className:"survey-content"},!p&&t.createElement("div",{className:"survey-edit-explainer"},!f&&n.editAllowed&&"The survey is in read-only mode; click the “Start editing“ button to begin editing the answers.",!f&&!n.editAllowed&&"The survey is in read-only mode and can not be edited by you.",f&&f!=b.name&&"The survey is in read-only mode and currently being edited by: "+f+". To start editing the survey, ask them to complete their edits.",f&&f==b.name&&'The survey is in read-only mode because you started editing in another tab, browser or device. To start editing the survey, either complete those edits or click the "Discard any unsaved changes" button.')),t.createElement(qn,null,t.createElement(io,{surveyModel:n,pageNoSetter:w}),s),t.createElement(qn,null,R()))},ao=function(e){var n=e.when,r=e.onPageExit;return function(e){let{router:n}=Qe(Be.UseBlocker),r=ze(Fe.UseBlocker),[o]=t.useState((()=>String(++Ue))),i=t.useCallback((t=>!!e()),[e]);n.getBlocker(o,i);t.useEffect((()=>()=>n.deleteBlocker(o)),[n,o]),r.blockers.get(o)}((function(){if(n()){var t=window.confirm(e.message);return t&&r(),!t}return!1})),t.createElement("div",null)};Jr.Serializer.addProperty("itemvalue","customDescription:text"),Jr.Serializer.addProperty("question","hideCheckboxLabels:boolean");const lo=function(e){var n=e.loadFrom,r=st((0,t.useState)(),2),o=r[0],i=r[1],s=function(){let{matches:e}=t.useContext(Te),n=e[e.length-1];return n?n.params:{}}(),a=s.year,l=s.nren,u=st((0,t.useState)("loading survey..."),2),c=u[0],p=u[1],d=(0,t.useCallback)((function(e){return e.preventDefault(),e.returnValue=""}),[]),h=(0,t.useCallback)((function(){window.navigator.sendBeacon("/api/response/unlock/"+a+"/"+l)}),[]),f=(0,t.useCallback)((function(){window.navigator.sendBeacon("/api/response/unlock/"+a+"/"+l),removeEventListener("beforeunload",d,{capture:!0}),removeEventListener("pagehide",h)}),[]);if((0,t.useEffect)((function(){function e(){return(e=lt(ct().mark((function e(){var t,r,o,s;return ct().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return e.next=2,fetch(n+a+(l?"/"+l:""));case 2:return t=e.sent,e.next=5,t.json();case 5:if(r=e.sent,t.ok){e.next=12;break}if(!("message"in r)){e.next=11;break}throw new Error(r.message);case 11:throw new Error("Request failed with status ".concat(t.status));case 12:for(s in(o=new Jr.Model(r.model)).setVariable("surveyyear",a),o.setVariable("previousyear",parseInt(a)-1),o.showNavigationButtons=!1,o.requiredText="",o.verificationStatus=new Map,r.verification_status)o.verificationStatus.set(s,r.verification_status[s]);o.data=r.data,o.clearIncorrectValues(!0),o.currentPageNo=r.page,o.mode=r.mode,o.lockedBy=r.locked_by,o.status=r.status,o.editAllowed=r.edit_allowed,i(o);case 27:case"end":return e.stop()}}),e)})))).apply(this,arguments)}(function(){return e.apply(this,arguments)})().catch((function(e){return p("Error when loading survey: "+e.message)}))}),[]),!o)return c;var g,m,y,v,b,C=function(){var e=lt(ct().mark((function e(t,n){var r,i,s;return ct().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:if(l){e.next=2;break}return e.abrupt("return","Saving not available in inpect/try mode");case 2:return r={lock_uuid:t.lockUUID,new_state:n,data:t.data,page:t.currentPageNo,verification_status:Object.fromEntries(t.verificationStatus)},e.prev=3,e.next=6,fetch("/api/response/save/"+a+"/"+l,{method:"POST",headers:{"Content-Type":"application/json; charset=utf-8"},body:JSON.stringify(r)});case 6:return i=e.sent,e.next=9,i.json();case 9:if(s=e.sent,i.ok){e.next=12;break}return e.abrupt("return",s.message);case 12:o.mode=s.mode,o.lockedBy=s.locked_by,o.status=s.status,e.next=20;break;case 17:return e.prev=17,e.t0=e.catch(3),e.abrupt("return","Unknown Error: "+e.t0.message);case 20:case"end":return e.stop()}}),e,null,[[3,17]])})));return function(t,n){return e.apply(this,arguments)}}(),w=function(e){var t="",n=function(e,n){e.verificationStatus.get(n.name)==En.Unverified&&(""==t&&(t=n.name),n.error='Please verify that last years data is correct by editing the answer or pressing the "No change from previous year" button!')};o.onValidateQuestion.add(n);var r=e();return o.onValidateQuestion.remove(n),r||Wr("Validation failed!"),r},x={save:(b=lt(ct().mark((function e(){var t;return ct().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return e.next=2,C(o,"editing");case 2:t=e.sent,Wr(t?"Failed saving survey: "+t:"Survey saved!");case 4:case"end":return e.stop()}}),e)}))),function(){return b.apply(this,arguments)}),complete:(v=lt(ct().mark((function e(){var t;return ct().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:if(!w(o.validate.bind(o,!0,!0))){e.next=6;break}return e.next=4,C(o,"completed");case 4:(t=e.sent)?Wr("Failed completing survey: "+t):(Wr("Survey completed!"),removeEventListener("beforeunload",d,{capture:!0}),removeEventListener("pagehide",h));case 6:case"end":return e.stop()}}),e)}))),function(){return v.apply(this,arguments)}),saveAndStopEdit:(y=lt(ct().mark((function e(){var t;return ct().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return e.next=2,C(o,"readonly");case 2:(t=e.sent)?Wr("Failed saving survey: "+t):(Wr("Survey saved!"),removeEventListener("beforeunload",d,{capture:!0}),removeEventListener("pagehide",h));case 4:case"end":return e.stop()}}),e)}))),function(){return y.apply(this,arguments)}),startEdit:(m=lt(ct().mark((function e(){var t,n,r;return ct().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return e.next=2,fetch("/api/response/lock/"+a+"/"+l,{method:"POST"});case 2:return t=e.sent,e.next=5,t.json();case 5:if(n=e.sent,t.ok){e.next=9;break}return Wr("Failed starting edit: "+n.message),e.abrupt("return");case 9:for(r in addEventListener("pagehide",h),addEventListener("beforeunload",d,{capture:!0}),n.verification_status)o.verificationStatus.set(r,n.verification_status[r]);o.data=n.data,o.clearIncorrectValues(!0),o.mode=n.mode,o.lockedBy=n.locked_by,o.lockUUID=n.lock_uuid,o.status=n.status;case 18:case"end":return e.stop()}}),e)}))),function(){return m.apply(this,arguments)}),releaseLock:(g=lt(ct().mark((function e(){var t,n;return ct().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return e.next=2,fetch("/api/response/unlock/"+a+"/"+l,{method:"POST"});case 2:return t=e.sent,e.next=5,t.json();case 5:if(n=e.sent,t.ok){e.next=9;break}return Wr("Failed releasing lock: "+n.message),e.abrupt("return");case 9:o.mode=n.mode,o.lockedBy=n.locked_by,o.status=n.status;case 12:case"end":return e.stop()}}),e)}))),function(){return g.apply(this,arguments)}),validatePage:function(){w(o.validatePage.bind(o))&&Wr("Page validation successful!")}};return t.createElement(Mn,{className:"survey-container"},t.createElement(Ur,null),t.createElement(ao,{message:"Are you sure you want to leave this page? Information you've entered may not be saved.",when:function(){return"edit"==o.mode&&!!l},onPageExit:f}),t.createElement(so,{surveyModel:o,surveyActions:x,year:a,nren:l},t.createElement(eo,{surveyModel:o})))},uo=n.p+"9ab20ac1d835b50b2e01.svg",co=function(){return t.createElement("div",{className:"external-page-nav-bar"},t.createElement(Mn,null,t.createElement(qn,null,t.createElement(no,{xs:10},t.createElement("div",{className:"nav-wrapper"},t.createElement("nav",{className:"header-nav"},t.createElement("a",{href:"https://geant.org/"},t.createElement("img",{src:uo})),t.createElement("ul",null,t.createElement("li",null,t.createElement("a",{className:"nav-link-entry",href:"https://network.geant.org/"},"NETWORK")),t.createElement("li",null,t.createElement("a",{className:"nav-link-entry",href:"https://geant.org/services/"},"SERVICES")),t.createElement("li",null,t.createElement("a",{className:"nav-link-entry",href:"https://community.geant.org/"},"COMMUNITY")),t.createElement("li",null,t.createElement("a",{className:"nav-link-entry",href:"https://tnc23.geant.org/"},"TNC")),t.createElement("li",null,t.createElement("a",{className:"nav-link-entry",href:"https://geant.org/projects/"},"PROJECTS")),t.createElement("li",null,t.createElement("a",{className:"nav-link-entry",href:"https://connect.geant.org/"},"CONNECT")),t.createElement("li",null,t.createElement("a",{className:"nav-link-entry",href:"https://impact.geant.org/"},"IMPACT")),t.createElement("li",null,t.createElement("a",{className:"nav-link-entry",href:"https://careers.geant.org/"},"CAREERS")),t.createElement("li",null,t.createElement("a",{className:"nav-link-entry",href:"https://about.geant.org/"},"ABOUT")),t.createElement("li",null,t.createElement("a",{className:"nav-link-entry",href:"https://connect.geant.org/community-news"},"NEWS")),t.createElement("li",null,t.createElement("a",{className:"nav-link-entry",href:"https://resources.geant.org/"},"RESOURCES")))))))))},po=function(){var e,n=(0,t.useContext)(Bn).user,r=je(),o=!!n.id,i=!!o&&!!n.nrens.length,s=i?n.nrens[0]:"",a=!!o&&n.permissions.admin;return t.createElement(Mn,{className:"py-5 grey-container"},t.createElement(qn,null,t.createElement("div",{className:"center-text"},t.createElement("h1",{className:"geant-header"},"THE GÉANT COMPENDIUM OF NRENS SURVEY"),t.createElement("div",{className:"wordwrap pt-4",style:{maxWidth:"75rem"}},t.createElement("p",{style:{textAlign:"left"}},"Hello,",t.createElement("br",null),"Welcome to the GÉANT Compendium Survey. (N)REN Compendium administrators can login via Single Sign On (SSO) ",t.createElement("a",{href:"/login"},"here"),", which will complete their registration to fill in the 2023 Compendium survey. This will send a notification to the Compendium administration team and they will assign you to your (N)REN.",t.createElement("br",null),"Once this step has been completed, you will receive an email from the administration team. We aim to get back to you the same working day, but sometimes may take a little longer.",t.createElement("br",null),"If you are not sure whether you are a Compendium Administrator for your (N)REN, please contact your GÉANT Partner Relations relationship manager.",t.createElement("br",null),"Thank you."),t.createElement("span",null,"Current registration status:"),t.createElement("br",null),t.createElement("br",null),a?t.createElement("ul",null,t.createElement("li",null,t.createElement("span",null,"You are logged in as a Compendium Administrator")),t.createElement("li",null,t.createElement("span",null,"Click ",t.createElement(tt,{to:"/survey/admin/surveys"},"here")," to access the survey management page.")),t.createElement("li",null,t.createElement("span",null,"Click ",t.createElement(tt,{to:"/survey/admin/users"},"here")," to access the user management page."))):t.createElement("ul",null,!a&&i&&(e=(new Date).getFullYear(),r("/survey/response/".concat(e,"/").concat(s)),t.createElement(t.Fragment,null)),o?t.createElement("li",null,t.createElement("span",null,"You are logged in")):t.createElement("li",null,t.createElement("span",null,"You are not logged in")),o&&!i&&t.createElement("li",null,t.createElement("span",null,"Your access to the survey has not yet been approved")),o&&!i&&t.createElement("li",null,t.createElement("span",null,"Once you have been approved, you will immediately be directed to the relevant survey upon visiting this page")))))))};var ho,fo=(ho=[{path:"survey/admin/surveys",element:t.createElement(In,null)},{path:"survey/admin/users",element:t.createElement(Jn,null)},{path:"survey/admin/inspect/:year",element:t.createElement(lo,{loadFrom:"/api/response/inspect/"})},{path:"survey/admin/try/:year",element:t.createElement(lo,{loadFrom:"/api/response/try/"})},{path:"survey/response/:year/:nren",element:t.createElement(lo,{loadFrom:"/api/response/load/"})},{path:"*",element:t.createElement(po,null)}],function(t){let n;if(s(t.routes.length>0,"You must provide a non-empty routes array to createRouter"),t.mapRouteProperties)n=t.mapRouteProperties;else if(t.detectErrorBoundary){let e=t.detectErrorBoundary;n=t=>({hasErrorBoundary:e(t)})}else n=Z;let r,i={},l=f(t.routes,n,void 0,i),c=t.basename||"/",p=o({v7_normalizeFormMethod:!1,v7_prependBasename:!1},t.future),h=null,m=new Set,y=null,v=null,b=null,C=null!=t.hydrationData,w=g(l,t.history.location,c),x=null;if(null==w){let e=pe(404,{pathname:t.history.location.pathname}),{matches:n,route:r}=ce(l);w=n,x={[r.id]:e}}let P,S,V=!(w.some((e=>e.route.lazy))||w.some((e=>e.route.loader))&&null==t.hydrationData),E={historyAction:t.history.action,location:t.history.location,matches:w,initialized:V,navigation:U,restoreScrollPosition:null==t.hydrationData&&null,preventScrollReset:!1,revalidation:"idle",loaderData:t.hydrationData&&t.hydrationData.loaderData||{},actionData:t.hydrationData&&t.hydrationData.actionData||null,errors:t.hydrationData&&t.hydrationData.errors||x,fetchers:new Map,blockers:new Map},O=e.Pop,T=!1,R=!1,I=!1,D=[],j=[],k=new Map,M=0,L=-1,q=new Map,N=new Set,A=new Map,B=new Map,F=new Map,Q=!1;function z(e){E=o({},E,e),m.forEach((e=>e(E)))}function te(n,i){var s,a;let u,c=null!=E.actionData&&null!=E.navigation.formMethod&&ye(E.navigation.formMethod)&&"loading"===E.navigation.state&&!0!==(null==(s=n.state)?void 0:s._isRedirect);u=i.actionData?Object.keys(i.actionData).length>0?i.actionData:null:c?E.actionData:null;let p=i.loaderData?le(E.loaderData,i.loaderData,i.matches||[],i.errors):E.loaderData;for(let[e]of F)_e(e);let d=!0===T||null!=E.navigation.formMethod&&ye(E.navigation.formMethod)&&!0!==(null==(a=n.state)?void 0:a._isRedirect);r&&(l=r,r=void 0),z(o({},i,{actionData:u,loaderData:p,historyAction:O,location:n,initialized:!0,navigation:U,revalidation:"idle",restoreScrollPosition:je(n,i.matches||E.matches),preventScrollReset:d,blockers:new Map(E.blockers)})),R||O===e.Pop||(O===e.Push?t.history.push(n,n.state):O===e.Replace&&t.history.replace(n,n.state)),O=e.Pop,T=!1,R=!1,I=!1,D=[],j=[]}async function ne(s,a,u){S&&S.abort(),S=null,O=s,R=!0===(u&&u.startUninterruptedRevalidation),function(e,t){if(y&&v&&b){let n=t.map((e=>we(e,E.loaderData))),r=v(e,n)||e.key;y[r]=b()}}(E.location,E.matches),T=!0===(u&&u.preventScrollReset);let p=r||l,h=u&&u.overrideNavigation,f=g(p,a,c);if(!f){let e=pe(404,{pathname:a.pathname}),{matches:t,route:n}=ce(p);return De(),void te(a,{matches:t,loaderData:{},errors:{[n.id]:e}})}if(E.initialized&&function(e,t){return e.pathname===t.pathname&&e.search===t.search&&(""===e.hash?""!==t.hash:e.hash===t.hash||""!==t.hash)}(E.location,a)&&!(u&&u.submission&&ye(u.submission.formMethod)))return void te(a,{matches:f});S=new AbortController;let m,C,w=ie(t.history,a,S.signal,u&&u.submission);if(u&&u.pendingError)C={[ue(f).route.id]:u.pendingError};else if(u&&u.submission&&ye(u.submission.formMethod)){let t=await async function(t,r,s,a,l){let u;Ce(),z({navigation:o({state:"submitting",location:r},s)});let p=xe(a,r);if(p.route.action||p.route.lazy){if(u=await oe("action",t,p,a,i,n,c),t.signal.aborted)return{shortCircuited:!0}}else u={type:d.error,error:pe(405,{method:t.method,pathname:r.pathname,routeId:p.route.id})};if(me(u)){let e;return e=l&&null!=l.replace?l.replace:u.location===E.location.pathname+E.location.search,await se(E,u,{submission:s,replace:e}),{shortCircuited:!0}}if(ge(u)){let t=ue(a,p.route.id);return!0!==(l&&l.replace)&&(O=e.Push),{pendingActionData:{},pendingActionError:{[t.route.id]:u.error}}}if(fe(u))throw pe(400,{type:"defer-action"});return{pendingActionData:{[p.route.id]:u.data}}}(w,a,u.submission,f,{replace:u.replace});if(t.shortCircuited)return;m=t.pendingActionData,C=t.pendingActionError,h=o({state:"loading",location:a},u.submission),w=new Request(w.url,{signal:w.signal})}let{shortCircuited:x,loaderData:P,errors:V}=await async function(e,n,i,s,a,u,p,d,h){let f=s;f||(f=o({state:"loading",location:n,formMethod:void 0,formAction:void 0,formEncType:void 0,formData:void 0},a));let g=a||u?a||u:f.formMethod&&f.formAction&&f.formData&&f.formEncType?{formMethod:f.formMethod,formAction:f.formAction,formData:f.formData,formEncType:f.formEncType}:void 0,m=r||l,[y,v]=ee(t.history,E,i,g,n,I,D,j,A,m,c,d,h);if(De((e=>!(i&&i.some((t=>t.route.id===e)))||y&&y.some((t=>t.route.id===e)))),0===y.length&&0===v.length){let e=Oe();return te(n,o({matches:i,loaderData:{},errors:h||null},d?{actionData:d}:{},e?{fetchers:new Map(E.fetchers)}:{})),{shortCircuited:!0}}if(!R){v.forEach((e=>{let t=E.fetchers.get(e.key),n={state:"loading",data:t&&t.data,formMethod:void 0,formAction:void 0,formEncType:void 0,formData:void 0," _hasFetcherDoneAnything ":!0};E.fetchers.set(e.key,n)}));let e=d||E.actionData;z(o({navigation:f},e?0===Object.keys(e).length?{actionData:null}:{actionData:e}:{},v.length>0?{fetchers:new Map(E.fetchers)}:{}))}L=++M,v.forEach((e=>{e.controller&&k.set(e.key,e.controller)}));let b=()=>v.forEach((e=>Ve(e.key)));S&&S.signal.addEventListener("abort",b);let{results:C,loaderResults:w,fetcherResults:x}=await he(E.matches,i,y,v,e);if(e.signal.aborted)return{shortCircuited:!0};S&&S.signal.removeEventListener("abort",b),v.forEach((e=>k.delete(e.key)));let P=de(C);if(P)return await se(E,P,{replace:p}),{shortCircuited:!0};let{loaderData:V,errors:O}=ae(E,i,y,w,h,v,x,B);B.forEach(((e,t)=>{e.subscribe((n=>{(n||e.done)&&B.delete(t)}))}));let T=Oe(),_=Te(L);return o({loaderData:V,errors:O},T||_||v.length>0?{fetchers:new Map(E.fetchers)}:{})}(w,a,f,h,u&&u.submission,u&&u.fetcherSubmission,u&&u.replace,m,C);x||(S=null,te(a,o({matches:f},m?{actionData:m}:{},{loaderData:P,errors:V})))}function re(e){return E.fetchers.get(e)||W}async function se(n,r,i){var a;let{submission:l,replace:p,isFetchActionRedirect:d}=void 0===i?{}:i;r.revalidate&&(I=!0);let h=u(n.location,r.location,o({_isRedirect:!0},d?{_isFetchActionRedirect:!0}:{}));if(s(h,"Expected a location on the redirect navigation"),$.test(r.location)&&G&&void 0!==(null==(a=window)?void 0:a.location)){let e=t.history.createURL(r.location),n=null==_(e.pathname,c);if(window.location.origin!==e.origin||n)return void(p?window.location.replace(r.location):window.location.assign(r.location))}S=null;let f=!0===p?e.Replace:e.Push,{formMethod:g,formAction:m,formEncType:y,formData:v}=n.navigation;!l&&g&&m&&v&&y&&(l={formMethod:g,formAction:m,formEncType:y,formData:v}),H.has(r.status)&&l&&ye(l.formMethod)?await ne(f,h,{submission:o({},l,{formAction:r.location}),preventScrollReset:T}):d?await ne(f,h,{overrideNavigation:{state:"loading",location:h,formMethod:void 0,formAction:void 0,formEncType:void 0,formData:void 0},fetcherSubmission:l,preventScrollReset:T}):await ne(f,h,{overrideNavigation:{state:"loading",location:h,formMethod:l?l.formMethod:void 0,formAction:l?l.formAction:void 0,formEncType:l?l.formEncType:void 0,formData:l?l.formData:void 0},preventScrollReset:T})}async function he(e,r,o,s,a){let l=await Promise.all([...o.map((e=>oe("loader",a,e,r,i,n,c))),...s.map((e=>e.matches&&e.match&&e.controller?oe("loader",ie(t.history,e.path,e.controller.signal),e.match,e.matches,i,n,c):{type:d.error,error:pe(404,{pathname:e.path})}))]),u=l.slice(0,o.length),p=l.slice(o.length);return await Promise.all([ve(e,o,u,u.map((()=>a.signal)),!1,E.loaderData),ve(e,s.map((e=>e.match)),p,s.map((e=>e.controller?e.controller.signal:null)),!0)]),{results:l,loaderResults:u,fetcherResults:p}}function Ce(){I=!0,D.push(...De()),A.forEach(((e,t)=>{k.has(t)&&(j.push(t),Ve(t))}))}function Pe(e,t,n){let r=ue(E.matches,t);Se(e),z({errors:{[r.route.id]:n},fetchers:new Map(E.fetchers)})}function Se(e){k.has(e)&&Ve(e),A.delete(e),q.delete(e),N.delete(e),E.fetchers.delete(e)}function Ve(e){let t=k.get(e);s(t,"Expected fetch controller: "+e),t.abort(),k.delete(e)}function Ee(e){for(let t of e){let e={state:"idle",data:re(t).data,formMethod:void 0,formAction:void 0,formEncType:void 0,formData:void 0," _hasFetcherDoneAnything ":!0};E.fetchers.set(t,e)}}function Oe(){let e=[],t=!1;for(let n of N){let r=E.fetchers.get(n);s(r,"Expected fetcher: "+n),"loading"===r.state&&(N.delete(n),e.push(n),t=!0)}return Ee(e),t}function Te(e){let t=[];for(let[n,r]of q)if(r<e){let e=E.fetchers.get(n);s(e,"Expected fetcher: "+n),"loading"===e.state&&(Ve(n),q.delete(n),t.push(n))}return Ee(t),t.length>0}function _e(e){E.blockers.delete(e),F.delete(e)}function Re(e,t){let n=E.blockers.get(e)||J;s("unblocked"===n.state&&"blocked"===t.state||"blocked"===n.state&&"blocked"===t.state||"blocked"===n.state&&"proceeding"===t.state||"blocked"===n.state&&"unblocked"===t.state||"proceeding"===n.state&&"unblocked"===t.state,"Invalid blocker state transition: "+n.state+" -> "+t.state),E.blockers.set(e,t),z({blockers:new Map(E.blockers)})}function Ie(e){let{currentLocation:t,nextLocation:n,historyAction:r}=e;if(0===F.size)return;F.size>1&&a(!1,"A router only supports one blocker at a time");let o=Array.from(F.entries()),[i,s]=o[o.length-1],l=E.blockers.get(i);return l&&"proceeding"===l.state?void 0:s({currentLocation:t,nextLocation:n,historyAction:r})?i:void 0}function De(e){let t=[];return B.forEach(((n,r)=>{e&&!e(r)||(n.cancel(),t.push(r),B.delete(r))})),t}function je(e,t){if(y&&v&&b){let n=t.map((e=>we(e,E.loaderData))),r=v(e,n)||e.key,o=y[r];if("number"==typeof o)return o}return null}return P={get basename(){return c},get state(){return E},get routes(){return l},initialize:function(){return h=t.history.listen((e=>{let{action:n,location:r,delta:o}=e;if(Q)return void(Q=!1);a(0===F.size||null!=o,"You are trying to use a blocker on a POP navigation to a location that was not created by @remix-run/router. This will fail silently in production. This can happen if you are navigating outside the router via `window.history.pushState`/`window.location.hash` instead of using router navigation APIs. This can also happen if you are using createHashRouter and the user manually changes the URL.");let i=Ie({currentLocation:E.location,nextLocation:r,historyAction:n});return i&&null!=o?(Q=!0,t.history.go(-1*o),void Re(i,{state:"blocked",location:r,proceed(){Re(i,{state:"proceeding",proceed:void 0,reset:void 0,location:r}),t.history.go(o)},reset(){_e(i),z({blockers:new Map(P.state.blockers)})}})):ne(n,r)})),E.initialized||ne(e.Pop,E.location),P},subscribe:function(e){return m.add(e),()=>m.delete(e)},enableScrollRestoration:function(e,t,n){if(y=e,b=t,v=n||(e=>e.key),!C&&E.navigation===U){C=!0;let e=je(E.location,E.matches);null!=e&&z({restoreScrollPosition:e})}return()=>{y=null,b=null,v=null}},navigate:async function n(r,i){if("number"==typeof r)return void t.history.go(r);let s=Y(E.location,E.matches,c,p.v7_prependBasename,r,null==i?void 0:i.fromRouteId,null==i?void 0:i.relative),{path:a,submission:l,error:d}=X(p.v7_normalizeFormMethod,!1,s,i),h=E.location,f=u(E.location,a,i&&i.state);f=o({},f,t.history.encodeLocation(f));let g=i&&null!=i.replace?i.replace:void 0,m=e.Push;!0===g?m=e.Replace:!1===g||null!=l&&ye(l.formMethod)&&l.formAction===E.location.pathname+E.location.search&&(m=e.Replace);let y=i&&"preventScrollReset"in i?!0===i.preventScrollReset:void 0,v=Ie({currentLocation:h,nextLocation:f,historyAction:m});if(!v)return await ne(m,f,{submission:l,pendingError:d,preventScrollReset:y,replace:i&&i.replace});Re(v,{state:"blocked",location:f,proceed(){Re(v,{state:"proceeding",proceed:void 0,reset:void 0,location:f}),n(r,i)},reset(){_e(v),z({blockers:new Map(E.blockers)})}})},fetch:function(e,a,u,d){if(K)throw new Error("router.fetch() was called during the server render, but it shouldn't be. You are likely calling a useFetcher() method in the body of your component. Try moving it to a useEffect or a callback.");k.has(e)&&Ve(e);let h=r||l,f=Y(E.location,E.matches,c,p.v7_prependBasename,u,a,null==d?void 0:d.relative),m=g(h,f,c);if(!m)return void Pe(e,a,pe(404,{pathname:f}));let{path:y,submission:v}=X(p.v7_normalizeFormMethod,!0,f,d),b=xe(m,y);T=!0===(d&&d.preventScrollReset),v&&ye(v.formMethod)?async function(e,a,u,p,d,h){if(Ce(),A.delete(e),!p.route.action&&!p.route.lazy){let t=pe(405,{method:h.formMethod,pathname:u,routeId:a});return void Pe(e,a,t)}let f=E.fetchers.get(e),m=o({state:"submitting"},h,{data:f&&f.data," _hasFetcherDoneAnything ":!0});E.fetchers.set(e,m),z({fetchers:new Map(E.fetchers)});let y=new AbortController,v=ie(t.history,u,y.signal,h);k.set(e,y);let b=await oe("action",v,p,d,i,n,c);if(v.signal.aborted)return void(k.get(e)===y&&k.delete(e));if(me(b)){k.delete(e),N.add(e);let t=o({state:"loading"},h,{data:void 0," _hasFetcherDoneAnything ":!0});return E.fetchers.set(e,t),z({fetchers:new Map(E.fetchers)}),se(E,b,{submission:h,isFetchActionRedirect:!0})}if(ge(b))return void Pe(e,a,b.error);if(fe(b))throw pe(400,{type:"defer-action"});let C=E.navigation.location||E.location,w=ie(t.history,C,y.signal),x=r||l,P="idle"!==E.navigation.state?g(x,E.navigation.location,c):E.matches;s(P,"Didn't find any matches after fetcher action");let V=++M;q.set(e,V);let T=o({state:"loading",data:b.data},h,{" _hasFetcherDoneAnything ":!0});E.fetchers.set(e,T);let[_,R]=ee(t.history,E,P,h,C,I,D,j,A,x,c,{[p.route.id]:b.data},void 0);R.filter((t=>t.key!==e)).forEach((e=>{let t=e.key,n=E.fetchers.get(t),r={state:"loading",data:n&&n.data,formMethod:void 0,formAction:void 0,formEncType:void 0,formData:void 0," _hasFetcherDoneAnything ":!0};E.fetchers.set(t,r),e.controller&&k.set(t,e.controller)})),z({fetchers:new Map(E.fetchers)});let F=()=>R.forEach((e=>Ve(e.key)));y.signal.addEventListener("abort",F);let{results:Q,loaderResults:H,fetcherResults:U}=await he(E.matches,P,_,R,w);if(y.signal.aborted)return;y.signal.removeEventListener("abort",F),q.delete(e),k.delete(e),R.forEach((e=>k.delete(e.key)));let W=de(Q);if(W)return se(E,W);let{loaderData:J,errors:$}=ae(E,E.matches,_,H,void 0,R,U,B),G={state:"idle",data:b.data,formMethod:void 0,formAction:void 0,formEncType:void 0,formData:void 0," _hasFetcherDoneAnything ":!0};E.fetchers.set(e,G);let K=Te(V);"loading"===E.navigation.state&&V>L?(s(O,"Expected pending action"),S&&S.abort(),te(E.navigation.location,{matches:P,loaderData:J,errors:$,fetchers:new Map(E.fetchers)})):(z(o({errors:$,loaderData:le(E.loaderData,J,P,$)},K?{fetchers:new Map(E.fetchers)}:{})),I=!1)}(e,a,y,b,m,v):(A.set(e,{routeId:a,path:y}),async function(e,r,a,l,u,p){let d=E.fetchers.get(e),h=o({state:"loading",formMethod:void 0,formAction:void 0,formEncType:void 0,formData:void 0},p,{data:d&&d.data," _hasFetcherDoneAnything ":!0});E.fetchers.set(e,h),z({fetchers:new Map(E.fetchers)});let f=new AbortController,g=ie(t.history,a,f.signal);k.set(e,f);let m=await oe("loader",g,l,u,i,n,c);if(fe(m)&&(m=await be(m,g.signal,!0)||m),k.get(e)===f&&k.delete(e),g.signal.aborted)return;if(me(m))return N.add(e),void await se(E,m);if(ge(m)){let t=ue(E.matches,r);return E.fetchers.delete(e),void z({fetchers:new Map(E.fetchers),errors:{[t.route.id]:m.error}})}s(!fe(m),"Unhandled fetcher deferred data");let y={state:"idle",data:m.data,formMethod:void 0,formAction:void 0,formEncType:void 0,formData:void 0," _hasFetcherDoneAnything ":!0};E.fetchers.set(e,y),z({fetchers:new Map(E.fetchers)})}(e,a,y,b,m,v))},revalidate:function(){Ce(),z({revalidation:"loading"}),"submitting"!==E.navigation.state&&("idle"!==E.navigation.state?ne(O||E.historyAction,E.navigation.location,{overrideNavigation:E.navigation}):ne(E.historyAction,E.location,{startUninterruptedRevalidation:!0}))},createHref:e=>t.history.createHref(e),encodeLocation:e=>t.history.encodeLocation(e),getFetcher:re,deleteFetcher:Se,dispose:function(){h&&h(),m.clear(),S&&S.abort(),E.fetchers.forEach(((e,t)=>Se(t))),E.blockers.forEach(((e,t)=>_e(t)))},getBlocker:function(e,t){let n=E.blockers.get(e)||J;return F.get(e)!==t&&F.set(e,t),n},deleteBlocker:_e,_internalFetchControllers:k,_internalActiveDeferreds:B,_internalSetRoutes:function(e){i={},r=f(e,n,void 0,i)}},P}({basename:void 0,future:Ke({},void 0,{v7_prependBasename:!0}),history:function(t){return void 0===t&&(t={}),function(t,n,r,a){void 0===a&&(a={});let{window:p=document.defaultView,v5Compat:d=!1}=a,h=p.history,f=e.Pop,g=null,m=y();function y(){return(h.state||{idx:null}).idx}function v(){f=e.Pop;let t=y(),n=null==t?null:t-m;m=t,g&&g({action:f,location:C.location,delta:n})}function b(e){let t="null"!==p.location.origin?p.location.origin:p.location.href,n="string"==typeof e?e:c(e);return s(t,"No window.location.(origin|href) available to create URL for href: "+n),new URL(n,t)}null==m&&(m=0,h.replaceState(o({},h.state,{idx:m}),""));let C={get action(){return f},get location(){return t(p,h)},listen(e){if(g)throw new Error("A history only accepts one active listener");return p.addEventListener(i,v),g=e,()=>{p.removeEventListener(i,v),g=null}},createHref:e=>n(p,e),createURL:b,encodeLocation(e){let t=b(e);return{pathname:t.pathname,search:t.search,hash:t.hash}},push:function(t,n){f=e.Push;let o=u(C.location,t,n);r&&r(o,t),m=y()+1;let i=l(o,m),s=C.createHref(o);try{h.pushState(i,"",s)}catch(e){p.location.assign(s)}d&&g&&g({action:f,location:C.location,delta:1})},replace:function(t,n){f=e.Replace;let o=u(C.location,t,n);r&&r(o,t),m=y();let i=l(o,m),s=C.createHref(o);h.replaceState(i,"",s),d&&g&&g({action:f,location:C.location,delta:0})},go:e=>h.go(e)};return C}((function(e,t){let{pathname:n,search:r,hash:o}=e.location;return u("",{pathname:n,search:r,hash:o},t.state&&t.state.usr||null,t.state&&t.state.key||"default")}),(function(e,t){return"string"==typeof t?t:c(t)}),null,t)}({window:void 0}),hydrationData:function(){var e;let t=null==(e=window)?void 0:e.__staticRouterHydrationData;return t&&t.errors&&(t=Ke({},t,{errors:Ye(t.errors)})),t}(),routes:ho,mapRouteProperties:function(e){let n={hasErrorBoundary:null!=e.ErrorBoundary||null!=e.errorElement};return e.Component&&Object.assign(n,{element:t.createElement(e.Component),Component:void 0}),e.ErrorBoundary&&Object.assign(n,{errorElement:t.createElement(e.ErrorBoundary),ErrorBoundary:void 0}),n}}).initialize());const go=function(){return t.createElement("div",{className:"app"},t.createElement(Fn,null,t.createElement(co,null),t.createElement(We,{router:fo})))};var mo=document.getElementById("root");(0,r.s)(mo).render(t.createElement(t.StrictMode,null,t.createElement(go,null)))})()})(); \ No newline at end of file diff --git a/setup.py b/setup.py index 4f52031e10b05f510ad50b9f2c7d774ed473d480..a4b2767488b4c29be01dddaae807006fb5b0b708 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup, find_packages setup( name='compendium-v2', - version="0.31", + version="0.32", author='GEANT', author_email='swd@geant.org', description='Flask and React project for displaying ' diff --git a/survey-frontend/src/Landing.tsx b/survey-frontend/src/Landing.tsx index 3203f838152008834290fb68042382bbfd2985d9..16ba71a9d95c3d4609dfddff61c723750ad3701e 100644 --- a/survey-frontend/src/Landing.tsx +++ b/survey-frontend/src/Landing.tsx @@ -28,10 +28,10 @@ function Landing(): ReactElement { <div className="wordwrap pt-4" style={{ maxWidth: '75rem' }}> <p style={{ textAlign: "left" }}> Hello, - <br />Welcome to the GÉANT Compendium Survey. NREN Compendium administrators can login via Single Sign On (SSO) <a href="/login">here</a>, which will complete their registration to fill in the 2023 Compendium survey. - This will send a notification to the Compendium administration team and they will assign you to your NREN. + <br />Welcome to the GÉANT Compendium Survey. (N)REN Compendium administrators can login via Single Sign On (SSO) <a href="/login">here</a>, which will complete their registration to fill in the 2023 Compendium survey. + This will send a notification to the Compendium administration team and they will assign you to your (N)REN. <br />Once this step has been completed, you will receive an email from the administration team. We aim to get back to you the same working day, but sometimes may take a little longer. - <br />If you are not sure whether you are a Compendium Administrator for your NREN, please contact your GÉANT Partner Relations relationship manager. + <br />If you are not sure whether you are a Compendium Administrator for your (N)REN, please contact your GÉANT Partner Relations relationship manager. <br />Thank you. </p> diff --git a/test/test_send_mail.py b/test/test_send_mail.py index a1725367f4f4230b769f6338760c10c5d48c8d1f..e3ae5a9e448b4e1a2e11ab74d1624d64b49543d0 100644 --- a/test/test_send_mail.py +++ b/test/test_send_mail.py @@ -1,16 +1,36 @@ -from compendium_v2.email import send_mail +from contextlib import contextmanager +from compendium_v2.db.auth_model import User +from compendium_v2.email import send_admin_signup_notification, send_user_signup_notification -def test_email(app, mocked_admin_user, mocker): - - def _send_mail(*args, **kwargs): - pass - - mocker.patch('compendium_v2.email._send_mail', _send_mail) +@contextmanager +def test_user(app): with app.app_context(): app.config['MAIL_ENABLE'] = True app.config['MAIL_SERVER'] = 'localhost' app.config['MAIL_PORT'] = 54655 app.config['MAIL_SENDER_EMAIL'] = 'fakesender123@test.local' app.config['MAIL_EXCLUDED_ADMINS'] = [] - send_mail('testmail321') + user = User(fullname='testname', email='testmail321@email.com', oidc_sub='testsub') + yield user + + +def test_signup_email_admin(app, mocked_admin_user, mocker): + + def _send_mail(*args, **kwargs): + message = 'testname has just signed up with the email testmail321@email.com and provider ID testsub' + assert args[-1].split('\n\n')[-1] == message + + mocker.patch('compendium_v2.email._send_mail', _send_mail) + with test_user(app) as user: + send_admin_signup_notification(user) + + +def test_signup_email_user(app, mocker): + + def _send_mail(*args, **kwargs): + assert len(args[-1].split('\n\n', 1)[-1]) > 50 # check that there's a message + + mocker.patch('compendium_v2.email._send_mail', _send_mail) + with test_user(app) as user: + send_user_signup_notification(user, 'testname')