unleash-server
Version:
Unleash is an enterprise ready feature flag service. It provides different strategies for handling feature flags.
689 lines (589 loc) • 49.7 kB
JavaScript
import{n as e,s as t,t as n}from"./jsx-runtime-ButemYzH.js";import{$l as r,$r as i,$u as a,Ac as o,Al as s,Br as c,Cd as l,Co as u,Dd as d,Ea as f,Gr as p,Gu as m,H as h,Hr as g,Iu as _,Ji as v,Kn as y,La as b,Ls as x,Ml as S,Mo as ee,Ms as te,Na as ne,Nc as re,Ns as C,Nu as w,Ol as T,Ot as ie,Ps as E,Qu as D,Rl as ae,Ss as oe,Ts as se,Ua as ce,Ur as le,Vr as ue,Wa as O,Wo as de,Xr as fe,Xu as k,Yi as pe,Yl as me,Yr as he,Yu as A,Zi as ge,Zr as _e,_a as ve,_d as j,_o as M,aa as ye,ad as be,ca as xe,da as Se,fa as Ce,fr as we,fs as Te,ga as Ee,gs as De,ha as Oe,ia as ke,ja as Ae,ji as je,kc as N,kl as P,la as Me,lc as Ne,ll as Pe,ma as Fe,nd as Ie,nf as Le,oa as Re,oi as ze,pa as Be,qi as Ve,qn as He,qu as Ue,rd as F,ru as We,sa as Ge,ua as Ke,us as qe,uu as Je,va as Ye,xd as I,yi as Xe,yu as Ze,zi as L,zr as Qe}from"./index-B0RbDPtk.js";var R=n(),$e=j((0,R.jsx)(`path`,{d:`M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2m-2 10H7v-2h10z`}),`IndeterminateCheckBox`),et=Ie(),tt=({options:e,selectedOptions:t,indeterminateOptions:n,tagType:i,existingTags:o,disabled:s=!1,onChange:c})=>{let l=(0,R.jsx)(He,{fontSize:`small`});return(0,R.jsx)(a,{multiple:!0,id:`checkboxes-tag`,sx:{marginTop:e=>e.spacing(2),width:500},disableCloseOnSelect:!0,options:e,value:t,isOptionEqualToValue:(e,t)=>t.inputValue&&t.inputValue!==``?e.title===t.inputValue:e.title===t.title,getOptionLabel:e=>e.inputValue?e.inputValue:e.title,renderOption:({key:e,...t},i,{selected:a})=>{let o=n?.some(e=>e.title===i.title)??!1;return(0,R.jsxs)(`li`,{...t,children:[(0,R.jsx)(r,{condition:!!i.inputValue,show:(0,R.jsx)(b,{sx:{mr:e=>e.spacing(.5)}}),elseShow:(0,R.jsx)(Ue,{icon:l,checkedIcon:(0,R.jsx)(y,{fontSize:`small`}),indeterminateIcon:(0,R.jsx)($e,{fontSize:`small`}),sx:{mr:e=>e.spacing(.5)},checked:a&&!o,indeterminate:o})}),i.title]},e)},filterOptions:(e,t)=>{let n=t.inputValue.trim(),r=et(e,{...t,inputValue:n}),i=e.some(e=>n===e.title);return n.length>=2&&!i&&r.push({inputValue:n,title:`Create new value "${n}"`}),r},ListboxProps:{style:{maxHeight:200,overflow:`auto`}},onChange:c,renderInput:e=>(0,R.jsx)(Je,{...e,label:`Select values`,placeholder:`Select values`}),disabled:s})},nt=I(`li`)({flexDirection:`column`}),rt=({options:e,value:t,disabled:n=!1,onChange:r})=>{let i=l();return(0,R.jsx)(a,{disablePortal:!0,disabled:n,id:`tag-type-select`,sx:{marginTop:e=>e.spacing(2),width:500},options:e,disableClearable:!0,value:t,getOptionLabel:e=>e.name,renderOption:({key:e,...t},n)=>(0,R.jsxs)(nt,{...t,style:{alignItems:`flex-start`,gap:i.spacing(.5)},children:[(0,R.jsx)(F,{variant:`body1`,children:n.name}),(0,R.jsx)(F,{variant:`caption`,children:n.description})]},e),renderInput:e=>(0,R.jsx)(Je,{...e,label:`Tag type`,value:t}),onChange:r,ListboxProps:{style:{maxHeight:200,overflow:`auto`}}})},it=()=>{let{makeRequest:e,createRequest:t,errors:n,loading:r}=te({propagateErrors:!0});return{createTag:async n=>{let r=t(`api/admin/tags`,{method:`POST`,body:JSON.stringify(n)});return e(r.caller,r.id)},bulkUpdateTags:async(n,r)=>{let i=t(`api/admin/projects/${r}/tags`,{method:`PUT`,body:JSON.stringify(n)});return e(i.caller,i.id)},errors:n,loading:r}},z=t(e()),at=(e,t={})=>{let n=async()=>{let t=T(`api/admin/tags/${e}`);return(await fetch(t,{method:`GET`}).then(o(`Tags`))).json()},r=`api/admin/tags/${e}`,{data:i,error:a}=oe(!!e,{tags:[]},r,n,t),[s,c]=(0,z.useState)(!a&&!i);return(0,z.useEffect)(()=>{c(!a&&!i)},[i,a]),{tags:i?.tags||[],error:a,loading:s,refetch:()=>{S(r)}}},ot=(e,t)=>{let{project:n,refetch:r}=u(e);return{defaultStrategyFallback:{name:`flexibleRollout`,constraints:[],parameters:{rollout:`100`,stickiness:n.defaultStickiness||`default`,groupId:``}},strategy:n.environments?.find(e=>e.environment===t)?.defaultStrategy,refetch:r}},st=()=>{let e=ne(`projectId`),t=i(`environmentId`),{refetch:n}=u(e),{defaultStrategyFallback:r,strategy:a,refetch:o}=ot(e,t),[s,c]=(0,z.useState)(a||r),{updateDefaultStrategy:l,loading:d}=Xe(),{strategyDefinition:f}=fe(s.name),{setToastData:p,setToastApiError:m}=E(),h=_e(),{uiConfig:g}=N(),{unleashUrl:_}=g,v=Le(),{trackEvent:y}=x(),b=ue(s.constraints);if(!f)return null;let S=ct(s);return(0,R.jsx)(Ve,{modal:!0,disablePadding:!0,description:ut,documentationLink:dt,documentationLinkLabel:ft,formatApiCode:()=>lt(e,t,S,f,_),children:(0,R.jsxs)(we,{strategy:s,setStrategy:c,strategyDefinition:f,errors:h,groupIdTooltip:`Defaults to the feature flag name if not set.`,onSubmit:async()=>{let r=`/projects/${e}/settings/default-strategy`;try{await l(e,t,S),y(`default_strategy`,{props:{action:`edit`,hasTitle:!!S.title}}),n(),p({text:`Default Strategy updated`,type:`success`}),await o(),v(r)}catch(e){m(C(e))}},children:[(0,R.jsx)(M,{permission:[ee,de],projectId:e,environmentId:t,variant:`contained`,color:`primary`,type:`submit`,disabled:d||!b||h.hasFormErrors(),"data-testid":Pe,children:`Save strategy`}),(0,R.jsx)(A,{type:`button`,onClick:()=>v(`/projects/${e}/settings/default-strategy`),children:`Cancel`})]})})},ct=e=>({name:e.name,title:e.title,constraints:e.constraints??[],parameters:Object.fromEntries(Object.entries(e.parameters??{}).filter(([,e])=>e!==void 0).map(([e,t])=>[e,String(t)])),variants:e.variants??[],segments:e.segments??[],disabled:e.disabled??!1}),lt=(e,t,n,r,i)=>{if(!i)return``;let a={...n,parameters:he(n.parameters??{},r)};return`curl --location --request POST '${`${i}/api/admin/projects/${e}/environments/${t}/default-strategy`}' \\
--header 'Authorization: INSERT_API_KEY' \\
--header 'Content-Type: application/json' \\
--data-raw '${JSON.stringify(a,void 0,2)}'`},ut=`
An activation strategy will only run when a feature flag is enabled and provides a way to control who will get access to the feature.
If any of a feature flag's activation strategies returns true, the user will get access.
`,dt=`https://docs.getunleash.io/concepts/projects#project-default-strategy`,ft=`Default strategy documentation`,pt=e=>{let{data:t,error:n,mutate:r}=s(T(`api/admin/environments/project/${e}`),mt);return{environments:(0,z.useMemo)(()=>t||[],[t]),refetchEnvironments:(0,z.useCallback)(async()=>{await r()},[r]),loading:!n&&!t,error:n}},mt=async e=>(await fetch(e).then(o(`Environments`)).then(e=>e.json())).environments.sort((e,t)=>e.sortOrder-t.sortOrder),ht=e=>{let{setToastData:t,setToastApiError:n}=E(),{addChange:r}=p(),{refetch:i}=le(e),[a,o]=(0,z.useState)(!1),[s,c]=(0,z.useState)({isOpen:!1});return{pending:a,onChangeRequestToggle:(0,z.useCallback)((e,t,n,r)=>{c({featureName:e,environment:t,enabled:n,shouldActivateDisabledStrategies:r,isOpen:!0})},[]),onChangeRequestToggleClose:(0,z.useCallback)(()=>{c(e=>({...e,isOpen:!1}))},[]),onChangeRequestToggleConfirm:(0,z.useCallback)(async()=>{try{o(!0),await r(e,s.environment,{feature:s.featureName,action:`updateEnabled`,payload:{enabled:!!s.enabled,shouldActivateDisabledStrategies:!!s.shouldActivateDisabledStrategies}}),i(),c(e=>({...e,isOpen:!1})),t({type:`success`,text:`Changes added to draft`})}catch(e){n(C(e)),c(e=>({...e,isOpen:!1}))}finally{o(!1)}},[r]),changeRequestDialogDetails:s}},gt=({enabled:e,featureName:t,environment:n})=>(0,R.jsxs)(F,{"data-testid":`update-enabled-message`,children:[(0,R.jsx)(`strong`,{children:e?`Enable`:`Disable`}),` feature flag`,` `,(0,R.jsx)(`strong`,{children:t}),` in `,(0,R.jsx)(`strong`,{children:n})]}),_t=I(`ul`)(({theme:e})=>({margin:e.spacing(1),paddingLeft:e.spacing(2)})),vt=({isOpen:e,onAddDefaultStrategy:t,onActivateDisabledStrategies:n,onClose:r,environment:i,featureId:a})=>{let o=ne(`projectId`),{feature:s}=ce(o,a),c=s.environments?.find(({name:e})=>e===i)?.strategies?.filter(({disabled:e})=>e).length,l=c?c===1?`1 disabled strategy`:`${c} disabled strategies`:`disabled strategies`;return(0,R.jsxs)(se,{open:e,secondaryButtonText:`Cancel`,permissionButton:(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(M,{type:`button`,variant:`outlined`,permission:qe,projectId:o,environmentId:i,onClick:t,children:`Add default strategy`}),(0,R.jsx)(M,{type:`button`,variant:`outlined`,permission:qe,projectId:o,environmentId:i,onClick:n,children:`Enable all strategies`})]}),onClose:r,title:`Enable feature flag in ${i}`,fullWidth:!0,children:[(0,R.jsx)(F,{sx:{mb:e=>e.spacing(3)},children:`A feature flag cannot be enabled without an enabled strategy.`}),(0,R.jsx)(F,{children:`To enable this feature flag you can choose to:`}),(0,R.jsxs)(_t,{children:[(0,R.jsx)(`li`,{children:(0,R.jsx)(F,{children:(0,R.jsx)(`strong`,{children:`Add the default strategy`})})}),(0,R.jsx)(`li`,{children:(0,R.jsxs)(F,{children:[(0,R.jsx)(`strong`,{children:`Enable all the disabled strategies`}),` `,`(this feature flag has `,l,`)`]})})]})]})},yt=e=>{let t=n=>{n<e.length&&e[n](()=>t(n+1))};t(0)},bt=e=>{let{toggleFeatureEnvironmentOn:t,toggleFeatureEnvironmentOff:n}=g(),{setToastData:i,setToastApiError:a}=E(),[o,s]=(0,z.useState)({open:!1,label:``,loading:!1,onClose:()=>{},onClick:()=>{}}),[l,u]=(0,z.useState)({isOpen:!1,environment:``,featureId:``,onClose:()=>{},onActivateDisabledStrategies:()=>{},onAddDefaultStrategy:()=>{}}),{pending:d,onChangeRequestToggle:f,onChangeRequestToggleClose:p,onChangeRequestToggleConfirm:m,changeRequestDialogDetails:_}=ht(e),[v,y]=(0,z.useState)(),b=(0,z.useCallback)(async(e,r)=>{let o=!1;return yt([t=>{if(r.isChangeRequestEnabled||!c(r.environmentType||``))return t();s({open:!0,label:`${e?`Enable`:`Disable`} Environment`,loading:!1,onClose:()=>{s(e=>({...e,open:!1})),r.onRollback?.()},onClick:()=>{s(e=>({...e,open:!1,loading:!0})),t()}})},t=>{if(e===!1||!r.hasStrategies||r.hasEnabledStrategies||r.hasReleasePlans)return t();u({isOpen:!0,environment:r.environmentName,featureId:r.featureId,onClose:()=>{u(e=>({...e,isOpen:!1})),r.onRollback?.()},onActivateDisabledStrategies:()=>{u(e=>({...e,isOpen:!1})),o=!0,t()},onAddDefaultStrategy:()=>{u(e=>({...e,isOpen:!1})),t()}})},t=>{if(!r.isChangeRequestEnabled)return t();y(()=>{y(void 0),r.onRollback?.()}),f(r.featureId,r.environmentName,e,o)},async t=>{if(e!==!1)return t();try{await n(r.projectId,r.featureId,r.environmentName),i({type:`success`,text:`Disabled in ${r.environmentName}`}),r.onSuccess?.()}catch(e){a(C(e)),r.onRollback?.()}},async n=>{if(e!==!0)return n();try{await t(r.projectId,r.featureId,r.environmentName,o),i({type:`success`,text:`Enabled in ${r.environmentName}`}),r.onSuccess?.()}catch(e){a(C(e)),r.onRollback?.()}}])},[s]),x=l.featureId.length!==0;return{onToggle:b,modals:(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(Qe,{...o}),(0,R.jsx)(r,{condition:x,show:(0,R.jsx)(vt,{...l})}),(0,R.jsx)(h,{isOpen:_.isOpen,onClose:()=>{v?.(),p()},environment:_?.environment,disabled:d,onConfirm:()=>{v?.(),m()},messageComponent:(0,R.jsx)(gt,{enabled:_?.enabled,featureName:_?.featureName,environment:_.environment})})]})}},xt=e=>{let[t,n]=(0,z.useState)(e),r=(0,z.useCallback)(()=>n(e),[e]);return(0,z.useEffect)(()=>{n(e)},[e]),[t,n,r]},St=I(k)(()=>({mx:`auto`,...We})),Ct=({projectId:e,featureId:t,environmentName:n,value:r,onToggle:i})=>{let[a,o,s]=xt(r),c=()=>{o(!a),requestAnimationFrame(()=>{i(!a,s)})},l=`${t}-${n}`;return(0,R.jsx)(R.Fragment,{children:(0,R.jsx)(St,{"data-testid":`TOGGLE-${l}`,children:(0,R.jsx)(f,{tooltip:a?`Disable flag in ${n}`:`Enable flag in ${n}`,checked:r,environmentId:n,projectId:e,permission:Te,inputProps:{"aria-label":n},onClick:c,"data-testid":`permission-switch`,disabled:r!==a})},l)})},wt=j((0,R.jsx)(`path`,{d:`M16 11h-1V3c0-1.1-.9-2-2-2h-2c-1.1 0-2 .9-2 2v8H8c-2.76 0-5 2.24-5 5v7h18v-7c0-2.76-2.24-5-5-5m3 10h-2v-3c0-.55-.45-1-1-1s-1 .45-1 1v3h-2v-3c0-.55-.45-1-1-1s-1 .45-1 1v3H9v-3c0-.55-.45-1-1-1s-1 .45-1 1v3H5v-5c0-1.65 1.35-3 3-3h8c1.65 0 3 1.35 3 3z`}),`CleaningServices`),Tt=`flag-reminders:v1`,Et=50,Dt=7,Ot=({days:e=Dt,maxReminders:t=Et}={})=>{let[n,r]=Ne(Tt,{});return{shouldShowReminder:e=>{let t=n[e];return!t||ae(new Date,new Date(t))},snoozeReminder:(n,i=e)=>{let a=me(new Date,i).getTime();r(e=>{let r={...e,[n]:a},i=Object.entries(r);if(i.length>t){i.sort((e,t)=>e[1]-t[1]);let e=i.slice(i.length-t);return Object.fromEntries(e)}return r})}}},kt=(e,t={})=>{let{data:n,error:r,mutate:i}=s(T(`api/admin/projects/${e}/api-tokens`),At,t),a=(0,z.useMemo)(()=>n??[],[n]),o=(0,z.useCallback)(()=>{i().catch(console.warn)},[i]);return{tokens:a,error:r,loading:!r&&!n,refetch:o}},At=async e=>(await(await fetch(e).then(o(`Project Api tokens`))).json()).tokens,jt=()=>{let{makeRequest:e,createRequest:t,errors:n,loading:r}=te({propagateErrors:!0});return{deleteToken:async(n,r)=>{let i=t(`api/admin/projects/${r}/api-tokens/${n}`,{method:`DELETE`});return e(i.caller,i.id)},createToken:async(n,r)=>{let i=t(`api/admin/projects/${r}/api-tokens`,{method:`POST`,body:JSON.stringify(n)});return e(i.caller,i.id)},errors:n,loading:r}},Mt=e=>{if(!e)return null;let[t,n]=e.split(`:`,2);if(!n)return null;let[r,i,...a]=n.split(`.`);return t&&r&&i&&a.length===0?{project:t,environment:r,secret:i}:null},B=ie(),V=I(`div`)(({theme:e})=>({fontWeight:e.typography.fontWeightBold,marginBottom:e.spacing(1),fontSize:e.typography.body1.fontSize})),H=I(`div`)(({theme:e})=>({display:`flex`,alignItems:`center`,justifyContent:`space-between`,marginTop:e.spacing(2)})),Nt=I(`div`)(({theme:e})=>({display:`flex`,gap:e.spacing(1)})),Pt=I(`div`)(({theme:e})=>({background:e.palette.background.application,borderRadius:e.shape.borderRadius,width:e.spacing(7),height:e.spacing(1)})),Ft=I(`div`)(({theme:e})=>({background:e.palette.background.sidebar,borderRadius:e.shape.borderRadius,width:e.spacing(7),height:e.spacing(1)})),U=({active:e,steps:t})=>(0,R.jsx)(Nt,{children:Array.from({length:t},(t,n)=>n===e?(0,R.jsx)(Ft,{},n):(0,R.jsx)(Pt,{},n))}),It=({environments:e,onSelect:t,currentEnvironment:n})=>{let r=Math.max(...e.map(e=>e.length));return(0,R.jsx)(ze,{tooltip:{header:``},description:`Select the environment where the API key will be created`,options:e.map(e=>({label:e,value:e})),onChange:e=>{t(e)},button:{label:n,icon:(0,R.jsx)(De,{}),labelWidth:`${r+5}ch`},search:{label:`Filter project mode options`,placeholder:`Select project mode`}})},Lt=I(`div`)(({theme:e})=>({backgroundColor:e.palette.background.elevation1,borderRadius:e.shape.borderRadius,padding:e.spacing(3),display:`flex`,flexDirection:`column`,alignItems:`center`})),W=I(`div`)(({theme:e})=>({backgroundColor:e.palette.background.paper,borderRadius:e.shape.borderRadius,padding:e.spacing(2),flex:1,color:e.palette.text.secondary,fontSize:e.typography.body2.fontSize})),Rt=I(k)(({theme:e})=>({display:`flex`,gap:e.spacing(2),alignItems:`flex-start`,marginTop:e.spacing(8),flexWrap:`wrap`})),G=I(`p`)(({theme:e})=>({color:e.palette.text.secondary,fontSize:e.typography.body2.fontSize,marginBottom:e.spacing(2)})),zt=I(`div`)(({theme:e})=>({padding:e.spacing(5,8,3,8),display:`flex`,flexDirection:`column`,gap:e.spacing(3)})),Bt=({project:e,environment:t,secret:n})=>{let r=l(),i=_(r.breakpoints.up(`lg`));return(0,R.jsx)(B.ArcherContainer,{strokeColor:r.palette.secondary.border,endMarker:!1,lineStyle:`curve`,children:(0,R.jsxs)(Lt,{children:[(0,R.jsxs)(k,{sx:{wordBreak:`break-all`},children:[(0,R.jsx)(B.ArcherElement,{id:`project`,children:(0,R.jsx)(`span`,{children:e})}),`:`,(0,R.jsx)(B.ArcherElement,{id:`environment`,children:(0,R.jsx)(`span`,{children:t})}),`.`,(0,R.jsx)(B.ArcherElement,{id:`secret`,children:(0,R.jsx)(`span`,{children:n})})]}),i?(0,R.jsxs)(Rt,{children:[(0,R.jsx)(B.ArcherElement,{id:`project-description`,relations:[{targetId:`project`,targetAnchor:`bottom`,sourceAnchor:`top`}],children:(0,R.jsx)(W,{children:`The project this API key can retrieve feature flags from`})}),(0,R.jsx)(B.ArcherElement,{id:`environment-description`,relations:[{targetId:`environment`,targetAnchor:`bottom`,sourceAnchor:`top`}],children:(0,R.jsx)(W,{children:`The environment this API key can retrieve feature flag configuration from`})}),(0,R.jsx)(B.ArcherElement,{id:`secret-description`,relations:[{targetId:`secret`,targetAnchor:`right`,sourceAnchor:`top`}],children:(0,R.jsx)(W,{children:`The API key secret`})})]}):null]})})},Vt=({environments:e,environment:t,project:n,sdkType:r,onEnvSelect:i,onApiKey:a})=>{let{trackEvent:o}=x(),{tokens:s,refetch:c}=kt(n),{createToken:l,loading:u}=jt(),d=s.find(e=>e.environment===t&&e.type===r);(0,z.useEffect)(()=>{a(d?.secret||null)},[d]);let f=Mt(d?.secret),{setToastApiError:p}=E(),m=async()=>{try{await l({environment:t,type:r,projects:[n],tokenName:`api-key-${n}-${t}`},n),c(),h()}catch(e){p(C(e))}},h=()=>{o(`onboarding`,{props:{eventType:`api-key-generated`}})};return(0,R.jsxs)(zt,{children:[(0,R.jsx)(F,{variant:`h2`,children:`Connect an SDK to Unleash`}),(0,R.jsxs)(H,{children:[(0,R.jsx)(U,{active:1,steps:3}),(0,R.jsx)(O,{color:`secondary`,children:`2/3 - Generate API Key`})]}),(0,R.jsxs)(k,{sx:{mt:2},children:[(0,R.jsx)(V,{children:`Environment`}),(0,R.jsx)(G,{children:`The environment the SDK connects to to retrieve configuration.`}),e.length>0?(0,R.jsx)(It,{environments:e,currentEnvironment:t,onSelect:i}):null]}),(0,R.jsxs)(k,{sx:{mt:3},children:[(0,R.jsx)(V,{children:`API Key`}),f?(0,R.jsxs)(G,{children:[`Here is your generated API key. We will use it to connect to the `,(0,R.jsx)(`b`,{children:f.project}),` project in the `,(0,R.jsx)(`b`,{children:f.environment}),` environment.`]}):(0,R.jsx)(G,{children:`You currently have no active API keys for this project/environment combination. Generate an API key to proceed with connecting your SDK.`}),f?(0,R.jsx)(Bt,{project:f.project,environment:f.environment,secret:f.secret}):(0,R.jsx)(A,{variant:`contained`,disabled:u,onClick:m,children:`Generate API Key`})]})]})},Ht=[{name:`Node.js`,icon:Se},{name:`Go`,icon:Oe},{name:`Ruby`,icon:Ge},{name:`PHP`,icon:Ke},{name:`Rust`,icon:Re},{name:`.NET`,icon:ve},{name:`Java`,icon:Be},{name:`Python`,icon:Me}],K=[{name:`JavaScript`,icon:Ce},{name:`React`,icon:xe},{name:`Vue`,icon:ke},{name:`Svelte`,icon:ye},{name:`Swift`,icon:Fe},{name:`Android`,icon:Ye},{name:`Flutter`,icon:Ee}],Ut=[...Ht,...K],Wt=I(`div`)(({theme:e})=>({padding:e.spacing(5,8,8,8),display:`flex`,flexDirection:`column`,gap:e.spacing(3)})),q=I(`div`)(({theme:e})=>({marginTop:e.spacing(4),marginBottom:e.spacing(2),fontSize:e.typography.body1.fontSize})),Gt=I(`div`)(({theme:e})=>({backgroundColor:e.palette.background.elevation1,borderRadius:e.shape.borderRadius,padding:e.spacing(6),display:`flex`,columnGap:e.spacing(2),rowGap:e.spacing(5),alignItems:`center`,justifyContent:`flex-start`,flexWrap:`wrap`})),Kt=I(`div`)(({theme:e})=>({fontSize:e.typography.body2.fontSize,backgroundColor:e.palette.background.default,borderRadius:e.shape.borderRadius,padding:e.spacing(2,3),width:`170px`,position:`relative`})),qt=I(`div`)(()=>({display:`flex`,justifyContent:`space-between`})),Jt=I(D)(({theme:e})=>({position:`absolute`,width:e.spacing(4),height:e.spacing(4),top:e.spacing(-2.75),left:e.spacing(2),boxShadow:e.shadows[2]})),Yt=({onSelect:e})=>(0,R.jsxs)(Wt,{children:[(0,R.jsx)(F,{variant:`h2`,children:`Connect an SDK to Unleash`}),(0,R.jsxs)(H,{children:[(0,R.jsx)(U,{active:0,steps:3}),(0,R.jsx)(O,{color:`secondary`,children:`1/3 - Choose SDK`})]}),(0,R.jsxs)(k,{sx:{mt:2},children:[(0,R.jsx)(V,{children:`Select SDK`}),(0,R.jsx)(q,{children:`Server side SDKs`}),(0,R.jsx)(Gt,{children:Ht.map(t=>(0,R.jsxs)(Kt,{children:[(0,R.jsx)(Jt,{src:P(t.icon)}),(0,R.jsxs)(qt,{children:[(0,R.jsx)(`b`,{children:t.name}),` `,(0,R.jsx)(w,{onClick:()=>e({name:t.name,type:`client`}),component:`button`,children:`Select`})]})]},t.name))}),(0,R.jsx)(q,{children:`Client side SDKs`}),(0,R.jsx)(Gt,{children:K.map(t=>(0,R.jsxs)(Kt,{children:[(0,R.jsx)(Jt,{src:P(t.icon)}),(0,R.jsxs)(qt,{children:[(0,R.jsx)(`b`,{children:t.name}),` `,(0,R.jsx)(w,{onClick:()=>e({name:t.name,type:`frontend`}),component:`button`,children:`Select`})]})]},t.name))})]})]}),Xt=I(`div`)(({theme:e})=>({backgroundColor:e.palette.background.sidebar,padding:e.spacing(12,6,6,6),flex:0,minWidth:`400px`})),J=I(`p`)(({theme:e})=>({color:e.palette.primary.contrastText,fontSize:e.typography.caption.fontSize,marginBottom:e.spacing(2)})),Y=({theme:e})=>({color:e.palette.primary.contrastText,fontSize:e.typography.body2.fontSize,marginTop:e.spacing(.5)}),Zt=I(re)(Y),Qt=I(De)(Y),$t=I(Ae)(Y),X=I(`div`)(({theme:e})=>({display:`flex`,gap:e.spacing(1.5),alignItems:`flex-start`,marginTop:e.spacing(3)})),Z=I(`div`)(({theme:e})=>({color:e.palette.primary.contrastText,fontSize:e.typography.body2.fontSize,fontWeight:e.typography.fontWeightBold,marginBottom:e.spacing(2)})),en=()=>(0,R.jsxs)(Xt,{children:[(0,R.jsxs)(X,{children:[(0,R.jsx)(Zt,{}),(0,R.jsxs)(k,{children:[(0,R.jsx)(Z,{children:`Flags live in projects`}),(0,R.jsx)(J,{children:`Projects are containers for feature flags. Each flag belongs to the project where you create it.`})]})]}),(0,R.jsxs)(X,{children:[(0,R.jsx)(Qt,{}),(0,R.jsxs)(k,{children:[(0,R.jsx)(Z,{children:`Flags have configuration in environments`}),(0,R.jsx)(J,{children:`You can have multiple environments, and each feature flag has a different configuration per environment.`})]})]}),(0,R.jsxs)(X,{children:[(0,R.jsx)($t,{}),(0,R.jsxs)(k,{children:[(0,R.jsx)(Z,{children:`SDKs connect to Unleash to retrieve configuration`}),(0,R.jsx)(J,{children:`When you connect an SDK to Unleash, it uses the API key to identify which feature flags and configuration to retrieve from each environment.`})]})]})]}),tn=()=>(0,R.jsx)(Xt,{children:(0,R.jsxs)(X,{children:[(0,R.jsx)($t,{}),(0,R.jsxs)(k,{children:[(0,R.jsx)(Z,{children:`SDKs and Unleash`}),(0,R.jsx)(J,{children:`SDKs serve to bind your application to Unleash. The SDK can connect to Unleash via HTTP and retrieve feature flag configuration that is then cached in your application. Making sure none of your application data ever leaves your servers.`})]})]})}),nn=I(D,{shouldForwardProp:e=>e!==`active`})(({theme:e,active:t})=>({transition:`background-color 0.5s ease`,color:e.palette.common.white,backgroundColor:t?e.palette.primary.main:e.palette.divider,"@keyframes pulse":{"0%":{boxShadow:`0 0 0 0px ${d(e.palette.primary.main,.7)}`},"100%":{boxShadow:`0 0 0 20px ${d(e.palette.primary.main,0)}`}},animation:t?`pulse 2s infinite`:``})),rn=I(D,{shouldForwardProp:e=>e!==`active`})(({theme:e,active:t})=>({transition:`background-color 0.5s ease`,color:e.palette.primary.main,backgroundColor:t?e.palette.background.default:e.palette.divider,"@keyframes pulse":{"0%":{boxShadow:`0 0 0 0px ${d(e.palette.background.default,.7)}`},"100%":{boxShadow:`0 0 0 20px ${d(e.palette.background.default,0)}`}},animation:t?`pulse 2s infinite`:``})),an=j((0,R.jsx)(`path`,{d:`M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2M7 13.5c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5m5 0c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5m5 0c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5`}),`Pending`),on=I(`div`)(({theme:e})=>({backgroundColor:e.palette.background.sidebar,padding:e.spacing(6,9,6,9),minWidth:`400px`,display:`flex`,flexDirection:`column`,color:e.palette.primary.contrastText})),sn=I(F)(({theme:e})=>({display:`flex`,alignItems:`center`,justifyContent:`center`,fontWeight:e.typography.fontWeightBold})),cn=I(`div`)(({theme:e})=>({display:`flex`,flexDirection:`row`,padding:e.spacing(4,0,12,0),justifyContent:`space-between`,fontSize:e.spacing(1)})),ln=I(`div`)(({theme:e})=>({display:`flex`,gap:e.spacing(1),flexDirection:`column`})),un=I(`div`)(({theme:e})=>({alignItems:`center`,justifyContent:`center`,display:`flex`,gap:e.spacing(2),flexDirection:`column`,fontSize:e.fontSizes.smallBody})),dn=I(je)(({theme:e})=>({color:e.palette.primary.main,backgroundColor:e.palette.background.paper,borderRadius:`50%`,padding:e.spacing(1),width:`80px`,height:`80px`})),fn=({projectId:e,sdk:t,environment:n})=>{let r=l(),{project:i}=u(e,{refreshInterval:1e3}),a=i.onboardingStatus.status===`onboarded`;return(0,R.jsxs)(on,{children:[(0,R.jsx)(sn,{children:`Connection information`}),(0,R.jsxs)(cn,{children:[(0,R.jsxs)(ln,{children:[(0,R.jsx)(F,{fontWeight:`bold`,variant:`body2`,children:`Environment`}),(0,R.jsx)(F,{variant:`body2`,children:n})]}),(0,R.jsxs)(ln,{children:[(0,R.jsx)(F,{fontWeight:`bold`,variant:`body2`,children:`SDK`}),(0,R.jsx)(F,{variant:`body2`,children:t})]})]}),a?(0,R.jsxs)(un,{children:[(0,R.jsx)(F,{fontWeight:`bold`,variant:`body2`,children:`Connection status`}),(0,R.jsx)(F,{sx:{mb:r.spacing(4)},variant:`body2`,children:`Connected`}),(0,R.jsx)(dn,{}),(0,R.jsx)(F,{sx:{mb:r.spacing(4)},variant:`body2`,children:`We received metrics from your application!`})]}):(0,R.jsxs)(un,{children:[(0,R.jsx)(F,{fontWeight:`bold`,variant:`body2`,children:`Connection status`}),(0,R.jsx)(F,{sx:{mb:r.spacing(4)},variant:`body2`,children:`Waiting for SDK data...`}),(0,R.jsx)(rn,{sx:{width:80,height:80},active:!0,children:(0,R.jsx)(an,{fontSize:`large`})})]})]})},pn=t(v()),Q={Android:`1\\. Install the SDK
\`\`\`gradle
implementation("io.getunleash:unleash-android:1")
\`\`\`
2\\. Enable required [permissions](https://developer.android.com/guide/topics/manifest/uses-permission-element)
\`\`\`xml
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
\`\`\`
2\\. Initialize Unleash in your application
\`\`\`kotlin
class MyApplication: Application() {
val unleash: Unleash by lazy {
val instance = DefaultUnleash(
androidContext = this,
unleashConfig = UnleashConfig.newBuilder(appName = "unleash-onboarding-android")
.proxyUrl("<YOUR_API_URL>")
.clientKey("<YOUR_API_TOKEN>")
.build()
)
instance.start()
instance
}
override fun onTerminate() {
super.onTerminate()
unleash.close()
}
}
\`\`\`
3\\. Check flag status
\`\`\`kotlin
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val unleashInstance = (application as MyApplication).unleash
setContent {
var flagStatus by remember { mutableStateOf("loading") }
LaunchedEffect(Unit) {
while (isActive) {
val isFlagEnabled = unleashInstance.isEnabled("<YOUR_FLAG>")
flagStatus = if (isFlagEnabled) "enabled" else "disabled"
delay(3000L)
}
}
Text(text = "Flag is $flagStatus!")
}
}
}
\`\`\`
ℹ️ **Info:** The Android SDK takes at least 60 seconds to post metrics to Unleash.
---
---
- [SDK repository with documentation and example](https://github.com/Unleash/unleash-android)
- [Android SDK basic example](hhttps://github.com/Unleash/unleash-sdk-examples/tree/main/Android)
`,Go:`1\\. Install the SDK
\`\`\`sh
go get github.com/Unleash/unleash-client-go/v4
\`\`\`
2\\. Run Unleash
\`\`\`go
package main
import (
"github.com/Unleash/unleash-client-go/v4"
"net/http"
"time"
)
func init() {
unleash.Initialize(
unleash.WithListener(&unleash.DebugListener{}),
unleash.WithAppName("unleash-onboarding-golang"),
unleash.WithUrl("<YOUR_API_URL>"),
unleash.WithCustomHeaders(http.Header{"Authorization": {"<YOUR_API_TOKEN>"}}), // in production use environment variable
)
}
func main() {
for {
unleash.IsEnabled("<YOUR_FLAG>")
time.Sleep(time.Second)
}
}
\`\`\`
---
\`\`\`go
func init() {
unleash.Initialize(
unleash.WithListener(&unleash.DebugListener{}),
unleash.WithAppName("unleash-onboarding-golang"),
unleash.WithUrl("<YOUR_API_URL>"),
unleash.WithCustomHeaders(http.Header{
"Authorization": {os.Getenv("UNLEASH_API_KEY")},
})
)
}
\`\`\`
---
- [SDK repository with documentation](https://github.com/Unleash/unleash-client-go)
- [Go SDK example with CodeSandbox](https://github.com/Unleash/unleash-sdk-examples/tree/main/Go)
`,JavaScript:`1\\. Install the SDK
\`\`\`sh
npm install unleash-proxy-client
\`\`\`
2\\. Run Unleash
\`\`\`js
const { UnleashClient } = require('unleash-proxy-client');
const unleash = new UnleashClient({
url: '<YOUR_API_URL>',
clientKey: '<YOUR_API_TOKEN>', // in production use environment variable
appName: 'unleash-onboarding-javascript',
});
unleash.start();
setInterval(() => {
console.log('Is enabled', unleash.isEnabled('<YOUR_FLAG>'));
}, 1000);
\`\`\`
---
\`\`\`js
const unleash = new UnleashClient({
url: '<YOUR_API_URL>',
clientKey: process.env.UNLEASH_API_TOKEN,
appName: 'unleash-onboarding-javascript',
});
unleash.start();
\`\`\`
---
- [SDK repository with documentation](https://github.com/Unleash/unleash-proxy-client-js)
- [JavaScript SDK example with CodeSandbox](https://github.com/Unleash/unleash-sdk-examples/tree/main/JavaScript)
`,"Node.js":`1\\. Install the SDK
\`\`\`sh
npm install unleash-client
\`\`\`
2\\. Run Unleash
\`\`\`js
const { initialize } = require('unleash-client');
const unleash = initialize({
url: '<YOUR_API_URL>',
appName: 'unleash-onboarding-node',
customHeaders: {
Authorization: '<YOUR_API_TOKEN>' // in production use environment variable
},
});
setInterval(() => {
console.log('Is enabled', unleash.isEnabled('<YOUR_FLAG>'));
}, 1000);
\`\`\`
---
\`\`\`js
const { initialize } = require('unleash-client');
const unleash = initialize({
url: '<YOUR_API_URL>',
appName: 'unleash-onboarding-node',
customHeaders: { Authorization: process.env.UNLEASH_API_KEY },
});
\`\`\`
---
- [SDK repository with documentation](https://github.com/Unleash/unleash-client-node)
- [Node.js SDK example with CodeSandbox](https://github.com/Unleash/unleash-sdk-examples/tree/main/Node.js)
- [Node.js SDK tutorial](https://dev.to/reeshee/how-to-implement-feature-flags-in-nodejs-using-unleash-3907)
`,Python:`1\\. Install the SDK
\`\`\`sh
pip install UnleashClient
\`\`\`
2\\. Run Unleash
\`\`\`python
from UnleashClient import UnleashClient
import asyncio
client = UnleashClient(
url="<YOUR_API_URL>",
app_name="unleash-onboarding-python",
custom_headers={'Authorization': '<YOUR_API_TOKEN>'}) # in production use environment variable
client.initialize_client()
while True:
print(client.is_enabled("<YOUR_FLAG>"))
asyncio.run(asyncio.sleep(1))
\`\`\`
---
\`\`\`python
from UnleashClient import UnleashClient
import asyncio
import os
client = UnleashClient(
url="<YOUR_API_URL>",
app_name="unleash-onboarding-python",
custom_headers={'Authorization': os.getenv('UNLEASH_API_TOKEN')}
\`\`\`
---
- [SDK repository with documentation](https://github.com/Unleash/unleash-client-python)
- [Python SDK example with CodeSandbox](https://github.com/Unleash/unleash-sdk-examples/tree/main/Python)
- [How to Implement Feature Flags in Python](https://docs.getunleash.io/feature-flag-tutorials/python)
`,Ruby:`1\\. Install the SDK
\`\`\`sh
gem install unleash
\`\`\`
2\\. Run Unleash
\`\`\`rb
require 'unleash'
@unleash = Unleash::Client.new(
url: "<YOUR_API_URL>",
custom_http_headers: { 'Authorization': "<YOUR_API_TOKEN>" }, # in production use environment variable
app_name: 'unleash-onboarding-ruby',
instance_id: 'unleash-onboarding-ruby',
)
while true
if @unleash.is_enabled?("<YOUR_FLAG>")
puts "Flag is enabled"
else
puts "Flag is not enabled"
end
sleep 3
end
\`\`\`
---
\`\`\`rb
@unleash = Unleash::Client.new(
url: "<YOUR_API_URL>",
custom_http_headers: { 'Authorization': ENV['UNLEASH_API_TOKEN'] },
app_name: 'unleash-onboarding-ruby',
instance_id: 'unleash-onboarding-ruby',
)
\`\`\`
---
- [SDK repository with documentation](https://github.com/Unleash/unleash-client-ruby)
- [Ruby example with CodeSandbox](https://github.com/Unleash/unleash-sdk-examples/tree/main/Ruby)
- [How to Implement Feature Flags in Ruby](https://docs.getunleash.io/feature-flag-tutorials/ruby)
`,Svelte:`1\\. Install the SDK
\`\`\`sh
npm install @unleash/proxy-client-svelte
\`\`\`
2\\. Initialize Unleash
\`\`\`svelte
<script>
import { FlagProvider } from '@unleash/proxy-client-svelte';
const config = {
url: '<YOUR_API_URL>',
clientKey: '<YOUR_API_TOKEN>', // in production use environment variable
appName: 'unleash-onboarding-svelte',
};
<\/script>
<div class="app">
<FlagProvider {config}>
<main>
<slot />
</main>
</FlagProvider>
</div>
\`\`\`
3\\. Check feature flag status
\`\`\`svelte
<script lang="ts">
import { useFlag } from '@unleash/proxy-client-svelte';
const enabled = useFlag('<YOUR_FLAG>');
<\/script>
<section>
<p>
{$enabled ? 'Feature is enabled!' : 'Feature is disabled!'}
</p>
</section>
\`\`\`
---
\`\`\`svelte
const config = {
url: '<YOUR_API_URL>',
clientKey: import.meta.env.VITE_UNLEASH_API_TOKEN,
appName: 'unleash-onboarding-svelte',
};
\`\`\`
---
- [SDK repository with documentation](https://github.com/Unleash/proxy-client-svelte)
- [Svelte example with CodeSandbox](https://github.com/Unleash/unleash-sdk-examples/tree/main/Svelte)
- [How to Implement Feature Flags in SvelteKit](https://docs.getunleash.io/feature-flag-tutorials/sveltekit)
`,Vue:`1\\. Install the SDK
\`\`\`sh
npm install @unleash/proxy-client-vue
\`\`\`
2\\. Initialize Unleash
\`\`\`vue
<script setup lang="ts">
import { FlagProvider } from '@unleash/proxy-client-vue'
const config = {
url: '<YOUR_API_URL>',
clientKey: '<YOUR_API_TOKEN>', // in production use environment variable
appName: 'unleash-onboarding-vue',
}
<\/script>
<template>
<FlagProvider :config="config">
<!-- <YourComponent /> -->
</FlagProvider>
</template>
\`\`\`
3\\. Check feature flag status
\`\`\`vue
<script setup lang="ts">
import { useFlag } from '@unleash/proxy-client-vue'
const enabled = useFlag('<YOUR_FLAG>')
<\/script>
<template>
<div>
{{ enabled ? 'Feature is enabled!' : 'Feature is disabled!' }}
</div>
</template>
\`\`\`
---
\`\`\`svelte
const config = {
url: '<YOUR_API_URL>',
clientKey: import.meta.env.VITE_UNLEASH_API_TOKEN,
appName: 'unleash-onboarding-vue',
}
\`\`\`
---
- [SDK repository with documentation](https://github.com/Unleash/proxy-client-vue)
- [Vue example with CodeSandbox](https://github.com/Unleash/unleash-sdk-examples/tree/main/Vue)
`,Flutter:`1\\. Install the SDK
\`\`\`sh
flutter pub add unleash_proxy_client_flutter
\`\`\`
2\\. Run Unleash
\`\`\`dart
import 'package:unleash_proxy_client_flutter/unleash_proxy_client_flutter.dart';
import 'dart:async';
final unleash = UnleashClient(
url: Uri.parse('<YOUR_API_URL>'),
clientKey: '<YOUR_API_TOKEN>', // in production use environment variable
appName: 'unleash-onboarding-flutter');
unleash.start();
Timer.periodic(Duration(seconds: 1), (Timer timer) {
final flagStatus = unleash.isEnabled('<YOUR_FLAG>');
print('Flag is \${unleash.isEnabled("<YOUR_FLAG>") ? "enabled" : "disabled"}');
});
\`\`\`
---
\`\`\`dart
import 'package:unleash_proxy_client_flutter/unleash_proxy_client_flutter.dart';
import 'dart:async';
import 'dart:io';
final unleash = UnleashClient(
url: Uri.parse('<YOUR_API_URL>'),
clientKey: Platform.environment['UNLEASH_CLIENT_KEY']!,
appName: 'unleash-onboarding-flutter');
unleash.start();
\`\`\`
---
- [SDK repository with documentation](https://github.com/Unleash/unleash_proxy_client_flutter)
- [Flutter example with CodeSandbox](https://github.com/Unleash/unleash-sdk-examples/tree/main/Flutter)
- [A/B Testing in Flutter using Unleash and Mixpanel](https://docs.getunleash.io/feature-flag-tutorials/flutter/a-b-testing)
`,Java:`1\\. Install the SDK
\`\`\`xml
<dependency>
<groupId>io.getunleash</groupId>
<artifactId>unleash-client-java</artifactId>
<version>LATEST</version>
</dependency>
\`\`\`
2\\. Run Unleash
\`\`\`java
UnleashConfig config = UnleashConfig.builder()
.appName("unleash-onboarding-java")
.instanceId("unleash-onboarding-instance")
.unleashAPI("<YOUR_API_URL>")
.apiKey("<YOUR_API_TOKEN>") // in production use environment variable
.build();
Unleash unleash = new DefaultUnleash(config);
while (true) {
boolean featureEnabled = unleash.isEnabled("<YOUR_FLAG>");
System.out.println("Feature enabled: " + featureEnabled);
Thread.sleep(1000);
}
\`\`\`
---
\`\`\`java
UnleashConfig config = UnleashConfig.builder()
.appName("unleash-onboarding-java")
.instanceId("unleash-onboarding-instance")
.unleashAPI("<YOUR_API_URL>")
.apiKey(System.getenv("UNLEASH_API_KEY"))
.build();
\`\`\`
---
- [SDK repository with documentation](https://github.com/Unleash/unleash-client-java)
- [Java SDK example with CodeSandbox](https://github.com/Unleash/unleash-sdk-examples/tree/main/Java)
- [How to Implement Feature Flags in Java](https://docs.getunleash.io/feature-flag-tutorials/java)
`,".NET":`1\\. Install the SDK
\`\`\`sh
dotnet add package unleash.client
// If you do not have a json library in your project:
dotnet add package Newtonsoft.Json
\`\`\`
2\\. Initialize Unleash
\`\`\`csharp
using Unleash;
using Unleash.ClientFactory;
public class Program
{
public static async Task Main()
{
var settings = new UnleashSettings()
{
AppName = "unleash-onboarding-dotnet",
UnleashApi = new Uri("<YOUR_API_URL>"),
CustomHttpHeaders = new Dictionary<string, string>()
{
{"Authorization","<YOUR_API_TOKEN>"} // in production use environment variable
}
};
var unleash = new DefaultUnleash(settings);
while (true) {
Console.WriteLine($"Flag is enabled: {unleash.IsEnabled("<YOUR_FLAG>")}");
await Task.Delay(1000);
}
}
}
\`\`\`
---
\`\`\`csharp
var settings = new UnleashSettings()
{
AppName = "unleash-onboarding-dotnet",
UnleashApi = new Uri("<YOUR_API_URL>"),
CustomHttpHeaders = new Dictionary<string, string>()
{
{"Authorization",Environment.GetEnvironmentVariable("UNLEASH_API_KEY")}
}
};
\`\`\`
---
- [SDK repository with documentation](https://github.com/Unleash/unleash-client-dotnet)
- [.NET/C# SDK example with CodeSandbox](https://github.com/Unleash/unleash-sdk-examples/tree/main/Csharp)
`,PHP:`1\\. Install the SDK
\`\`\`sh
composer require unleash/client
\`\`\`
2\\. Initialize Unleash
\`\`\`php
<?php
use Unleash\\\\Client\\\\UnleashBuilder;
require 'vendor/autoload.php';
$unleash = UnleashBuilder::create()
->withAppName('unleash-onboarding-php')
->withAppUrl('<YOUR_API_URL>')
->withHeader('Authorization', '<YOUR_API_TOKEN>') // in production use environment variable
->withInstanceId('unleash-onboarding-instance')
->build();
while (true) {
echo 'Feature flag is: ' . $unleash->isEnabled('<YOUR_FLAG>') . PHP_EOL;
sleep(1);
}
\`\`\`
---
\`\`\`php
$unleash = UnleashBuilder::create()
->withAppName('unleash-onboarding-php')
->withAppUrl('<YOUR_API_URL>')
->withHeader('Authorization', getenv('UNLEASH_API_TOKEN'))
->withInstanceId('unleash-onboarding-instance')
->build();
\`\`\`
---
- [SDK repository with documentation](https://github.com/Unleash/unleash-client-php)
- [PHP SDK example with CodeSandbox](https://github.com/Unleash/unleash-sdk-examples/tree/main/PHP)
`,React:`1\\. Install the SDK
\`\`\`sh
npm install @unleash/proxy-client-react unleash-proxy-client
\`\`\`
2\\. Initialize Unleash
\`\`\`jsx
import { createRoot } from 'react-dom/client';
import { FlagProvider } from '@unleash/proxy-client-react';
const config = {
url: '<YOUR_API_URL>',
clientKey: '<YOUR_API_TOKEN>', // in production use environment variable
appName: 'unleash-onboarding-react',
};
const root = createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<FlagProvider config={config}>
<App />
</FlagProvider>
</React.StrictMode>
);
\`\`\`
3\\. Check feature flag status
\`\`\`jsx
import { useFlag } from '@unleash/proxy-client-react';
const TestComponent = () => {
const enabled = useFlag('<YOUR_FLAG>');
return enabled ? 'Flag is enabled' : 'Flag is disabled'
};
\`\`\`
---
\`\`\`jsx
const config = {
url: '<YOUR_API_URL>',
clientKey: process.env.UNLEASH_API_TOKEN,
appName: 'unleash-onboarding-react',
};
\`\`\`
---
- [SDK repository with documentation](https://github.com/Unleash/proxy-client-react)
- [React SDK example with CodeSandbox](https://github.com/Unleash/unleash-sdk-examples/tree/main/React)
- [https://docs.getunleash.io/feature-flag-tutorials/react](https://docs.getunleash.io/feature-flag-tutorials/react)
`,Rust:`1\\. Install the SDK
\`\`\`sh
cargo add unleash-api-client --features async-std,reqwest,surf
cargo add serde --features derive
cargo add serde reqwest --features json
cargo add serde tokio --features full
cargo add serde anyhow cfg cfg-if enum-map@~2.0.0 surf
\`\`\`
2\\. Run Unleash
\`\`\`rust
use enum_map::Enum;
use serde::{Deserialize, Serialize};
use std::error::Error;
use std::time::Duration;
use tokio::time::sleep;
use unleash_api_client::client::ClientBuilder;
use unleash_api_client::Client;
#[derive(Debug, Deserialize, Serialize, Enum, Clone)]
enum Flags {
#[serde(rename = "<YOUR_FLAG>")]
TestFlag,
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
let client: Client<Flags, reqwest::Client> = ClientBuilder::default()
.into_client(
"<YOUR_API_URL>",
"unleash-onboarding-rust",
"unleash-onboarding-instance",
Some("<YOUR_API_TOKEN>".to_owned()), // in production use environment variable
)?;
client.register().await?;
let (_, _) = tokio::join!(client.poll_for_updates(), async {
sleep(Duration::from_millis(1000)).await;
let is_enabled = client.is_enabled(Flags::TestFlag, None, true);
println!("\\nIs flag enabled: {}\\n", is_enabled);
sleep(Duration::from_millis(5000)).await;
client.stop_poll().await;
Ok::<(), Box<dyn Error + Send + Sync>>(())
});
Ok(())
}
\`\`\`
---
\`\`\`rust
let api_token = env::var("UNLEASH_API_TOKEN").expect("UNLEASH_API_TOKEN environment variable not set");
let client: Client<Flags, reqwest::Client> = ClientBuilder::default()
.into_client(
"<YOUR_API_URL>",
"unleash-onboarding-rust",
"unleash-onboarding-instance",
Some(api_token.to_owned()),
)?;
client.register().await?;
\`\`\`
---
- [SDK repository with documentation](https://github.com/Unleash/unleash-client-rust)
- [Rust example with CodeSandbox](https://github.com/Unleash/unleash-sdk-examples/tree/main/Rust)
- [How to Implement Feature Flags in Rust](https://docs.getunleash.io/feature-flag-tutorials/rust)
`,Swift:`1\\. Install the SDK
\`\`\`sh
// Instructions to add the Swift SDK can be found at the provided URL:
https://github.com/Unleash/unleash-proxy-client-swift.git
\`\`\`
2\\. Run Unleash
\`\`\`swift
import Foundation
import UnleashProxyClientSwift
var unleash = UnleashProxyClientSwift.UnleashClient(
unleashUrl: "<YOUR_API_URL>",
clientKey: "<YOUR_API_TOKEN>", // in production use environment variable
appName: "unleash-onboarding-swift",
context: [:])
unleash.start()
Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { _ in
print("Is enabled", unleash.isEnabled(name: "<YOUR_FLAG>"))
}
\`\`\`
ℹ️ **Info:** The Swift SDK takes at least 60 seconds to post metrics to Unleash.
`},mn=I(`pre`)(({theme:e})=>({backgroundColor:e.palette.background.elevation1,padding:e.spacing(2),borderRadius:e.shape.borderRadius,overflow:`auto`,fontSize:e.typography.body2.fontSize,wordBreak:`break-all`,whiteSpace:`pre-wrap`,position:`relative`,maxHeight:e.spacing(34)})),hn=I(Ze)(({theme:e})=>({position:`absolute`,top:e.spacing(1),right:e.spacing(1)})),gn=({title:e,code:t})=>{let n=e=>()=>{(0,pn.default)(e),r({type:`success`,text:`Copied to clipboard`})},{setToastData:r}=E();return(0,R.jsxs)(mn,{children:[t,(0,R.jsx)(hn,{title:e,arrow:!0,children:(0,R.jsx)(be,{onClick:n(t),size:`small`,children:(0,R.jsx)(ge,{})})})]})},$=({inline:e=!1,children:t})=>!e&&typeof t?.[0]==`string`?(0,R.jsx)(gn,{code:t[0],title:`Copy code`}):(0,R.jsx)(`code`,{children:t}),_n=(e,t)=>`${e}/api${K.some(e=>e.name===t)?`/frontend`:``}/`,vn=I(`div`)(({theme:e})=>({padding:e.spacing(5,8,2,8),display:`flex`,flexDirection:`column`,gap:e.spacing(3)})),yn=I(`div`)(({theme:e})=>({display:`inline-flex`,gap:e.spacing(3),padding:e.spacing(1,2),border:`1px solid ${e.palette.divider}`,borderRadius:e.shape.borderRadius,marginBottom:e.spacing(3)})),bn=({sdk:e,apiKey:t,feature:n,onSdkChange:r})=>{let{uiConfig:i}=N(),a=Ut.find(t=>t.name===e.name)?.icon,o=_n(i.unleashUrl,e.name),[s,c,l]=(Q[e.name]||``).replace(`<YOUR_API_TOKEN>`,t).replace(`<YOUR_API_URL>`,o).replaceAll(`<YOUR_FLAG>`,n).split(`---
`);return(0,R.jsxs)(vn,{children:[(0,R.jsx)(F,{variant:`h2`,children:`Connect an SDK to Unleash`}),(0,R.jsxs)(H,{children:[(0,R.jsx)(U,{active:2,steps:3}),(0,R.jsx)(O,{color:`secondary`,children:`3/3 - Test connection`})]}),(0,R.jsxs)(k,{sx:{mt:2},children:[(0,R.jsxs)(yn,{children:[a?(0,R.jsx)(D,{variant:`circular`,src:P(a),alt:e.name}):null,(0,R.jsx)(w,{onClick:r,component:`button`,children:`Change SDK`})]}),(0,R.jsx)(V,{children:`Setup the SDK`}),(0,R.jsx)(L,{components:{code:$},children:s})]})]})},xn=I(`div`)(({theme:e})=>({padding:e.spacing(5,8,2,8),display:`flex`,flexDirection:`column`,gap:e.spacing(3),fontSize:e.typography.body2.fontSize})),Sn=({sdk:e})=>{let{uiConfig:t}=N(),n=`${t.unleashUrl}/api/`,r=`${t.unleashUrl}/api/frontend/`,i=e.type===`client`?n:r,[a,o,s]=(Q[e.name]||``).replaceAll(`<YOUR_API_URL>`,i).split(`---
`);return(0,R.jsxs)(xn,{children:[(0,R.jsx)(F,{variant:`h2`,children:`Connect an SDK to Unleash`}),(0,R.jsxs)(H,{children:[(0,R.jsx)(U,{active:2,steps:3}),(0,R.jsx)(O,{color:`secondary`,children:`3/3 - Test connection`})]}),o?.trim()?(0,R.jsxs)(k,{sx:{mt:2},children:[(0,R.jsx)(V,{children:`Production settings`}),(0,R.jsx)(F,{variant:`body2`,children:`You have successfully connected your SDK. In the previous code example, the settings were optimized for development. We recommend the following setup for production.`}),(0,R.jsx)(L,{components:{code:$},children:o})]}):null,s?.trim()?(0,R.jsxs)(k,{children:[(0,R.jsx)(V,{children:`Additional resources`}),(0,R.jsx)(F,{variant:`body2`,children:`Now that we’ve validated the connection, you might want to look into more advanced use cases and examples:`}),(0,R.jsx)(L,{components:{code:$},children:s})]}):null]})},Cn=({sdk:e,apiKey:t,feature:n,onSdkChange:r})=>(0,R.jsx)(z.Suspense,{fallback:(0,R.jsx)(pe,{}),children:n?(0,R.jsx)(bn,{sdk:e,apiKey:t,feature:n,onSdkChange:r}):(0,R.jsx)(Sn,{sdk:e})}),wn=I(`main`)(({theme:e})=>({backgroundColor:e.palette.background.paper,display:`flex`,flexDirection:`column`,flex:1})),Tn=I(m)(({theme:e})=>({"& .MuiDialog-paper":{borderRadius:e.shape.borderRadiusLarge,maxWidth:e.spacing(170),width:`100%`,backgroundColor:`transparent`},padding:0,"& .MuiPaper-root > section":{overflowX:`hidden`}})),En=I(`div`)(({theme:e})=>({borderTop:`1px solid ${e.palette.divider}}`,display:`flex`,justifyContent:`flex-end`,gap:e.spacing(4),alignItems:`center`,padding:e.spacing(3,8,3,8)})),Dn=I(`div`)(({theme:e})=>({display:`flex`,justifyContent:`flex-end`,gap:e.spacing(4),alignItems:`center`,padding:e.spacing(3,8,3,8)})),On=({onClose:e,onFinish:t,environments:n,project:r,feature:i})=>{let a=_(l().breakpoints.up(`lg`)),[o,s]=(0,z.useState)(null),[c,d]=(0,z.useState)(null),[f,p]=(0,z.useState)(null),[m,h]=(0,z.useState)(`select-sdk`),{project:g}=u(r,{refreshInterval:1e3}),v=m===`select-sdk`,y=m===`generate-api-key`&&o&&c,b=m===`test-connection`&&o&&c&&f,x=g.onboardingStatus.status===`onboarded`;return(0,z.useEffect)(()=>{n.length>0&&d(n[0])},[JSON.stringify(n)]),(0,R.jsx)(Tn,{open:!0,onClose:e,children:(0,R.jsxs)(k,{sx:{display:`flex`},children:[(0,R.jsxs)(wn,{children:[v?(0,R.jsx)(Yt,{onSelect:e=>{s(e),h(`generate-api-key`)}}):null,y?(0,R.jsx)(Vt,{environments:n,environment:c,project:r,sdkType:o.type,onEnvSelect:d,onApiKey:p}):null,b?(0,R.jsx)(Cn,{apiKey:f,sdk:o,feature:i,onSdkChange:()=>{h(`select-sdk`)}}):null,m===`generate-api-key`?(0,R.jsx)(En,{children:(0,R.jsxs)(Dn,{children:[(0,R.jsx)(A,{variant:`text`,color:`inherit`,onClick:()=>{h(`select-sdk`)},children:`Back`}),(0,R.jsx)(A,{variant:`contained`,disabled:!f,onClick:()=>{h(`test-connection`)},children:`Next`})]})}):null,b?(0,R.jsx)(En,{children:(0,R.jsxs)(Dn,{children:[x?null:(0,R.jsx)(A,{variant:`text`,color:`inherit`,onClick:()=>{h(`generate-api-key`)},children:`Back`}),(0,R.jsx)(A,{variant:`contained`,onClick:()=>{t(o.name)},children:`Complete`})]})}):null]}),a&&v?(0,R.jsx)(tn,{}):null,a&&y?(0,R.jsx)(en,{}):null,a&&b?(0,R.jsx)(fn,{projectId:r,sdk:o.name,environment:c}):null]})})},kn=({open:e,...t})=>e?(0,R.jsx)(On,{...t}):null,An=({isStale:e,isOpen:t,projectId:n,featureId:i,onClose:a})=>{let{setToastData:o,setToastApiError:s}=E(),{patchFeatureToggle:c}=g(),l=(0,R.jsx)(F,{children:`Setting a flag to stale marks it for cleanup`}),u=(0,R.jsx)(F,{children:`Setting a flag to active marks it as in active use`}),d=e?`active`:`stale`;return(0,R.jsx)(se,{open:t,secondaryButtonText:`Cancel`,primaryButtonText:`Flip to ${d}`,title:`Set feature state to ${d}`,onClick:async t=>{t.stopPropagation();try{await c(n,i,[{op:`replace`,path:`/stale`,value:!e}]),a()}catch(e){s(C(e))}o(e?{type:`success`,text:`The flag is no longer marked as stale`}:{type:`success`,text:`The flag has been marked as stale`})},onClose:a,children:(0,R.jsx)(r,{condition:e,show:u,elseShow:l})})};export{ot as _,Q as a,rt as b,Ut as c,Ot as d,wt as f,st as g,pt as h,$ as i,jt as l,bt as m,kn as n,an as o,Ct as p,_n as r,nn as s,An as t,kt as u,at as v,tt as x,it as y};