<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Srikanth Kyatham</title>
    <description>The latest articles on DEV Community by Srikanth Kyatham (@srikanthkyatham).</description>
    <link>https://dev.to/srikanthkyatham</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F413620%2Fafc963d7-b769-400b-9d6e-1de513e344e5.jpeg</url>
      <title>DEV Community: Srikanth Kyatham</title>
      <link>https://dev.to/srikanthkyatham</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/srikanthkyatham"/>
    <language>en</language>
    <item>
      <title>How to add custom org and role in grafana with AWS cognito as oauth provider</title>
      <dc:creator>Srikanth Kyatham</dc:creator>
      <pubDate>Mon, 31 Mar 2025 18:02:19 +0000</pubDate>
      <link>https://dev.to/srikanthkyatham/how-to-add-custom-org-and-role-in-grafana-with-aws-cognito-as-auth-provider-19hd</link>
      <guid>https://dev.to/srikanthkyatham/how-to-add-custom-org-and-role-in-grafana-with-aws-cognito-as-auth-provider-19hd</guid>
      <description>&lt;h1&gt;
  
  
  AWS Cognito + Grafana
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Idea
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;To be able to configure the user to a given organisation.&lt;/li&gt;
&lt;li&gt;In AWS cognito there are users and groups.&lt;/li&gt;
&lt;li&gt;If a user is added to a group based on the group which would be of format (GRAFANA_{orgName}_{role}), where the orgName is organisation name in grafana, then user to would be added to respective organisation on successful oauth sign in.&lt;/li&gt;
&lt;li&gt;In order that to happen, we need to add pre token generation lambda, which would add custom claims to the id token. &lt;/li&gt;
&lt;li&gt;Grafana needs to configure role and org attributes to in order extract the role and orgs and assign the user to correct organisations with the correct role.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Grafana role and org attributes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;role_attribute_path - the documentation is quite straight forward, in our case we want to extract the role from custom_role in the id_token response.&lt;/li&gt;
&lt;li&gt;org mapping - this was a bit tricky, we need to configure two attributes

&lt;ul&gt;
&lt;li&gt;org_attribute_path&lt;/li&gt;
&lt;li&gt;org_mapping&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;in our case we want the users to be assigned to organisations found in the org_attribute_path. In order that to happen

&lt;ul&gt;
&lt;li&gt;org_mapping needs to be updated, when an organisation is created in grafana. Meaning&lt;/li&gt;
&lt;li&gt;Lets say that the org_mapping is
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;org_mapping = org1:2:Viewer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have created a new organisation org2, then the org_mapping needs to be updated as&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;org_mapping = org1:2:Viewer,org2:3:Viewer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;where &lt;br&gt;
org1 is the organisation name&lt;br&gt;
2 is the organisation id&lt;br&gt;
You can find these details in the grafana&amp;gt;Administration&amp;gt;general&amp;gt;organisations&lt;/p&gt;
&lt;h2&gt;
  
  
  Grafana configuration
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The following attributes needs to updated

&lt;ul&gt;
&lt;li&gt;role, org mapping attributes&lt;/li&gt;
&lt;li&gt;clientId&lt;/li&gt;
&lt;li&gt;clientSecret&lt;/li&gt;
&lt;li&gt;authUrl&lt;/li&gt;
&lt;li&gt;tokenUrl&lt;/li&gt;
&lt;li&gt;apiUrl&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Domain url could be fetched from AWS cognito like shown in the figure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkqx6ugjkdt9s6cdmhz2m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkqx6ugjkdt9s6cdmhz2m.png" alt="Image description" width="800" height="177"&gt;&lt;/a&gt;&lt;br&gt;
in custom.ini, *.ini&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[log]
level = debug
[users]
auto_assign_org = true
[auth.basic_auth]
enabled = debug
[auth.generic_oauth]
client_id = &amp;lt;client_id&amp;gt;
client_secret = &amp;lt;client_secret&amp;gt;
scopes = &amp;lt;scopes&amp;gt;
auth_url = &amp;lt;domain_url&amp;gt;/oauth2/authorize
token_url = &amp;lt;domain_url&amp;gt;/oauth2/token
api_url = &amp;lt;domain_url&amp;gt;/oauth2/userInfo 
signout_redirect_url = &amp;lt;domain_url&amp;gt;/logout?client_id=&amp;lt;client_id&amp;gt;&amp;amp;logout_uri=&amp;lt;logout_url&amp;gt;
role_attribute_path = ("custom_role" || contains([*], 'ADMIN') &amp;amp;&amp;amp; 'Admin') || ("custom_role" || contains([*], 'EDITOR') &amp;amp;&amp;amp; 'Editor') || 'Viewer'
role_attribute_strict = true
org_attribute_path = "custom_orgs"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;if you are using docker-compose then the environment variables would be.&lt;/p&gt;

&lt;p&gt;The variables &lt;/p&gt;

&lt;p&gt;example docker-compose.yml&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;services:
  grafana:
    image: grafana/grafana-oss
    container_name: grafana
    restart: unless-stopped
    environment:
      - GF_AUTH_GENERIC_OAUTH_ENABLED=true
      - GF_AUTH_GENERIC_OAUTH_CLIENT_ID=&amp;lt;client_id&amp;gt;
      - GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET=&amp;lt;client_secret&amp;gt;
      - GF_AUTH_GENERIC_OAUTH_AUTH_URL=&amp;lt;domain_url&amp;gt;/oauth2/authorize
      - GF_AUTH_GENERIC_OAUTH_TOKEN_URL=&amp;lt;domain_url&amp;gt;/oauth2/token
      - GF_AUTH_GENERIC_OAUTH_API_URL=&amp;lt;domain_url&amp;gt;/oauth2/userInfo
      - GF_AUTH_GENERIC_OAUTH_API_URL=&amp;lt;domain_url&amp;gt;/logout?client_id=&amp;lt;client_id&amp;gt;&amp;amp;logout_uri=&amp;lt;logout_url&amp;gt;
      - GF_AUTH_GENERIC_OAUTH_SCOPES=&amp;lt;scopes&amp;gt;
      - GF_AUTH_GENERIC_OAUTH_ROLE_ATTRIBUTE_PATH=("custom_role" || contains([*], 'ADMIN') &amp;amp;&amp;amp; 'Admin') || ("custom_role" || contains([*], 'EDITOR') &amp;amp;&amp;amp; 'Editor') || 'Viewer'
      - GF_AUTH_GENERIC_OAUTH_ROLE_ATTRIBUTE_STRICT=true
      - GF_AUTH_GENERIC_OAUTH_ORG_ATTRIBUTE_PATH="custom_orgs"
      - GF_LOG_LEVEL=debug
      - GF_USERS_AUTO_ASSIGN_ORG=true
      - GF_AUTH_BASIC_ENABLED=true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  AWS Lambda
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;AWS lambda - Purpose is to populate the custom claims, which in our case are the organisation (custom_orgs) and role of the user (custom_role), which would be extract in the grafana upon succesfull oauth

&lt;ul&gt;
&lt;li&gt;In order to add pre auth token lambda we need to click on the extensions in the cognito user pool&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F00lgsuq99e73mwxcsoy0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F00lgsuq99e73mwxcsoy0.png" alt="Image description" width="281" height="792"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add pre token generation lambda options should be as shown in the figure

&lt;ul&gt;
&lt;li&gt;Trigger type - Authentication&lt;/li&gt;
&lt;li&gt;Authentication - Pre token generation trigger&lt;/li&gt;
&lt;li&gt;Trigger event version - Basic features + access token customization atleast&lt;/li&gt;
&lt;li&gt;Select the lambda to be added&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4k3g92k1wx7yvkrpmlgi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4k3g92k1wx7yvkrpmlgi.png" alt="Image description" width="800" height="524"&gt;&lt;/a&gt;    &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;code for the lambda is
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Event&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;groupConfiguration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;groupsToOverride&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nl"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;claimsAndScopeOverrideDetails&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;idTokenGeneration&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;claimsToAddOrOverride&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="na"&gt;custom_orgs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
                    &lt;span class="na"&gt;custom_role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Log the event for debugging&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cognitoGroups&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;groupConfiguration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;groupsToOverride&lt;/span&gt;
    &lt;span class="c1"&gt;// Extract groups from Cognite or other attribute sources&lt;/span&gt;
    &lt;span class="c1"&gt;// For example, if you have groups stored in a cognito:groups attribute&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;groups&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cognitoGroups&lt;/span&gt;

    &lt;span class="c1"&gt;// Filter for Grafana groups and format them&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;grafanaGroups&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;groups&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;group&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;GRAFANA_&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;customOrgs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;grafanaGroups&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;group&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;_&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;customRole&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
        &lt;span class="nx"&gt;grafanaGroups&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;grafanaGroups&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;_&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;grafanaGroups&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;_&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;



    &lt;span class="c1"&gt;// Add the custom claim to the ID token&lt;/span&gt;
    &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;claimsAndScopeOverrideDetails&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;idTokenGeneration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;claimsToAddOrOverride&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="na"&gt;custom_org&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;customOrgs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;custom_role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;customRole&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;When the user is created in the AWS Cognito

&lt;ul&gt;
&lt;li&gt;Create AWS cognito user&lt;/li&gt;
&lt;li&gt;Create AWS cognito group GRAFANA_{ORGNAME}_{ROLE}&lt;/li&gt;
&lt;li&gt;Assign the cogito user to the group&lt;/li&gt;
&lt;li&gt;Create the grafana org - POST /org
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;grafanaUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://localhost:3000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;orgsEndPoint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/orgs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;orgUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;grafanaUrl&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;orgsEndPoint&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;clientId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;you_client_id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;clientSecret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;you_client_secret&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;basicAuthHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pwd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;combo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;pwd&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;base64String&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;combo&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;base64&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;header&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`Basic &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;base64String&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;header&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;commonHeaders&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;authorization&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;basicAuthHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;grafanaUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;grafanaPwd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;headers&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;commonHeader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;commonHeaders&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;


&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createOrg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;orgName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;orgName&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;orgUrl&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;commonHeader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;User-Agent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;undici-stream-example&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Update the sso-settings/generic_oauth, orgMapping
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getSsoSettings&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;commonHeader&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;updateSsoSettings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;grafanaUrl&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/api/v1/sso-settings/generic_oauth`&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PUT&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;commonHeader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;User-Agent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;undici-stream-example&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;updateOrgMapping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newOrgName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newOrgId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ssoSettings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getSsoSettings&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;genericProvider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ssoSettings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;setting&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;setting&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;provider&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;generic_oauth&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;genericOauthSettings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;genericProvider&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;settings&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;orgMapping&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;genericOauthSettings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;orgMapping&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updatedOrgMapping&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;orgMapping&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;newOrgName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;newOrgId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:Viewer`&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;putBody&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;settings&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;clientId&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;clientId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;authUrl&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;DomainUrl&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/oauth2/authorize`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tokenUrl&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;DomainUrl&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/oauth2/token`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;orgMapping&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;updatedOrgMapping&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;updateSsoSettings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;putBody&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>grafana</category>
      <category>awscognito</category>
      <category>awslambda</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Debugging with breakpoints in ExUnit</title>
      <dc:creator>Srikanth Kyatham</dc:creator>
      <pubDate>Wed, 28 Feb 2024 13:35:18 +0000</pubDate>
      <link>https://dev.to/srikanthkyatham/debugging-with-breakpoints-in-exunit-522b</link>
      <guid>https://dev.to/srikanthkyatham/debugging-with-breakpoints-in-exunit-522b</guid>
      <description>&lt;p&gt;Hi&lt;/p&gt;

&lt;p&gt;The following is a demonstration on how to debug using debugger. Of course, IO.inspect works. Where it does not.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;defmodule Math do
  def add(a, b) do
    a + b
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;defmodule MathTest do

  # timeout: :infinity is needed as the exunit timeouts around 3 seconds 
  @tag timeout: :infinity
  test ~c"test add" do
    :debugger.start()
    :int.ni(Math)
    # break_in take module, function, arity
    # module - Math
    # function - add
    # arity - 2 no of parameters
    :int.break_in(Math, :add, 2)
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>elixir</category>
      <category>exunit</category>
      <category>debugger</category>
      <category>breakpoint</category>
    </item>
    <item>
      <title>Migrating to Create react app v5, single bundle with craco and fast-refresh disable</title>
      <dc:creator>Srikanth Kyatham</dc:creator>
      <pubDate>Tue, 23 Jan 2024 07:52:33 +0000</pubDate>
      <link>https://dev.to/srikanthkyatham/migrating-to-create-react-app-v5-single-bundle-with-craco-and-fast-refresh-disable-2gpn</link>
      <guid>https://dev.to/srikanthkyatham/migrating-to-create-react-app-v5-single-bundle-with-craco-and-fast-refresh-disable-2gpn</guid>
      <description>&lt;p&gt;Hi&lt;/p&gt;

&lt;p&gt;Until recently we have been working on node v16 and react-scripts v4. Our pipelines have migrated to v20 and we were forced to migrate. Due to our internal application framework limitations, our app cannot have more the one chunk. &lt;/p&gt;

&lt;p&gt;We had the following problems&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;limiting chunks to one &lt;/li&gt;
&lt;li&gt;skipping the limitation that all modules being imported need to have an file extension, like for example
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Earlier it was
import add from "./add"
// Now the expected is
import add from "./add.js"

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After googling and stack overflow, found that we could modify the web pack config without eject, using &lt;a href="https://www.npmjs.com/package/@craco/craco"&gt;craco&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;br&gt;
npm i -D @craco/craco&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Respective config file is, which solve the above problems is&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const webpack = require("webpack");

module.exports = {
  webpack: {
    plugins: {
      add: [
        new webpack.optimize.LimitChunkCountPlugin({
          maxChunks: 1,
        }),
      ],
      skipEnvChecks: true,
      skipEnvCheck: true,
    },
    configure: {
      module: {
        rules: [
          {
            test: /\.m?js$/,
            resolve: {
              fullySpecified: false,
            },
          },
        ],
      },
    },
  },
};

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Respective package.json changes are&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"scripts": {
-  "start": "react-scripts start"
+  "start": "craco start"
-  "build": "react-scripts build"
+  "build": "craco build"
-  "test:build": "craco build"
+. "test:build": "cross-env-shell NODE_ENV=test craco build"
-  "test": "react-scripts test"
+  "test": "craco test"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All was good, then came the next issue. Building for test enviroment. When I tried for it I have faced the following issue&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Error: [BABEL] /Users/srikanthkyatham/Projects/ajv/appointmentclerkapp/app/appointmentclerkapp-frontend/js/src/index.tsx: React Refresh Babel transform should only be enabled in development environment. Instead, the environment is: "production". If you want to override this check, pass {skipEnvCheck: true} as plugin options. (While processing: "/Users/srikanthkyatham/Projects/ajv/appointmentclerkapp/app/appointmentclerkapp-frontend/js/node_modules/react-refresh/babel.js")
    at Generator.next (&amp;lt;anonymous&amp;gt;)
    at Generator.next (&amp;lt;anonymous&amp;gt;)
    at Generator.next (&amp;lt;anonymous&amp;gt;)
    at Generator.next (&amp;lt;anonymous&amp;gt;)
    at cachedFunction.next (&amp;lt;anonymous&amp;gt;)
    at loadPluginDescriptor.next (&amp;lt;anonymous&amp;gt;)
    at loadPluginDescriptors.next (&amp;lt;anonymous&amp;gt;)
    at Generator.next (&amp;lt;anonymous&amp;gt;)
    at loadFullConfig.next (&amp;lt;anonymous&amp;gt;)
    at transform.next (&amp;lt;anonymous&amp;gt;)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Solution for that is add env variable FAST_REFRESH=false&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"scripts": {
  "test:build": "cross-env-shell NODE_ENV=test FAST_REFRESH=false craco build"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>react</category>
      <category>craco</category>
      <category>refresh</category>
      <category>fileextension</category>
    </item>
    <item>
      <title>Rescript Http Error Response</title>
      <dc:creator>Srikanth Kyatham</dc:creator>
      <pubDate>Sat, 12 Aug 2023 18:37:50 +0000</pubDate>
      <link>https://dev.to/srikanthkyatham/rescript-http-error-response-31bg</link>
      <guid>https://dev.to/srikanthkyatham/rescript-http-error-response-31bg</guid>
      <description>&lt;p&gt;Hi&lt;/p&gt;

&lt;p&gt;Have you ever wondered how would you get Http Error Response out of the Js.Exn.t. Js.Exn.t is intentionally opaque. We need to cast to the appropriate object type. In this particular case we are trying to get Http Error response&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module Response = {
  type t = {
    status: int
  }
}
@get external getResponse: Js.Exn.t =&amp;gt; option&amp;lt;Response.t&amp;gt; = "response"
let handleError = (error: Js.Exn.t) =&amp;gt; {
  let response = getResponse(error)
  switch response {
    | Some(response) =&amp;gt; Js.log2("response status", response.status)
    | None =&amp;gt; Js.log2("no response available")
  }
}

exception MyError(string)


// Now assume that we are trying to fetch 
open Promise
fetch("")
-&amp;gt;then(todos =&amp;gt; resolve(todos))
-&amp;gt;catch(error =&amp;gt; {
  handleError(error)
let err = switch e {
  | MyError(str) =&amp;gt; "found MyError: " ++ str
  | _ =&amp;gt; "Some unknown error"
  }

  // Here we are using the same type (`t&amp;lt;result&amp;gt;`) as in the previous `then` call
  Error(err)-&amp;gt;resolve
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hope you found it useful.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Mock React hooks based on environment</title>
      <dc:creator>Srikanth Kyatham</dc:creator>
      <pubDate>Mon, 13 Mar 2023 07:41:42 +0000</pubDate>
      <link>https://dev.to/srikanthkyatham/mock-react-hooks-based-on-environment-5b4l</link>
      <guid>https://dev.to/srikanthkyatham/mock-react-hooks-based-on-environment-5b4l</guid>
      <description>&lt;p&gt;Hi&lt;/p&gt;

&lt;p&gt;Recently I had an issue that there exists on React hook which was available only in the production environment since our application is being loaded inside other framework, which provided it. &lt;/p&gt;

&lt;p&gt;Basic issue is you cannot place the hook inside a condition.&lt;/p&gt;

&lt;p&gt;I needed to mock the hook, I have searched on the web and found hook mocking using jest. &lt;/p&gt;

&lt;p&gt;Hence the following approach.&lt;/p&gt;

&lt;p&gt;Let says my hook is &lt;strong&gt;useServerData&lt;/strong&gt; very unintuitive. But for this purpose its fine. &lt;/p&gt;

&lt;p&gt;I have created a mock hook, &lt;strong&gt;useServerDataMock&lt;/strong&gt; in my mock file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;useServerData&lt;/strong&gt; would given an object&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  userId: string,
  meta: any
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In my mock.ts&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const useServerDataMock = () =&amp;gt; {
  return {
    userId: "testId",
    meta: {}
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now how to use mock hook based on Dev or Prod environment&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;interface ContainerProps {
  serverData: ServerData
}
const Container = (props: ContainerProps) =&amp;gt; {
  ..
}
const ProdContainer = () =&amp;gt; {
  const serverData = useServerData()
  return &amp;lt;Container serverData={serverData} /&amp;gt;
}
const DevContainer = () =&amp;gt; {
  const serverData = useServerDataMock()
  return &amp;lt;Container serverData={serverData} /&amp;gt;
}

const App = () =&amp;gt; {
  if (process.env.NODE_ENV === "production") {
    return &amp;lt;ProdContainer /&amp;gt;
  } else {
    return &amp;lt;DevContainer /&amp;gt;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hope this helps someone facing similar issue.&lt;/p&gt;

</description>
      <category>react</category>
      <category>hooks</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Rescript React useStateMachine without useEffect usage</title>
      <dc:creator>Srikanth Kyatham</dc:creator>
      <pubDate>Mon, 23 Jan 2023 12:47:51 +0000</pubDate>
      <link>https://dev.to/srikanthkyatham/rescript-react-usestatemachine-without-useeffect-usage-34oh</link>
      <guid>https://dev.to/srikanthkyatham/rescript-react-usestatemachine-without-useeffect-usage-34oh</guid>
      <description>&lt;p&gt;Hi&lt;/p&gt;

&lt;p&gt;Lately I have been using too much useEffect, its becoming hard to track the state. After seeing David Piano (author of XState) I have been thinking on how to do it in Rescript.&lt;/p&gt;

&lt;p&gt;I have been using React.useReducer quite extensively. I have come up with a hook which combines React.useReducer and React.useEffect named it un-intuitively as useStateMachine.&lt;/p&gt;

&lt;p&gt;Let's see how useStateMachine is &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;structured&lt;/li&gt;
&lt;li&gt;how to structure your state&lt;/li&gt;
&lt;li&gt;how to use it in the project&lt;/li&gt;
&lt;li&gt;how to trigger side effects as well as part of the state actions&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;State and actions&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type effectulActions = 
| #Network(networkReducer)
| #Db(dbReducer)
| #Storage(storageReducer)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;actions with some tags(network, database, storage) would trigger the functions in the useEffect&lt;/p&gt;

&lt;p&gt;If the actions are part of this then trigger the effectful action in the useEffect&lt;/p&gt;

&lt;p&gt;Thus shielding the complexity from the react component&lt;br&gt;
How the dependencies should be added to the useEffect ?&lt;br&gt;
How the state should be part of the useEffect dependencies ? &lt;br&gt;
The above are the outstanding questions for now. &lt;br&gt;
For starters we can add the whole state to the dependencies.&lt;/p&gt;

&lt;p&gt;How the action should translate to sideEffect triggering function call ?&lt;/p&gt;

&lt;p&gt;How it should reflect/update in the state ?&lt;/p&gt;

&lt;p&gt;This is a basic structure I could come up with.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  let reducer = (state, action) =&amp;gt; {
    switch action {
    | #Network(networkReducer) =&amp;gt; {
      networkReducer(state, action)
    } 
  }

  let sideEffectReducer = (state, action) =&amp;gt; {
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  useStateMachine hook
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type stateMachineState&amp;lt;'state, 'effectfulAction&amp;gt; = {
  state: 'state,
  effectfulAction: option&amp;lt;'effectfulAction&amp;gt;,
}

type stateMachineActions&amp;lt;'state, 'action, 'effectfulAction&amp;gt; =
  | StateWithoutSideEffect('action)
  | StateAfterSideEffect(stateMachineState&amp;lt;'state, 'effectfulAction&amp;gt;)

type reducerType&amp;lt;'state, 'action, 'effectfulAction&amp;gt; = (
  stateMachineState&amp;lt;'state, 'effectfulAction&amp;gt;,
  stateMachineActions&amp;lt;'state, 'action, 'effectfulAction&amp;gt;,
) =&amp;gt; stateMachineState&amp;lt;'state, 'effectfulAction&amp;gt;

type sideEffectReducerType&amp;lt;'state, 'effectfulAction&amp;gt; = (
  stateMachineState&amp;lt;'state, 'effectfulAction&amp;gt;,
  'effectfulAction,
) =&amp;gt; Js.Promise.t&amp;lt;stateMachineState&amp;lt;'state, 'effectfulAction&amp;gt;&amp;gt;

let useStateMachine = (
  reducer: reducerType&amp;lt;'state, 'action, 'effectfulAction&amp;gt;,
  sideEffectReducer: sideEffectReducerType&amp;lt;'state, 'effectfulAction&amp;gt;,
  initialState: stateMachineState&amp;lt;'state, 'effectfulAction&amp;gt;,
) =&amp;gt; {
  let (stateMachineState, dispatch) = React.useReducer(reducer, initialState)
  // This does not handle the clean up
  React.useEffect3(() =&amp;gt; {
    switch stateMachineState.effectfulAction {
    | Some(effectfulAction) =&amp;gt; {
        open Promise
        sideEffectReducer(stateMachineState, effectfulAction)
        -&amp;gt;then(newState =&amp;gt; {
          dispatch(StateAfterSideEffect(newState))
          resolve()
        })
        -&amp;gt;catch(error =&amp;gt; {
          Js.log2("error", error)
          resolve()
        })
        -&amp;gt;ignore
      }

    | None =&amp;gt; ()
    }
    None
  }, (sideEffectReducer, stateMachineState, dispatch))

  (stateMachineState.state, dispatch)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A lot going on in the above code. Lets break down&lt;/p&gt;

&lt;p&gt;1.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type stateMachineState&amp;lt;'state, 'effectfulAction&amp;gt; = {
  state: 'state,
  effectfulAction: option&amp;lt;'effectfulAction&amp;gt;,
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;stateMachine state type is parameterised over state type and effectfulAction which is optional. The component using this state would pass the state and type of the sideEffectul actions it intends to deal with.&lt;/p&gt;

&lt;p&gt;2.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type stateMachineActions&amp;lt;'state, 'action, 'effectfulAction&amp;gt; =
  | StateWithoutSideEffect('action)
  | StateAfterSideEffect(stateMachineState&amp;lt;'state, 'effectfulAction&amp;gt;)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;stateMachine actions are parameterised our the state, action and effectulActions. There are two states this statemachine could be in (this was the simplest I could make, there could be more extensions for now this would suffice).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Whenever there are an action dispatch then  StateWithoutSideEffect action is dispatched in the reducer case could decide whether there could be any effectulActions that needs to be done based on the given case. If so then state.effectulAction is populated else it is None.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;useStateMachine hook explanation.
Whenever there effectulAction is populated then sideEffectReducer is invoke with appropriate parameters inside the useEffect hook. Thus all sideEffects happen in the sideEffectReducer inside the useEffect. Thus we could keep our code clean of the useEffect as much as possible.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Usage of the useStateMachine
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type action = INFO(array&amp;lt;string&amp;gt;)

type state = {options: array&amp;lt;string&amp;gt;}
type rec sideEffectActions =
  INFO_UPDATE(StateMachine.stateMachineState&amp;lt;state, sideEffectActions&amp;gt;, string)

let getInitialState = () =&amp;gt; {
  let state = {
    options: [],
  }

  let stateMachineState: StateMachine.stateMachineState&amp;lt;state, sideEffectActions&amp;gt; = {
    state,
    effectfulAction: None,
  }
  stateMachineState
}

let reducer = (state, action) =&amp;gt; {
  switch action {
  | INFO(_) =&amp;gt; state
  }
}

let sideEffectReducer = (
  state: StateMachine.stateMachineState&amp;lt;state, sideEffectActions&amp;gt;,
  action: sideEffectActions,
): Js.Promise.t&amp;lt;StateMachine.stateMachineState&amp;lt;state, sideEffectActions&amp;gt;&amp;gt; =&amp;gt; {
  open Promise

  switch action {
  | INFO_UPDATE(_state, _str) =&amp;gt;
    // side effectul action
    resolve(state)
  }
}

let stateMachineReducer = (
  state: StateMachine.stateMachineState&amp;lt;state, sideEffectActions&amp;gt;,
  action: StateMachine.stateMachineActions&amp;lt;state, action, sideEffectActions&amp;gt;,
): StateMachine.stateMachineState&amp;lt;'state, 'effectfulAction&amp;gt; =&amp;gt; {
  switch action {
  | StateWithoutSideEffect(action) =&amp;gt;
    switch action {
    | INFO(_options) =&amp;gt; // every state change should trigger the debounce api call
      {
        ...state,
        effectfulAction: Some(INFO_UPDATE(state, "asd")),
      }
    }
  | _ =&amp;gt; state
  }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>react</category>
      <category>javascript</category>
      <category>rescript</category>
      <category>xstate</category>
    </item>
    <item>
      <title>How we solved Gnarly bug with React table + useGlobalFilter + useRowSelect</title>
      <dc:creator>Srikanth Kyatham</dc:creator>
      <pubDate>Fri, 13 Jan 2023 09:42:30 +0000</pubDate>
      <link>https://dev.to/srikanthkyatham/how-we-solved-gnarly-bug-with-react-table-useglobalfilter-userowselect-1nb9</link>
      <guid>https://dev.to/srikanthkyatham/how-we-solved-gnarly-bug-with-react-table-useglobalfilter-userowselect-1nb9</guid>
      <description>&lt;h2&gt;
  
  
  Application
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;We have react table showing data related to customers &lt;/li&gt;
&lt;li&gt;We have external filters, to filter out customer based on a selected filter criteria&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--b-SHOD8o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2lqqqfwxl8qzdqnue4vw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--b-SHOD8o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2lqqqfwxl8qzdqnue4vw.png" alt="Image description" width="880" height="574"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Usage which cause issue
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Whenever the master checkbox is checked, we get the list of selected indices from the react table. &lt;/li&gt;
&lt;li&gt;The selected indices are an array of strings like ["0", "1"..]&lt;/li&gt;
&lt;li&gt;We parse the string to number and then iterate over given customers and filter the customer which match the indices given us&lt;/li&gt;
&lt;li&gt;This was working fine till the global filter came in to play.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5mdwkgwQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/atenyjvv77wef1bzwcm2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5mdwkgwQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/atenyjvv77wef1bzwcm2.png" alt="Image description" width="880" height="710"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  With Global filter
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Lets say we have filter which filters the customers based on the age
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let customers = [
  {
    name: "name1",
    age: 60,
  },
  {
    name: "name2",
    age: 20
  }
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;We have picked the age-group [0-20]&lt;/li&gt;
&lt;li&gt;Since the external data has changed the globalFilter function is invoked and after the filter is applied the result would be
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;customers = [
  {
    name: "name2",
    age: 20
  }
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now if we select the master-checkbox of the react table, the selected indices returned is ["1"] not ["0"], this minor details caught us off guard. Meaning the selected customers is always based on the original data set which is fed to the react table. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--K_VSEfds--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q6n9wo1434qbriuwnmc2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--K_VSEfds--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q6n9wo1434qbriuwnmc2.png" alt="Image description" width="880" height="445"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Code sandbox link for the above code - &lt;a href="https://codesandbox.io/s/unruffled-dubinsky-lrxixo?file=/src/App.js"&gt;https://codesandbox.io/s/unruffled-dubinsky-lrxixo?file=/src/App.js&lt;/a&gt; &lt;/p&gt;

</description>
      <category>reacttable</category>
      <category>react</category>
      <category>typescript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Rescript bindings for Typescript union types</title>
      <dc:creator>Srikanth Kyatham</dc:creator>
      <pubDate>Mon, 08 Aug 2022 12:51:17 +0000</pubDate>
      <link>https://dev.to/srikanthkyatham/rescript-bindings-for-typescript-union-types-2lb2</link>
      <guid>https://dev.to/srikanthkyatham/rescript-bindings-for-typescript-union-types-2lb2</guid>
      <description>&lt;p&gt;Hi&lt;/p&gt;

&lt;p&gt;Typescript has a beautiful concept of combining different types for a given interface attribute/variable/parameter etc.&lt;br&gt;
Rescript is more strict you can have only one type for a given attribute/variable/parameter. So in this post, I would like show on how to create a union type in Rescript which would be accepted by typescript as well.&lt;/p&gt;

&lt;p&gt;Let's assume we have a prop type, which accepts string | number.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;interface Props {
  ...otherProps,
  badgeContent: string | number
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In rescript side we have to come up with module which would wrap Number and String like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@unboxed
type rec t = Any('a): t

module String_or_number: {
  type t
  type case =
    | Number(float)
    | String(string)
  let number: float =&amp;gt; t
  let string: string =&amp;gt; t
  let classify: t =&amp;gt; case
} = {
  @unboxed
  type rec t = Any('a): t
  type case =
    | Number(float)
    | String(string)
  let number = (v: float) =&amp;gt; Any(v)
  let string = (v: string) =&amp;gt; Any(v)
  let classify = (Any(v): t): case =&amp;gt;
    if Js.typeof(v) == "number" {
      Number((Obj.magic(v): float))
    } else {
      String((Obj.magic(v): string))
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The usage of the String_or_number type&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module Badge = {

  @genType.import("./Badge") @react.component
  external make: (
    ...,
    ~badgeContent: String_or_number.t=?,
  ) =&amp;gt; React.element = "Badge"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In case we want to pass number to badgeContent then we use it as follows&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;Badge badgeContent=String_or_number.number(1.0) /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>react</category>
      <category>rescrip</category>
      <category>typescript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Rescript bindings for JSX.IntrinsicElements prop type</title>
      <dc:creator>Srikanth Kyatham</dc:creator>
      <pubDate>Thu, 04 Aug 2022 08:02:00 +0000</pubDate>
      <link>https://dev.to/srikanthkyatham/rescript-bindings-for-jsxintrinsicelements-interface-8la</link>
      <guid>https://dev.to/srikanthkyatham/rescript-bindings-for-jsxintrinsicelements-interface-8la</guid>
      <description>&lt;p&gt;Hi&lt;/p&gt;

&lt;p&gt;In our workplace the react library relies heavily on typescript. Lately certain props have a type &lt;br&gt;
&lt;code&gt;keyof JSX.IntrinsicElements&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;interface Props {
  ...,
  tagName?: keyof JSX.IntrinsicElements
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now how to pass this prop from the rescript side. After checking out the documentation &lt;a href="https://www.typescriptlang.org/docs/handbook/jsx.html#intrinsic-elements"&gt;https://www.typescriptlang.org/docs/handbook/jsx.html#intrinsic-elements&lt;/a&gt; and type definitions in @types/react/index.d.ts, I came up with polymorphic variant which would solve prop type issue.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module JSX = {
  module IntrinsicElements = {
    type t = [
      | #a
      | #abbr
      | #address
      | #area
      | #article
      | #aside
      | #audio
      | #b
      | #base
      | #bdi
      | #bdo
      | #big
      | #blockquote
      | #body
      | #br
      | #button
      | #canvas
      | #caption
      | #cite
      | #code
      | #col
      | #colgroup
      | #data
      | #datalist
      | #dd
      | #del
      | #details
      | #dfn
      | #dialog
      | #div
      | #dl
      | #dt
      | #em
      | #embed
      | #fieldset
      | #figcaption
      | #figure
      | #footer
      | #form
      | #h1
      | #h2
      | #h3
      | #h4
      | #h5
      | #h6
      | #head
      | #header
      | #hgroup
      | #hr
      | #html
      | #i
      | #iframe
      | #img
      | #input
      | #ins
      | #kbd
      | #keygen
      | #label
      | #legend
      | #li
      | #link
      | #main
      | #map
      | #mark
      | #menu
      | #menuitem
      | #meta
      | #meter
      | #nav
      | #noindex
      | #noscript
      | #object
      | #ol
      | #optgroup
      | #option
      | #output
      | #p
      | #param
      | #picture
      | #pre
      | #progress
      | #q
      | #rp
      | #rt
      | #ruby
      | #s
      | #samp
      | #slot
      | #script
      | #section
      | #select
      | #small
      | #source
      | #span
      | #strong
      | #style
      | #sub
      | #summary
      | #sup
      | #table
      | #template
      | #tbody
      | #td
      | #textarea
      | #tfoot
      | #th
      | #thead
      | #time
      | #title
      | #tr
      | #track
      | #u
      | #ul
      | #var
      | #video
      | #wbr
      | #webview
      | #svg
      | #animate
      | #animateMotion
      | #animateTransform
      | #circle
      | #clipPath
      | #defs
      | #desc
      | #ellipse
      | #feBlend
      | #feColorMatrix
      | #feComponentTransfer
      | #feComposite
      | #feConvolveMatrix
      | #feDiffuseLighting
      | #feDisplacementMap
      | #feDistantLight
      | #feDropShadow
      | #feFlood
      | #feFuncA
      | #feFuncB
      | #feFuncG
      | #feFuncR
      | #feGaussianBlur
      | #feImage
      | #feMerge
      | #feMergeNode
      | #feMorphology
      | #feOffset
      | #fePointLight
      | #feSpecularLighting
      | #feSpotLight
      | #feTile
      | #feTurbulence
      | #filter
      | #foreignObject
      | #g
      | #image
      | #line
      | #linearGradient
      | #marker
      | #mask
      | #metadata
      | #mpath
      | #path
      | #pattern
      | #polygon
      | #polyline
      | #radialGradient
      | #rect
      | #stop
      | #"switch"
      | #symbol
      | #text
      | #textPath
      | #tspan
      | #use
      | #view
    ]
  }
}


module Tile = {
  @genType.import("./Tile") @react.component
  external make: (
    ~tagName: JSX.IntrinsicElements.t
  ) =&amp;gt; React.element = "Tile"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is working fine. If anyone has a better suggestion please comment. &lt;/p&gt;

</description>
      <category>react</category>
      <category>rescript</category>
      <category>typescript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Rescript React Error boundary usage</title>
      <dc:creator>Srikanth Kyatham</dc:creator>
      <pubDate>Wed, 03 Aug 2022 21:09:56 +0000</pubDate>
      <link>https://dev.to/srikanthkyatham/rescript-react-error-boundary-usage-3b05</link>
      <guid>https://dev.to/srikanthkyatham/rescript-react-error-boundary-usage-3b05</guid>
      <description>&lt;p&gt;Hi&lt;/p&gt;

&lt;p&gt;I was trying to capture the react errors. I had to write the bindings for the ErrorBoundary and its usage is shown below.&lt;/p&gt;

&lt;p&gt;The actual ErrorBoundary component is below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// ErrorBoundary.js
import React from "react";

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {
    // Update state so the next render will show the fallback UI.
    return { hasError: true };
  }

  componentDidCatch(error, errorInfo) {
    // You can also log the error to an error reporting service
    //logErrorToMyService(error, errorInfo);
    console.log({ error, errorInfo });
  }

  render() {
    if (this.state.hasError) {
      // You can render any custom fallback UI
      return &amp;lt;h1&amp;gt;Something went wrong.&amp;lt;/h1&amp;gt;;
    }

    return this.props.children;
  }
}

export default ErrorBoundary;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bindings to the ErrorBoundary for Rescript.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// ReactErrorBoundary.res
@react.component @module("./ErrorBoundary.js")
external make: (
  ~children: React.element,
  ~onError: ('e, 'i) =&amp;gt; unit=?,
  ~renderFallback: ('e, 'i) =&amp;gt; React.element=?,
) =&amp;gt; React.element = "ErrorBoundary"

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Error component to show the react error&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Error.res
module Error = {
  @react.component
  let make = (~error) =&amp;gt; {
    &amp;lt;div&amp;gt; {React.string(error)} &amp;lt;/div&amp;gt;
  }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How to use ReactErrorBoundary in rescript&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// ReactErrorBoundary usage
&amp;lt;ReactErrorBoundary fallback={params =&amp;gt; &amp;lt;Error 
  error=params.error /&amp;gt;}&amp;gt;
  &amp;lt;ComponentThrowingException /&amp;gt;
&amp;lt;/ReactErrorBoundary&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>rescript</category>
      <category>react</category>
    </item>
    <item>
      <title>How to run Cypress tests in parallel with code example</title>
      <dc:creator>Srikanth Kyatham</dc:creator>
      <pubDate>Wed, 03 Aug 2022 19:14:00 +0000</pubDate>
      <link>https://dev.to/srikanthkyatham/cypress-tests-run-in-parallel-443h</link>
      <guid>https://dev.to/srikanthkyatham/cypress-tests-run-in-parallel-443h</guid>
      <description>&lt;p&gt;Hi&lt;/p&gt;

&lt;p&gt;Lately we have been adding multiple cypress tests and the tests run have been taking more and more time on ci and local environments as the cypress spec files are run or executed sequentially. &lt;/p&gt;

&lt;p&gt;Luckily we have organised our tests in different folders.&lt;br&gt;
I wrote a small script which would spawn cypress run for different folders.&lt;/p&gt;

&lt;p&gt;Here is the script&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// run_test_in_parallel.js
const { exec } = require("child_process");
const util = require("util");
const execPromisified = util.promisify(exec);

const baseCommand = "npx cypress run --env coverage=false --spec ";

const specs = [
  "cypress/e2e/folder1/*.cy.*",
  "cypress/e2e/folder2/*.cy.*",
];

const runCypressSpec = async (command) =&amp;gt; {
  try {
    const { stdout, stderr } = await execPromisified(command);
    console.log("stdout:", stdout);
    console.log("stderr:", stderr);
    return Promise.resolve();
  } catch (e) {
    console.error(e);
    return Promise.reject(e);
  }
};

const runAllTests = async () =&amp;gt; {
  const promises = specs.map((spec) =&amp;gt; {
    const specRunCommand = baseCommand + spec;
    return runCypressSpec(specRunCommand);
  });
  console.log("all spec runs started");
  try {
    console.time("all tests");
    // using Promise.all waiting for 
    // all successful execution of test cases 
    await Promise.all(promises);
    console.timeEnd("all tests");
    // Continuous Integration expects 0 for success case
    return 0;
  } catch (e) {
    console.error(e);
    // Continuous Integration expects non-zero for failure case
    return 255;
  }
};

runAllTests();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I have added a package.json script to run the above command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"scripts": {
  "test:e2e_run_parallel": "node ./location/of/run_test_in_parallel.js"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hope this helps any one having the same issues. &lt;/p&gt;

</description>
      <category>cypress</category>
      <category>testing</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Rescript React Lifting Component state</title>
      <dc:creator>Srikanth Kyatham</dc:creator>
      <pubDate>Tue, 12 Oct 2021 19:20:18 +0000</pubDate>
      <link>https://dev.to/srikanthkyatham/rescript-react-lifting-component-state-4nn8</link>
      <guid>https://dev.to/srikanthkyatham/rescript-react-lifting-component-state-4nn8</guid>
      <description>&lt;p&gt;Let's see how lift state in rescript&lt;/p&gt;

&lt;p&gt;Let's assume there is button component which increments count like below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// button.res
type action =
    | Add

type state = {
  count: int
}

let reducer = (state, action) =&amp;gt; {
    switch action {
        | Add =&amp;gt; {count: state.count + 1}
    }
}

let getInitialState = () =&amp;gt; {
    let initialState = {
       count: 0
    }
    initialState
}

let make = (state, dispatch) =&amp;gt; {
    let onClick = () =&amp;gt; {
        dispatch(Add)
    }

    &amp;lt;button onClick&amp;gt;{React.string("add")}&amp;lt;/button&amp;gt;
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we want to use the component in a parent component, which uses the component but also wants to store the state of the child in it. One of the way I figured is like below, in two steps&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;One of the parent action would be variant encapsulating the child action&lt;/li&gt;
&lt;li&gt;dispatch which is passed to the child component here button would take the child action and encapsulate in the parent action and dispatch to the parent state&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can see the above steps in action below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// parent
type action = {
    | Text(string)
    | Button(Button.action)
}

type state = {
    text: string,
    buttonState: Button.state
}

let reducer = (state, action) =&amp;gt; {
    switch action {
        | Text(text) =&amp;gt; {...state, text: text}
        | Button(action) =&amp;gt; 
            let {buttonState} = state
            let newButtonState = Button.reducer(buttonState, action)
            {...state, buttonState: newButtonState}
    }
}

let getInitialState = () =&amp;gt; {
    let initialState = {
        text: "",
        buttonState: Button.getInitialState()
    }
    initialState
}


let make = () =&amp;gt; {
   let {state, dispatch}  = React.useReducer(reducer, getInitialState())

    let childDispatch = (action: Button.action) =&amp;gt; {
    dispatch(Button(action))
    }

    let onChange = () =&amp;gt; {

    }

   &amp;lt;div&amp;gt;
    &amp;lt;TextInput onChange=onChange value=state.text /&amp;gt;
    &amp;lt;Button state=state.buttonState dispatch=childDispatch /&amp;gt;
   &amp;lt;/div&amp;gt;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hope this helps!&lt;/p&gt;

</description>
      <category>rescript</category>
      <category>react</category>
    </item>
  </channel>
</rss>
