<?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: Kishan Srivastava</title>
    <description>The latest articles on DEV Community by Kishan Srivastava (@superman01).</description>
    <link>https://dev.to/superman01</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3308249%2F2feb1e11-75ad-4169-8340-2f781a3420f1.jpg</url>
      <title>DEV Community: Kishan Srivastava</title>
      <link>https://dev.to/superman01</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/superman01"/>
    <language>en</language>
    <item>
      <title>updates</title>
      <dc:creator>Kishan Srivastava</dc:creator>
      <pubDate>Tue, 08 Sep 2026 19:54:37 +0000</pubDate>
      <link>https://dev.to/superman01/updates-1cgh</link>
      <guid>https://dev.to/superman01/updates-1cgh</guid>
      <description>&lt;p&gt;Explored SharePoint’s page/section customization and web parts, and recreated the Key Contacts section to understand the layout and styling possibilities. Got a better idea of what we can achieve natively and the current limitations.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>SharePoint</title>
      <dc:creator>Kishan Srivastava</dc:creator>
      <pubDate>Tue, 08 Sep 2026 08:55:59 +0000</pubDate>
      <link>https://dev.to/superman01/sharepoint-2nhd</link>
      <guid>https://dev.to/superman01/sharepoint-2nhd</guid>
      <description>&lt;p&gt;Use this as the follow-up prompt in SharePoint Copilot:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Refine the current Key Contacts section with these specific changes while keeping the existing content, layout, and overall styling:&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Global Footprint: Change the US, EMEA, APAC and India options from full-width rectangular tabs into small pill/capsule-shaped buttons. Keep all four buttons grouped together and aligned to the left of the section rather than stretching across the entire width. Keep India as the active/selected option.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Section background: Change the entire Key Contacts section background to solid black. Remove the current teal/green background. Keep the existing cyan/green accent elements.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Contact cards: Keep the four cards in the same horizontal row. For each card, move the initials (PA, AR, MD, UG) to the left of the person's name and designation. Display the initials inside a circular avatar with a green/cyan background matching the accent color currently used in the section.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Keep the names, designations, text, card borders, spacing and bottom-right accent elements unchanged. Maintain a clean, premium corporate/technology appearance.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Change footprint to left-aligned pills; make section black; put initials in green circles left of names.&lt;/p&gt;

</description>
      <category>design</category>
      <category>frontend</category>
      <category>webdev</category>
      <category>website</category>
    </item>
    <item>
      <title>Automate</title>
      <dc:creator>Kishan Srivastava</dc:creator>
      <pubDate>Tue, 25 Aug 2026 10:08:39 +0000</pubDate>
      <link>https://dev.to/superman01/automate-2j15</link>
      <guid>https://dev.to/superman01/automate-2j15</guid>
      <description>&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;playwright.sync_api&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sync_playwright&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;TimeoutError&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;PlaywrightTimeoutError&lt;/span&gt;

&lt;span class="n"&gt;SITE_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://YOUR-SITE-URL-HERE&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="n"&gt;EMAIL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;kishan-a.srivastava@db.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;PASSWORD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;abc123&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;wait_for_page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;120_000&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wait_for_load_state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;domcontentloaded&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;PlaywrightTimeoutError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Page is taking longer than expected to load...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Continuing anyway.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;sync_playwright&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;browser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chromium&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;headless&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;slow_mo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new_page&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_default_timeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;60_000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_default_navigation_timeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;120_000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Opening website...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;SITE_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;wait_until&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;domcontentloaded&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;120_000&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Website opened.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Looking for &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Continue with DWS UAT&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;continue_button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;button[type=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;submit&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;]&lt;/span&gt;&lt;span class="sh"&gt;'&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="n"&gt;has_text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Continue with DWS UAT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;continue_button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wait_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;visible&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;continue_button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Clicked &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Continue with DWS UAT&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;wait_for_page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Waiting for email field...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;email_field&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;input#i0116[type=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;]&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;email_field&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wait_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;visible&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;email_field&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EMAIL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Email entered.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;next_button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;input#idSIButton9[type=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;submit&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;]&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;next_button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wait_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;visible&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;next_button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Next clicked.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;wait_for_page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Waiting for password field...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;password_field&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;input#i0118[type=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;password&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;]&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;password_field&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wait_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;visible&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;60_000&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;PlaywrightTimeoutError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Password field has not appeared yet.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;A company verification/MFA step may be running.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Complete the verification manually if required.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Waiting for the password field...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="n"&gt;password_field&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wait_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;visible&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;300_000&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Password field found.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;password_field&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PASSWORD&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Password entered.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;submit_button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;input#idSIButton9[type=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;submit&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;]&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;submit_button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wait_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;visible&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;submit_button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Password submitted.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Waiting for final page to load...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;wait_for_page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;120_000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;==========================================&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;LOGIN FLOW COMPLETED&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;==========================================&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Current URL:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Browser will remain open for 30 seconds...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
    <item>
      <title>iptester-redesigned</title>
      <dc:creator>Kishan Srivastava</dc:creator>
      <pubDate>Mon, 30 Jun 2025 09:50:56 +0000</pubDate>
      <link>https://dev.to/superman01/iptester-redesigned-2hle</link>
      <guid>https://dev.to/superman01/iptester-redesigned-2hle</guid>
      <description>&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useState, useCallback } from 'react';
import { useUnleashContext, useUnleashClient } from '@unleash/proxy-client-react';
import styled, { keyframes, css } from 'styled-components';

// --- Keyframe Animations ---

const fadeIn = keyframes`
  from { 
    opacity: 0; 
    transform: translateY(20px) scale(0.95); 
  }
  to { 
    opacity: 1; 
    transform: translateY(0) scale(1); 
  }
`;

const slideIn = keyframes`
  from { 
    opacity: 0; 
    transform: translateX(-20px); 
  }
  to { 
    opacity: 1; 
    transform: translateX(0); 
  }
`;

const spin = keyframes`
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
`;

const pulse = keyframes`
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.05); }
`;

const gradientShift = keyframes`
  0% { background-position: 0% 50%; }
  50% { background-position: 100% 50%; }
  100% { background-position: 0% 50%; }
`;

const float = keyframes`
  0%, 100% { transform: translateY(0px); }
  50% { transform: translateY(-10px); }
`;

// --- Modern Styled Components ---

const Container = styled.div`
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  min-height: 100vh;
  padding: 2rem 1rem;
  display: flex;
  justify-content: center;
  align-items: flex-start;
  position: relative;

  &amp;amp;::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: 
      radial-gradient(circle at 20% 50%, rgba(120, 119, 198, 0.3) 0%, transparent 50%),
      radial-gradient(circle at 80% 20%, rgba(255, 118, 117, 0.3) 0%, transparent 50%),
      radial-gradient(circle at 40% 80%, rgba(255, 177, 153, 0.3) 0%, transparent 50%);
    pointer-events: none;
  }
`;

const MaxWidthWrapper = styled.div`
  max-width: 1400px;
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 2rem;
  position: relative;
  z-index: 1;
`;

const Card = styled.div`
  background: rgba(255, 255, 255, 0.95);
  backdrop-filter: blur(20px);
  border-radius: 24px;
  box-shadow: 
    0 32px 64px -12px rgba(0, 0, 0, 0.25),
    0 0 0 1px rgba(255, 255, 255, 0.05);
  padding: 2rem;
  border: 1px solid rgba(255, 255, 255, 0.2);
  animation: ${fadeIn} 0.6s ease-out;
  transition: all 0.3s ease;

  &amp;amp;:hover {
    transform: translateY(-2px);
    box-shadow: 
      0 40px 80px -12px rgba(0, 0, 0, 0.3),
      0 0 0 1px rgba(255, 255, 255, 0.1);
  }
`;

const Header = styled.div`
  text-align: center;
  margin-bottom: 1.5rem;
  animation: ${slideIn} 0.8s ease-out;
`;

const Title = styled.h1`
  font-size: 3rem;
  font-weight: 800;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 50%, #f093fb 100%);
  background-size: 200% 200%;
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  margin-bottom: 0.75rem;
  animation: ${gradientShift} 4s ease infinite;
  line-height: 1.2;
`;

const Subtitle = styled.p`
  font-size: 1.25rem;
  color: #64748b;
  font-weight: 500;
  max-width: 600px;
  margin: 0 auto;
  line-height: 1.6;
`;

const SectionTitle = styled.h2`
  font-size: 1.75rem;
  font-weight: 700;
  background: linear-gradient(135deg, #1e293b, #475569);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  margin-bottom: 1.5rem;
  display: flex;
  align-items: center;
  gap: 0.75rem;

  &amp;amp;::before {
    content: '';
    width: 4px;
    height: 24px;
    background: linear-gradient(135deg, #667eea, #764ba2);
    border-radius: 2px;
  }
`;

const ConfigGrid = styled.div`
  display: grid;
  gap: 2rem;
  margin-bottom: 2rem;
`;

const InputGroup = styled.div`
  display: grid;
  grid-template-columns: 1fr 1fr auto;
  gap: 1rem;
  align-items: end;

  @media (max-width: 768px) {
    grid-template-columns: 1fr;
  }
`;

const DiscreteInputGroup = styled.div`
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 1rem;
  align-items: end;

  @media (max-width: 768px) {
    grid-template-columns: 1fr;
  }
`;

const InputField = styled.div`
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
`;

const Label = styled.label`
  font-size: 0.875rem;
  font-weight: 600;
  color: #374151;
  letter-spacing: 0.025em;
`;

const Input = styled.input`
  width: 100%;
  padding: 1rem 1.25rem;
  border: 2px solid #e2e8f0;
  border-radius: 16px;
  font-size: 1rem;
  color: #1f2937;
  background: rgba(255, 255, 255, 0.8);
  backdrop-filter: blur(10px);
  transition: all 0.3s ease;
  font-weight: 500;

  &amp;amp;::placeholder {
    color: #9ca3af;
    font-weight: 400;
  }

  &amp;amp;:focus {
    outline: none;
    border-color: #667eea;
    background: rgba(255, 255, 255, 0.95);
    box-shadow: 
      0 0 0 4px rgba(102, 126, 234, 0.1),
      0 8px 25px -5px rgba(102, 126, 234, 0.2);
    transform: translateY(-1px);
  }
`;

const Button = styled.button`
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.75rem;
  padding: 1rem 2rem;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: white;
  font-weight: 600;
  border-radius: 16px;
  border: none;
  cursor: pointer;
  transition: all 0.3s ease;
  white-space: nowrap;
  font-size: 0.975rem;
  letter-spacing: 0.025em;
  position: relative;
  overflow: hidden;

  &amp;amp;::before {
    content: '';
    position: absolute;
    top: 0;
    left: -100%;
    width: 100%;
    height: 100%;
    background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
    transition: left 0.5s;
  }

  &amp;amp;:hover {
    transform: translateY(-2px);
    box-shadow: 0 15px 35px -5px rgba(102, 126, 234, 0.4);

    &amp;amp;::before {
      left: 100%;
    }
  }

  &amp;amp;:active {
    transform: translateY(0);
  }

  &amp;amp;:disabled {
    background: linear-gradient(135deg, #9ca3af, #6b7280);
    cursor: not-allowed;
    transform: none;
    box-shadow: none;

    &amp;amp;::before {
      display: none;
    }
  }
`;

const Spinner = styled.div`
  border: 3px solid rgba(255, 255, 255, 0.3);
  border-top: 3px solid white;
  border-radius: 50%;
  width: 1.25rem;
  height: 1.25rem;
  animation: ${spin} 1s linear infinite;
`;

const ErrorMessage = styled.div`
  background: linear-gradient(135deg, #fee2e2, #fecaca);
  color: #dc2626;
  font-size: 0.875rem;
  padding: 1rem 1.5rem;
  border-radius: 12px;
  text-align: center;
  border: 1px solid #fca5a5;
  font-weight: 500;
  animation: ${fadeIn} 0.3s ease-out;
`;

const IpCardsGrid = styled.div`
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: 1.5rem;
  margin-top: 2rem;
`;

const IpCardContainer = styled.div`
  background: rgba(255, 255, 255, 0.95);
  backdrop-filter: blur(20px);
  border-radius: 20px;
  box-shadow: 
    0 20px 40px -12px rgba(0, 0, 0, 0.15),
    0 0 0 1px rgba(255, 255, 255, 0.1);
  padding: 1.5rem;
  border: 1px solid rgba(255, 255, 255, 0.2);
  display: flex;
  flex-direction: column;
  gap: 1rem;
  animation: ${fadeIn} 0.5s ease-out;
  transition: all 0.3s ease;
  position: relative;
  overflow: hidden;

  &amp;amp;::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 4px;
    background: linear-gradient(135deg, #667eea, #764ba2);
    border-radius: 20px 20px 0 0;
  }

  &amp;amp;:hover {
    transform: translateY(-4px) scale(1.02);
    box-shadow: 
      0 32px 64px -12px rgba(0, 0, 0, 0.25),
      0 0 0 1px rgba(255, 255, 255, 0.2);
  }
`;

const IpCardHeader = styled.h3`
  font-size: 1.5rem;
  font-weight: 700;
  color: #1f2937;
  margin: 0;
  font-family: 'Monaco', 'Menlo', monospace;
  background: linear-gradient(135deg, #1f2937, #374151);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
`;

const IpCardDetail = styled.div`
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 0.925rem;
  padding: 0.5rem 0;
`;

const IpCardLabel = styled.span`
  font-weight: 600;
  color: #6b7280;
  font-size: 0.875rem;
`;

const IpCardValue = styled.span`
  font-weight: 700;
  color: #1f2937;
  font-size: 0.875rem;
`;

const StatusBadge = styled.span`
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 1rem;
  border-radius: 50px;
  font-size: 0.875rem;
  font-weight: 600;
  transition: all 0.3s ease;

  ${(props) =&amp;gt; {
    switch (props.type) {
      case 'enabled':
        return css`
          background: linear-gradient(135deg, #d1fae5, #a7f3d0);
          color: #059669;
          border: 1px solid #6ee7b7;
          animation: ${pulse} 2s ease-in-out infinite;
        `;
      case 'disabled':
        return css`
          background: linear-gradient(135deg, #fee2e2, #fecaca);
          color: #dc2626;
          border: 1px solid #fca5a5;
        `;
      case 'loading':
        return css`
          background: linear-gradient(135deg, #eff6ff, #dbeafe);
          color: #2563eb;
          border: 1px solid #93c5fd;
        `;
      case 'error':
        return css`
          background: linear-gradient(135deg, #fee2e2, #fecaca);
          color: #dc2626;
          border: 1px solid #fca5a5;
        `;
      default:
        return css`
          background: linear-gradient(135deg, #f3f4f6, #e5e7eb);
          color: #6b7280;
          border: 1px solid #d1d5db;
        `;
    }
  }}
`;

const TestButton = styled(Button)`
  width: 100%;
  margin-top: 0.5rem;
  background: linear-gradient(135deg, #4f46e5, #7c3aed);
  font-size: 0.875rem;
  padding: 0.875rem 1.5rem;

  &amp;amp;:hover {
    box-shadow: 0 15px 35px -5px rgba(79, 70, 229, 0.4);
  }

  &amp;amp;:disabled {
    background: linear-gradient(135deg, #9ca3af, #6b7280);
  }
`;

const EmptyState = styled.div`
  text-align: center;
  padding: 4rem 2rem;
  background: rgba(255, 255, 255, 0.95);
  backdrop-filter: blur(20px);
  border-radius: 24px;
  box-shadow: 
    0 32px 64px -12px rgba(0, 0, 0, 0.15),
    0 0 0 1px rgba(255, 255, 255, 0.1);
  border: 1px solid rgba(255, 255, 255, 0.2);
  animation: ${fadeIn} 0.6s ease-out;
  position: relative;
  overflow: hidden;

  &amp;amp;::before {
    content: '';
    position: absolute;
    top: -50%;
    left: -50%;
    width: 200%;
    height: 200%;
    background: 
      radial-gradient(circle, rgba(102, 126, 234, 0.1) 0%, transparent 50%);
    animation: ${float} 6s ease-in-out infinite;
  }
`;

const EmptyStateIcon = styled.div`
  font-size: 4rem;
  margin-bottom: 1.5rem;
  display: block;
  background: linear-gradient(135deg, #667eea, #764ba2);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  animation: ${float} 3s ease-in-out infinite;
`;

const EmptyStateTitle = styled.h3`
  font-size: 1.75rem;
  font-weight: 700;
  background: linear-gradient(135deg, #1f2937, #374151);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  margin-bottom: 1rem;
`;

const EmptyStateText = styled.p`
  font-size: 1.125rem;
  color: #6b7280;
  margin-bottom: 1.5rem;
  line-height: 1.6;
  max-width: 400px;
  margin-left: auto;
  margin-right: auto;
`;

const EmptyStateNote = styled.p`
  font-size: 0.925rem;
  color: #9ca3af;
  font-style: italic;
  background: rgba(102, 126, 234, 0.05);
  padding: 1rem 1.5rem;
  border-radius: 12px;
  border: 1px solid rgba(102, 126, 234, 0.1);
  max-width: 500px;
  margin: 0 auto;
`;

const StatsBar = styled.div`
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 1rem;
  margin-top: 2rem;
  padding: 1.5rem;
  background: rgba(255, 255, 255, 0.6);
  backdrop-filter: blur(10px);
  border-radius: 16px;
  border: 1px solid rgba(255, 255, 255, 0.3);
`;

const StatItem = styled.div`
  text-align: center;
  padding: 0.5rem;
`;

const StatValue = styled.div`
  font-size: 1.5rem;
  font-weight: 800;
  background: linear-gradient(135deg, #667eea, #764ba2);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
`;

const StatLabel = styled.div`
  font-size: 0.75rem;
  color: #6b7280;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin-top: 0.25rem;
`;

// --- Helper Functions for IP Conversion ---
const ipToNumber = (ip) =&amp;gt; {
  return ip.split('.').reduce((acc, octet) =&amp;gt; (acc &amp;lt;&amp;lt; 8) + parseInt(octet, 10), 0) &amp;gt;&amp;gt;&amp;gt; 0;
};

const numberToIp = (num) =&amp;gt; {
  return [
    (num &amp;gt;&amp;gt;&amp;gt; 24) &amp;amp; 0xFF,
    (num &amp;gt;&amp;gt;&amp;gt; 16) &amp;amp; 0xFF,
    (num &amp;gt;&amp;gt;&amp;gt; 8) &amp;amp; 0xFF,
    num &amp;amp; 0xFF
  ].join('.');
};

// --- IP Card Component ---
const IpCard = ({ ipData, featureFlagName, onTestFlag }) =&amp;gt; {
  const { id, ipAddress, testResult } = ipData;

  const handleTestClick = () =&amp;gt; {
    onTestFlag(id, ipAddress);
  };

  return (
    &amp;lt;IpCardContainer&amp;gt;
      &amp;lt;IpCardHeader&amp;gt;🌐 {ipAddress}&amp;lt;/IpCardHeader&amp;gt;
      &amp;lt;IpCardDetail&amp;gt;
        &amp;lt;IpCardLabel&amp;gt;Status:&amp;lt;/IpCardLabel&amp;gt;
        {testResult ? (
          testResult.isLoading ? (
            &amp;lt;StatusBadge type="loading"&amp;gt;
              &amp;lt;Spinner style={{ width: '1rem', height: '1rem', borderTopColor: '#2563eb' }} /&amp;gt;
              Testing...
            &amp;lt;/StatusBadge&amp;gt;
          ) : testResult.error ? (
            &amp;lt;StatusBadge type="error"&amp;gt;❌ Error&amp;lt;/StatusBadge&amp;gt;
          ) : testResult.enabled ? (
            &amp;lt;StatusBadge type="enabled"&amp;gt;✅ Enabled&amp;lt;/StatusBadge&amp;gt;
          ) : (
            &amp;lt;StatusBadge type="disabled"&amp;gt;❌ Disabled&amp;lt;/StatusBadge&amp;gt;
          )
        ) : (
          &amp;lt;StatusBadge&amp;gt;⏳ Not Tested&amp;lt;/StatusBadge&amp;gt;
        )}
      &amp;lt;/IpCardDetail&amp;gt;
      {testResult &amp;amp;&amp;amp; testResult.timestamp &amp;amp;&amp;amp; (
        &amp;lt;IpCardDetail&amp;gt;
          &amp;lt;IpCardLabel&amp;gt;Last Test:&amp;lt;/IpCardLabel&amp;gt;
          &amp;lt;IpCardValue&amp;gt;{testResult.timestamp}&amp;lt;/IpCardValue&amp;gt;
        &amp;lt;/IpCardDetail&amp;gt;
      )}
      &amp;lt;TestButton onClick={handleTestClick} disabled={testResult?.isLoading}&amp;gt;
        {testResult?.isLoading ? (
          &amp;lt;&amp;gt;
            &amp;lt;Spinner style={{ width: '1rem', height: '1rem' }} /&amp;gt;
            Testing...
          &amp;lt;/&amp;gt;
        ) : (
          &amp;lt;&amp;gt;
            🧪 Test Flag
          &amp;lt;/&amp;gt;
        )}
      &amp;lt;/TestButton&amp;gt;
    &amp;lt;/IpCardContainer&amp;gt;
  );
};

// --- Main IP Range Simulator Component ---
const IPRangeSimulator = () =&amp;gt; {
  const [featureFlagName, setFeatureFlagName] = useState('geo-targeted-feature');
  const [startIp, setStartIp] = useState('192.168.1.1');
  const [endIp, setEndIp] = useState('192.168.1.10');
  const [discreteIp, setDiscreteIp] = useState('');
  const [ipCards, setIpCards] = useState([]);
  const [errorMessage, setErrorMessage] = useState('');

  const unleashClient = useUnleashClient();
  const updateContext = useUnleashContext();

  // Calculate stats
  const stats = {
    total: ipCards.length,
    tested: ipCards.filter(card =&amp;gt; card.testResult &amp;amp;&amp;amp; !card.testResult.isLoading).length,
    enabled: ipCards.filter(card =&amp;gt; card.testResult &amp;amp;&amp;amp; card.testResult.enabled &amp;amp;&amp;amp; !card.testResult.error).length,
    disabled: ipCards.filter(card =&amp;gt; card.testResult &amp;amp;&amp;amp; !card.testResult.enabled &amp;amp;&amp;amp; !card.testResult.error).length,
  };

  const addRangeCards = useCallback(() =&amp;gt; {
    setErrorMessage('');
    try {
      const startNum = ipToNumber(startIp);
      const endNum = ipToNumber(endIp);

      if (isNaN(startNum) || isNaN(endNum) || startNum &amp;gt; endNum) {
        setErrorMessage('Invalid IP range. Please enter valid start and end IPs.');
        return;
      }

      const newCards = [];
      for (let i = startNum; i &amp;lt;= endNum; i++) {
        newCards.push({
          id: crypto.randomUUID(),
          ipAddress: numberToIp(i),
          testResult: null,
        });
        if (newCards.length &amp;gt; 100) {
          setErrorMessage('Too many IPs in range. Max 100 cards allowed per range generation.');
          break;
        }
      }
      setIpCards(prevCards =&amp;gt; [...prevCards, ...newCards]);
      setStartIp('');
      setEndIp('');
    } catch (e) {
      setErrorMessage('Error parsing IP range. Please check format.');
      console.error(e);
    }
  }, [startIp, endIp]);

  const addDiscreteCard = useCallback(() =&amp;gt; {
    setErrorMessage('');
    if (!discreteIp || !/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(discreteIp)) {
      setErrorMessage('Please enter a valid discrete IP address.');
      return;
    }
    setIpCards(prevCards =&amp;gt; [
      ...prevCards,
      {
        id: crypto.randomUUID(),
        ipAddress: discreteIp,
        testResult: null,
      },
    ]);
    setDiscreteIp('');
  }, [discreteIp]);

  const handleTestFlag = useCallback(async (cardId, ipAddress) =&amp;gt; {
    setIpCards(prevCards =&amp;gt;
      prevCards.map(card =&amp;gt;
        card.id === cardId ? { ...card, testResult: { ...card.testResult, isLoading: true, error: false } } : card
      )
    );
    setErrorMessage('');

    try {
      await updateContext({
        remoteAddress: ipAddress,
        userId: 'simulator-user-' + ipAddress.replace(/\./g, '-'),
      });
      await new Promise((resolve) =&amp;gt; setTimeout(resolve, 100));

      const isEnabled = unleashClient.isEnabled(featureFlagName);

      setIpCards(prevCards =&amp;gt;
        prevCards.map(card =&amp;gt;
          card.id === cardId
            ? {
                ...card,
                testResult: {
                  ip: ipAddress,
                  enabled: isEnabled,
                  timestamp: new Date().toLocaleTimeString(),
                  isLoading: false,
                  error: false,
                },
              }
            : card
        )
      );
    } catch (error) {
      console.error(`Error testing flag for IP ${ipAddress}:`, error);
      setIpCards(prevCards =&amp;gt;
        prevCards.map(card =&amp;gt;
          card.id === cardId
            ? {
                ...card,
                testResult: {
                  ip: ipAddress,
                  enabled: false,
                  timestamp: new Date().toLocaleTimeString(),
                  isLoading: false,
                  error: true,
                },
              }
            : card
        )
      );
      setErrorMessage(`Failed to test flag for ${ipAddress}. Check console.`);
    }
  }, [featureFlagName, updateContext, unleashClient]);

  return (
    &amp;lt;Container&amp;gt;
      &amp;lt;MaxWidthWrapper&amp;gt;
        {/* Header */}
        &amp;lt;Card&amp;gt;
          &amp;lt;Header&amp;gt;
            &amp;lt;Title&amp;gt;🗺️ Unleash IP Strategy Simulator&amp;lt;/Title&amp;gt;
            &amp;lt;Subtitle&amp;gt;
              Generate and test feature flag status for multiple IP addresses with modern, intuitive interface.
            &amp;lt;/Subtitle&amp;gt;
          &amp;lt;/Header&amp;gt;
        &amp;lt;/Card&amp;gt;

        {/* Configuration Panel */}
        &amp;lt;Card&amp;gt;
          &amp;lt;SectionTitle&amp;gt;⚙️ Configuration &amp;amp; IP Generation&amp;lt;/SectionTitle&amp;gt;

          &amp;lt;ConfigGrid&amp;gt;
            &amp;lt;InputField&amp;gt;
              &amp;lt;Label htmlFor="flagName"&amp;gt;🚩 Feature Flag Name&amp;lt;/Label&amp;gt;
              &amp;lt;Input
                id="flagName"
                type="text"
                value={featureFlagName}
                onChange={(e) =&amp;gt; setFeatureFlagName(e.target.value)}
                placeholder="e.g., geo-targeted-feature"
              /&amp;gt;
            &amp;lt;/InputField&amp;gt;

            &amp;lt;InputGroup&amp;gt;
              &amp;lt;InputField&amp;gt;
                &amp;lt;Label htmlFor="startIp"&amp;gt;🚀 Start IP (Range)&amp;lt;/Label&amp;gt;
                &amp;lt;Input
                  id="startIp"
                  type="text"
                  value={startIp}
                  onChange={(e) =&amp;gt; setStartIp(e.target.value)}
                  placeholder="e.g., 192.168.1.1"
                /&amp;gt;
              &amp;lt;/InputField&amp;gt;
              &amp;lt;InputField&amp;gt;
                &amp;lt;Label htmlFor="endIp"&amp;gt;🏁 End IP (Range)&amp;lt;/Label&amp;gt;
                &amp;lt;Input
                  id="endIp"
                  type="text"
                  value={endIp}
                  onChange={(e) =&amp;gt; setEndIp(e.target.value)}
                  placeholder="e.g., 192.168.1.10"
                /&amp;gt;
              &amp;lt;/InputField&amp;gt;
              &amp;lt;Button onClick={addRangeCards}&amp;gt;
                📊 Generate Range
              &amp;lt;/Button&amp;gt;
            &amp;lt;/InputGroup&amp;gt;

            &amp;lt;DiscreteInputGroup&amp;gt;
              &amp;lt;InputField&amp;gt;
                &amp;lt;Label htmlFor="discreteIp"&amp;gt;🎯 Discrete IP Address&amp;lt;/Label&amp;gt;
                &amp;lt;Input

&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;&amp;lt;DiscreteInputGroup&amp;gt;
              &amp;lt;InputField&amp;gt;
                &amp;lt;Label htmlFor="discreteIp"&amp;gt;🎯 Discrete IP Address&amp;lt;/Label&amp;gt;
                &amp;lt;Input
                  id="discreteIp"
                  type="text"
                  value={discreteIp}
                  onChange={(e) =&amp;gt; setDiscreteIp(e.target.value)}
                  placeholder="e.g., 203.0.113.45"
                /&amp;gt;
              &amp;lt;/InputField&amp;gt;
              &amp;lt;Button onClick={addDiscreteCard}&amp;gt;
                ➕ Add IP
              &amp;lt;/Button&amp;gt;
            &amp;lt;/DiscreteInputGroup&amp;gt;
          &amp;lt;/ConfigGrid&amp;gt;

          {errorMessage &amp;amp;&amp;amp; (
            &amp;lt;ErrorMessage&amp;gt;{errorMessage}&amp;lt;/ErrorMessage&amp;gt;
          )}
        &amp;lt;/Card&amp;gt;

        {/* Stats Bar */}
        {ipCards.length &amp;gt; 0 &amp;amp;&amp;amp; (
          &amp;lt;StatsBar&amp;gt;
            &amp;lt;StatItem&amp;gt;
              &amp;lt;StatValue&amp;gt;{stats.total}&amp;lt;/StatValue&amp;gt;
              &amp;lt;StatLabel&amp;gt;Total IPs&amp;lt;/StatLabel&amp;gt;
            &amp;lt;/StatItem&amp;gt;
            &amp;lt;StatItem&amp;gt;
              &amp;lt;StatValue&amp;gt;{stats.tested}&amp;lt;/StatValue&amp;gt;
              &amp;lt;StatLabel&amp;gt;Tested&amp;lt;/StatLabel&amp;gt;
            &amp;lt;/StatItem&amp;gt;
            &amp;lt;StatItem&amp;gt;
              &amp;lt;StatValue&amp;gt;{stats.enabled}&amp;lt;/StatValue&amp;gt;
              &amp;lt;StatLabel&amp;gt;Enabled&amp;lt;/StatLabel&amp;gt;
            &amp;lt;/StatItem&amp;gt;
            &amp;lt;StatItem&amp;gt;
              &amp;lt;StatValue&amp;gt;{stats.disabled}&amp;lt;/StatValue&amp;gt;
              &amp;lt;StatLabel&amp;gt;Disabled&amp;lt;/StatLabel&amp;gt;
            &amp;lt;/StatItem&amp;gt;
          &amp;lt;/StatsBar&amp;gt;
        )}

        {/* IP Cards Display */}
        {ipCards.length &amp;gt; 0 ? (
          &amp;lt;IpCardsGrid&amp;gt;
            {ipCards.map((ipData) =&amp;gt; (
              &amp;lt;IpCard
                key={ipData.id}
                ipData={ipData}
                featureFlagName={featureFlagName}
                onTestFlag={handleTestFlag}
              /&amp;gt;
            ))}
          &amp;lt;/IpCardsGrid&amp;gt;
        ) : (
          &amp;lt;EmptyState&amp;gt;
            &amp;lt;EmptyStateIcon&amp;gt;🚀&amp;lt;/EmptyStateIcon&amp;gt;
            &amp;lt;EmptyStateTitle&amp;gt;Ready to Start Testing&amp;lt;/EmptyStateTitle&amp;gt;
            &amp;lt;EmptyStateText&amp;gt;
              Enter an IP range or discrete IP address above to generate cards and begin testing your feature flags.
            &amp;lt;/EmptyStateText&amp;gt;
            &amp;lt;EmptyStateNote&amp;gt;
              💡 Ensure your feature flag "{featureFlagName}" has an "IP Address" strategy configured in Unleash for accurate testing results.
            &amp;lt;/EmptyStateNote&amp;gt;
          &amp;lt;/EmptyState&amp;gt;
        )}
      &amp;lt;/MaxWidthWrapper&amp;gt;
    &amp;lt;/Container&amp;gt;
  );
};

export default IPRangeSimulator;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
    <item>
      <title>iptester2</title>
      <dc:creator>Kishan Srivastava</dc:creator>
      <pubDate>Mon, 30 Jun 2025 09:38:08 +0000</pubDate>
      <link>https://dev.to/superman01/iptester2-4lhi</link>
      <guid>https://dev.to/superman01/iptester2-4lhi</guid>
      <description>&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useState, useCallback } from 'react';
import { useUnleashContext, useUnleashClient } from '@unleash/proxy-client-react';
import styled, { keyframes, css } from 'styled-components';

// --- Styled Components ---

const fadeIn = keyframes`
  from { opacity: 0; transform: translateY(-10px); }
  to { opacity: 1; transform: translateY(0); }
`;

const spin = keyframes`
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
`;

const Container = styled.div`
  font-family: 'Inter', sans-serif;
  background-color: #f8fafc; /* Tailwind gray-50 */
  min-height: 100vh;
  padding: 2rem;
  display: flex;
  justify-content: center;
  align-items: flex-start;
`;

const MaxWidthWrapper = styled.div`
  max-width: 1200px; /* Increased max-width for more cards */
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 1.5rem; /* gap-6 */
`;

const Card = styled.div`
  background-color: white;
  border-radius: 0.75rem; /* rounded-xl */
  box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); /* shadow-xl */
  padding: 1.5rem; /* p-6 */
  border: 1px solid #e2e8f0; /* border-gray-200 */
`;

const Header = styled.div`
  text-align: center;
  margin-bottom: 1rem; /* mb-4 */
`;

const Title = styled.h1`
  font-size: 1.875rem; /* text-3xl */
  font-weight: 700; /* font-bold */
  color: #1a202c; /* gray-900 */
  margin-bottom: 0.5rem; /* mb-2 */
`;

const Subtitle = styled.p`
  font-size: 1.125rem; /* text-lg */
  color: #4a5568; /* gray-600 */
`;

const SectionTitle = styled.h2`
  font-size: 1.5rem; /* text-2xl */
  font-weight: 600; /* font-semibold */
  color: #2d3748; /* gray-800 */
  margin-bottom: 1rem; /* mb-4 */
`;

const InputGroup = styled.div`
  display: flex;
  flex-direction: column;
  gap: 1rem; /* gap-4 */
  @media (min-width: 640px) { /* sm */
    flex-direction: row;
    align-items: flex-end;
  }
`;

const InputField = styled.div`
  flex: 1;
`;

const Label = styled.label`
  display: block;
  font-size: 0.875rem; /* text-sm */
  font-weight: 500; /* font-medium */
  color: #2d3748; /* gray-700 */
  margin-bottom: 0.25rem; /* mb-1 */
`;

const Input = styled.input`
  width: 100%;
  padding: 0.75rem 1rem; /* px-4 py-3 */
  border: 1px solid #cbd5e0; /* border-gray-300 */
  border-radius: 0.5rem; /* rounded-lg */
  font-size: 1rem; /* text-base */
  color: #2d3748; /* text-gray-800 */
  box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05); /* shadow-sm */
  &amp;amp;:focus {
    outline: none;
    border-color: #3b82f6; /* border-blue-500 */
    box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.3); /* ring-2 ring-blue-300 */
  }
`;

const Button = styled.button`
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem; /* gap-2 */
  padding: 0.75rem 1.5rem; /* px-6 py-3 */
  background-color: #3b82f6; /* blue-500 */
  color: white;
  font-weight: 600; /* font-semibold */
  border-radius: 0.5rem; /* rounded-lg */
  border: none;
  cursor: pointer;
  box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); /* shadow-md */
  transition: background-color 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
  white-space: nowrap; /* Prevent text wrapping */

  &amp;amp;:hover {
    background-color: #2563eb; /* blue-600 */
    box-shadow: 0 6px 8px -1px rgba(0, 0, 0, 0.15), 0 4px 6px -2px rgba(0, 0, 0, 0.08);
  }

  &amp;amp;:disabled {
    background-color: #9ca3af; /* gray-400 */
    cursor: not-allowed;
    box-shadow: none;
  }
`;

const Spinner = styled.div`
  border: 4px solid rgba(255, 255, 255, 0.3);
  border-top: 4px solid white;
  border-radius: 50%;
  width: 1.5rem; /* h-6 w-6 */
  height: 1.5rem; /* h-6 w-6 */
  animation: ${spin} 1s linear infinite;
`;

const ErrorMessage = styled.p`
  color: #dc2626; /* red-600 */
  font-size: 0.875rem; /* text-sm */
  margin-top: 0.75rem; /* mt-3 */
  text-align: center;
`;

const IpCardsGrid = styled.div`
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); /* Responsive grid */
  gap: 1.5rem; /* gap-6 */
  margin-top: 1.5rem; /* mt-6 */
`;

const IpCardContainer = styled.div`
  background-color: white;
  border-radius: 0.75rem; /* rounded-xl */
  box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); /* shadow-md */
  padding: 1.25rem; /* p-5 */
  border: 1px solid #e2e8f0; /* border-gray-200 */
  display: flex;
  flex-direction: column;
  gap: 0.75rem; /* gap-3 */
  animation: ${fadeIn} 0.5s ease-out;
`;

const IpCardHeader = styled.h3`
  font-size: 1.25rem; /* text-xl */
  font-weight: 600; /* font-semibold */
  color: #2d3748; /* gray-800 */
  margin-bottom: 0.5rem;
`;

const IpCardDetail = styled.div`
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 0.9375rem; /* text-base */
  color: #4a5568; /* gray-600 */
`;

const IpCardLabel = styled.span`
  font-weight: 500;
`;

const IpCardValue = styled.span`
  font-weight: 700;
  color: #1a202c;
`;

const StatusBadge = styled.span`
  display: inline-flex;
  padding: 0.25rem 0.75rem; /* px-3 py-1 */
  border-radius: 9999px; /* rounded-full */
  font-size: 0.875rem; /* text-sm */
  font-weight: 600; /* font-semibold */
  ${(props) =&amp;gt; {
    switch (props.type) {
      case 'enabled':
        return css`
          background-color: #dcfce7; /* green-100 */
          color: #16a34a; /* green-700 */
        `;
      case 'disabled':
        return css`
          background-color: #fee2e2; /* red-100 */
          color: #dc2626; /* red-700 */
        `;
      case 'loading':
        return css`
          background-color: #eff6ff; /* blue-50 */
          color: #2563eb; /* blue-600 */
        `;
      case 'error':
        return css`
          background-color: #fee2e2; /* red-100 */
          color: #dc2626; /* red-700 */
        `;
      default:
        return css`
          background-color: #e2e8f0;
          color: #4a5568;
        `;
    }
  }}
`;

const TestButton = styled(Button)`
  width: 100%;
  margin-top: 1rem; /* mt-4 */
  background-color: #4f46e5; /* indigo-600 */
  &amp;amp;:hover {
    background-color: #4338ca; /* indigo-700 */
  }
`;

const EmptyState = styled.div`
  text-align: center;
  padding: 3rem; /* p-12 */
  background-color: white;
  border-radius: 0.75rem; /* rounded-xl */
  box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); /* shadow-xl */
  border: 1px solid #e2e8f0; /* border-gray-200 */
  animation: ${fadeIn} 0.5s ease-out;
`;

const EmptyStateIcon = styled.span`
  font-size: 3rem; /* text-5xl */
  margin-bottom: 1rem; /* mb-4 */
  display: block;
`;

const EmptyStateTitle = styled.h3`
  font-size: 1.5rem; /* text-2xl */
  font-weight: 600; /* font-semibold */
  color: #2d3748; /* gray-800 */
  margin-bottom: 0.5rem; /* mb-2 */
`;

const EmptyStateText = styled.p`
  font-size: 1rem; /* text-base */
  color: #4a5568; /* gray-600 */
  margin-bottom: 1rem; /* mb-4 */
`;

const EmptyStateNote = styled.p`
  font-size: 0.875rem; /* text-sm */
  color: #718096; /* gray-500 */
  font-style: italic;
`;

// --- Helper Functions for IP Conversion ---
// These are crucial for handling IP ranges

const ipToNumber = (ip) =&amp;gt; {
  return ip.split('.').reduce((acc, octet) =&amp;gt; (acc &amp;lt;&amp;lt; 8) + parseInt(octet, 10), 0) &amp;gt;&amp;gt;&amp;gt; 0; // &amp;gt;&amp;gt;&amp;gt; 0 converts to unsigned 32-bit
};

const numberToIp = (num) =&amp;gt; {
  return [
    (num &amp;gt;&amp;gt;&amp;gt; 24) &amp;amp; 0xFF,
    (num &amp;gt;&amp;gt;&amp;gt; 16) &amp;amp; 0xFF,
    (num &amp;gt;&amp;gt;&amp;gt; 8) &amp;amp; 0xFF,
    num &amp;amp; 0xFF
  ].join('.');
};

// --- IP Card Component ---
// This component represents a single IP address card

const IpCard = ({ ipData, featureFlagName, onTestFlag }) =&amp;gt; {
  const { id, ipAddress, testResult } = ipData;

  const handleTestClick = () =&amp;gt; {
    onTestFlag(id, ipAddress);
  };

  return (
    &amp;lt;IpCardContainer&amp;gt;
      &amp;lt;IpCardHeader&amp;gt;{ipAddress}&amp;lt;/IpCardHeader&amp;gt;
      &amp;lt;IpCardDetail&amp;gt;
        &amp;lt;IpCardLabel&amp;gt;Status:&amp;lt;/IpCardLabel&amp;gt;
        {testResult ? (
          testResult.isLoading ? (
            &amp;lt;StatusBadge type="loading"&amp;gt;
              &amp;lt;Spinner style={{ width: '1rem', height: '1rem', borderTopColor: '#2563eb' }} /&amp;gt; Testing...
            &amp;lt;/StatusBadge&amp;gt;
          ) : testResult.error ? (
            &amp;lt;StatusBadge type="error"&amp;gt;❌ Error&amp;lt;/StatusBadge&amp;gt;
          ) : testResult.enabled ? (
            &amp;lt;StatusBadge type="enabled"&amp;gt;✅ Enabled&amp;lt;/StatusBadge&amp;gt;
          ) : (
            &amp;lt;StatusBadge type="disabled"&amp;gt;❌ Disabled&amp;lt;/StatusBadge&amp;gt;
          )
        ) : (
          &amp;lt;StatusBadge&amp;gt;Not Tested&amp;lt;/StatusBadge&amp;gt;
        )}
      &amp;lt;/IpCardDetail&amp;gt;
      {testResult &amp;amp;&amp;amp; testResult.timestamp &amp;amp;&amp;amp; (
        &amp;lt;IpCardDetail&amp;gt;
          &amp;lt;IpCardLabel&amp;gt;Last Test:&amp;lt;/IpCardLabel&amp;gt;
          &amp;lt;IpCardValue&amp;gt;{testResult.timestamp}&amp;lt;/IpCardValue&amp;gt;
        &amp;lt;/IpCardDetail&amp;gt;
      )}
      &amp;lt;TestButton onClick={handleTestClick} disabled={testResult?.isLoading}&amp;gt;
        {testResult?.isLoading ? 'Testing...' : 'Test Flag'}
      &amp;lt;/TestButton&amp;gt;
    &amp;lt;/IpCardContainer&amp;gt;
  );
};

// --- Main IP Range Simulator Component ---

const IPRangeSimulator = () =&amp;gt; {
  const [featureFlagName, setFeatureFlagName] = useState('geo-targeted-feature');
  const [startIp, setStartIp] = useState('192.168.1.1');
  const [endIp, setEndIp] = useState('192.168.1.10');
  const [discreteIp, setDiscreteIp] = useState('');
  const [ipCards, setIpCards] = useState([]); // Array to hold all IP card data
  const [errorMessage, setErrorMessage] = useState('');

  const unleashClient = useUnleashClient();
  const updateContext = useUnleashContext();

  // Function to add IPs from a range
  const addRangeCards = useCallback(() =&amp;gt; {
    setErrorMessage('');
    try {
      const startNum = ipToNumber(startIp);
      const endNum = ipToNumber(endIp);

      if (isNaN(startNum) || isNaN(endNum) || startNum &amp;gt; endNum) {
        setErrorMessage('Invalid IP range. Please enter valid start and end IPs.');
        return;
      }

      const newCards = [];
      for (let i = startNum; i &amp;lt;= endNum; i++) {
        newCards.push({
          id: crypto.randomUUID(), // Unique ID for each card
          ipAddress: numberToIp(i),
          testResult: null, // Initial state for test result
        });
        if (newCards.length &amp;gt; 100) { // Limit to prevent too many cards
            setErrorMessage('Too many IPs in range. Max 100 cards allowed per range generation.');
            break;
        }
      }
      setIpCards(prevCards =&amp;gt; [...prevCards, ...newCards]);
      setStartIp(''); // Clear inputs after adding
      setEndIp('');
    } catch (e) {
      setErrorMessage('Error parsing IP range. Please check format.');
      console.error(e);
    }
  }, [startIp, endIp]);

  // Function to add a discrete IP
  const addDiscreteCard = useCallback(() =&amp;gt; {
    setErrorMessage('');
    if (!discreteIp || !/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(discreteIp)) {
      setErrorMessage('Please enter a valid discrete IP address.');
      return;
    }
    setIpCards(prevCards =&amp;gt; [
      ...prevCards,
      {
        id: crypto.randomUUID(),
        ipAddress: discreteIp,
        testResult: null,
      },
    ]);
    setDiscreteIp(''); // Clear input after adding
  }, [discreteIp]);

  // Function to handle testing a single IP flag (called by IpCard)
  const handleTestFlag = useCallback(async (cardId, ipAddress) =&amp;gt; {
    setIpCards(prevCards =&amp;gt;
      prevCards.map(card =&amp;gt;
        card.id === cardId ? { ...card, testResult: { ...card.testResult, isLoading: true, error: false } } : card
      )
    );
    setErrorMessage(''); // Clear general error message

    try {
      await updateContext({
        remoteAddress: ipAddress,
        userId: 'simulator-user-' + ipAddress.replace(/\./g, '-'), // Ensure unique userId per IP test
      });
      await new Promise((resolve) =&amp;gt; setTimeout(resolve, 100)); // Small delay

      const isEnabled = unleashClient.isEnabled(featureFlagName);

      setIpCards(prevCards =&amp;gt;
        prevCards.map(card =&amp;gt;
          card.id === cardId
            ? {
                ...card,
                testResult: {
                  ip: ipAddress,
                  enabled: isEnabled,
                  timestamp: new Date().toLocaleTimeString(),
                  isLoading: false,
                  error: false,
                },
              }
            : card
        )
      );
    } catch (error) {
      console.error(`Error testing flag for IP ${ipAddress}:`, error);
      setIpCards(prevCards =&amp;gt;
        prevCards.map(card =&amp;gt;
          card.id === cardId
            ? {
                ...card,
                testResult: {
                  ip: ipAddress,
                  enabled: false,
                  timestamp: new Date().toLocaleTimeString(),
                  isLoading: false,
                  error: true,
                },
              }
            : card
        )
      );
      setErrorMessage(`Failed to test flag for ${ipAddress}. Check console.`);
    }
  }, [featureFlagName, updateContext, unleashClient]);

  return (
    &amp;lt;Container&amp;gt;
      &amp;lt;MaxWidthWrapper&amp;gt;
        {/* Header */}
        &amp;lt;Card&amp;gt;
          &amp;lt;Header&amp;gt;
            &amp;lt;Title&amp;gt;🗺️ Unleash IP Strategy Simulator&amp;lt;/Title&amp;gt;
            &amp;lt;Subtitle&amp;gt;
              Generate and test feature flag status for multiple IP addresses.
            &amp;lt;/Subtitle&amp;gt;
          &amp;lt;/Header&amp;gt;
        &amp;lt;/Card&amp;gt;

        {/* Configuration Panel */}
        &amp;lt;Card&amp;gt;
          &amp;lt;SectionTitle&amp;gt;Configuration &amp;amp; IP Generation&amp;lt;/SectionTitle&amp;gt;
          &amp;lt;InputField className="mb-4"&amp;gt;
            &amp;lt;Label htmlFor="flagName"&amp;gt;Feature Flag Name&amp;lt;/Label&amp;gt;
            &amp;lt;Input
              id="flagName"
              type="text"
              value={featureFlagName}
              onChange={(e) =&amp;gt; setFeatureFlagName(e.target.value)}
              placeholder="e.g., geo-targeted-feature"
            /&amp;gt;
          &amp;lt;/InputField&amp;gt;

          &amp;lt;div className="flex flex-col gap-4 mb-4 md:flex-row"&amp;gt;
            &amp;lt;InputField&amp;gt;
              &amp;lt;Label htmlFor="startIp"&amp;gt;Start IP (Range)&amp;lt;/Label&amp;gt;
              &amp;lt;Input
                id="startIp"
                type="text"
                value={startIp}
                onChange={(e) =&amp;gt; setStartIp(e.target.value)}
                placeholder="e.g., 192.168.1.1"
              /&amp;gt;
            &amp;lt;/InputField&amp;gt;
            &amp;lt;InputField&amp;gt;
              &amp;lt;Label htmlFor="endIp"&amp;gt;End IP (Range)&amp;lt;/Label&amp;gt;
              &amp;lt;Input
                id="endIp"
                type="text"
                value={endIp}
                onChange={(e) =&amp;gt; setEndIp(e.target.value)}
                placeholder="e.g., 192.168.1.10"
              /&amp;gt;
            &amp;lt;/InputField&amp;gt;
            &amp;lt;Button onClick={addRangeCards}&amp;gt;
              Generate Range Cards
            &amp;lt;/Button&amp;gt;
          &amp;lt;/div&amp;gt;

          &amp;lt;div className="flex flex-col gap-4 md:flex-row"&amp;gt;
            &amp;lt;InputField&amp;gt;
              &amp;lt;Label htmlFor="discreteIp"&amp;gt;Discrete IP Address&amp;lt;/Label&amp;gt;
              &amp;lt;Input
                id="discreteIp"
                type="text"
                value={discreteIp}
                onChange={(e) =&amp;gt; setDiscreteIp(e.target.value)}
                placeholder="e.g., 203.0.113.45"
              /&amp;gt;
            &amp;lt;/InputField&amp;gt;
            &amp;lt;Button onClick={addDiscreteCard}&amp;gt;
              Add Discrete IP Card
            &amp;lt;/Button&amp;gt;
          &amp;lt;/div&amp;gt;

          {errorMessage &amp;amp;&amp;amp; (
            &amp;lt;ErrorMessage&amp;gt;{errorMessage}&amp;lt;/ErrorMessage&amp;gt;
          )}
        &amp;lt;/Card&amp;gt;

        {/* IP Cards Display */}
        {ipCards.length &amp;gt; 0 ? (
          &amp;lt;IpCardsGrid&amp;gt;
            {ipCards.map((ipData) =&amp;gt; (
              &amp;lt;IpCard
                key={ipData.id}
                ipData={ipData}
                featureFlagName={featureFlagName}
                onTestFlag={handleTestFlag}
              /&amp;gt;
            ))}
          &amp;lt;/IpCardsGrid&amp;gt;
        ) : (
          &amp;lt;EmptyState&amp;gt;
            &amp;lt;EmptyStateIcon&amp;gt;➕&amp;lt;/EmptyStateIcon&amp;gt;
            &amp;lt;EmptyStateTitle&amp;gt;Start by Adding IPs&amp;lt;/EmptyStateTitle&amp;gt;
            &amp;lt;EmptyStateText&amp;gt;
              Enter an IP range or a discrete IP address to generate cards and begin testing.
            &amp;lt;/EmptyStateText&amp;gt;
            &amp;lt;EmptyStateNote&amp;gt;
              Ensure your feature flag "{featureFlagName}" has an "IP Address" strategy configured in Unleash.
            &amp;lt;/EmptyStateNote&amp;gt;
          &amp;lt;/EmptyState&amp;gt;
        )}
      &amp;lt;/MaxWidthWrapper&amp;gt;
    &amp;lt;/Container&amp;gt;
  );
};

export default IPRangeSimulator;


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

&lt;/div&gt;



</description>
    </item>
    <item>
      <title>iptester</title>
      <dc:creator>Kishan Srivastava</dc:creator>
      <pubDate>Mon, 30 Jun 2025 08:36:20 +0000</pubDate>
      <link>https://dev.to/superman01/iptester-ee5</link>
      <guid>https://dev.to/superman01/iptester-ee5</guid>
      <description>&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useState, useCallback } from 'react';
import { useUnleashContext, useUnleashClient } from '@unleash/proxy-client-react';
import styled, { keyframes, css } from 'styled-components';

// --- Styled Components ---

const fadeIn = keyframes`
  from { opacity: 0; transform: translateY(-10px); }
  to { opacity: 1; transform: translateY(0); }
`;

const spin = keyframes`
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
`;

const Container = styled.div`
  font-family: 'Inter', sans-serif;
  background-color: #f8fafc; /* Tailwind gray-50 */
  min-height: 100vh;
  padding: 2rem;
  display: flex;
  justify-content: center;
  align-items: flex-start;
`;

const MaxWidthWrapper = styled.div`
  max-width: 56rem; /* max-w-xl (56rem) */
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 1.5rem; /* gap-6 */
`;

const Card = styled.div`
  background-color: white;
  border-radius: 0.75rem; /* rounded-xl */
  box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); /* shadow-xl */
  padding: 1.5rem; /* p-6 */
  border: 1px solid #e2e8f0; /* border-gray-200 */
`;

const Header = styled.div`
  text-align: center;
  margin-bottom: 1rem; /* mb-4 */
`;

const Title = styled.h1`
  font-size: 1.875rem; /* text-3xl */
  font-weight: 700; /* font-bold */
  color: #1a202c; /* gray-900 */
  margin-bottom: 0.5rem; /* mb-2 */
`;

const Subtitle = styled.p`
  font-size: 1.125rem; /* text-lg */
  color: #4a5568; /* gray-600 */
`;

const SectionTitle = styled.h2`
  font-size: 1.5rem; /* text-2xl */
  font-weight: 600; /* font-semibold */
  color: #2d3748; /* gray-800 */
  margin-bottom: 1rem; /* mb-4 */
`;

const InputGroup = styled.div`
  display: flex;
  flex-direction: column;
  gap: 1rem; /* gap-4 */
`;

const Label = styled.label`
  display: block;
  font-size: 0.875rem; /* text-sm */
  font-weight: 500; /* font-medium */
  color: #2d3748; /* gray-700 */
  margin-bottom: 0.25rem; /* mb-1 */
`;

const Input = styled.input`
  width: 100%;
  padding: 0.75rem 1rem; /* px-4 py-3 */
  border: 1px solid #cbd5e0; /* border-gray-300 */
  border-radius: 0.5rem; /* rounded-lg */
  font-size: 1rem; /* text-base */
  color: #2d3748; /* text-gray-800 */
  box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05); /* shadow-sm */
  &amp;amp;:focus {
    outline: none;
    border-color: #3b82f6; /* border-blue-500 */
    box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.3); /* ring-2 ring-blue-300 */
  }
`;

const Button = styled.button`
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem; /* gap-2 */
  padding: 0.75rem 1.5rem; /* px-6 py-3 */
  background-color: #3b82f6; /* blue-500 */
  color: white;
  font-weight: 600; /* font-semibold */
  border-radius: 0.5rem; /* rounded-lg */
  border: none;
  cursor: pointer;
  box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); /* shadow-md */
  transition: background-color 0.2s ease-in-out, box-shadow 0.2s ease-in-out;

  &amp;amp;:hover {
    background-color: #2563eb; /* blue-600 */
    box-shadow: 0 6px 8px -1px rgba(0, 0, 0, 0.15), 0 4px 6px -2px rgba(0, 0, 0, 0.08);
  }

  &amp;amp;:disabled {
    background-color: #9ca3af; /* gray-400 */
    cursor: not-allowed;
    box-shadow: none;
  }
`;

const Spinner = styled.div`
  border: 4px solid rgba(255, 255, 255, 0.3);
  border-top: 4px solid white;
  border-radius: 50%;
  width: 1.5rem; /* h-6 w-6 */
  height: 1.5rem; /* h-6 w-6 */
  animation: ${spin} 1s linear infinite;
`;

const ErrorMessage = styled.p`
  color: #dc2626; /* red-600 */
  font-size: 0.875rem; /* text-sm */
  margin-top: 0.75rem; /* mt-3 */
  text-align: center;
`;

const ResultItem = styled.div`
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding-top: 0.5rem; /* py-2 */
  padding-bottom: 0.5rem; /* py-2 */
  border-bottom: 1px solid #f3f4f6; /* border-gray-100 */
  &amp;amp;:last-child {
    border-bottom: none;
  }
`;

const ResultLabel = styled.span`
  color: #4a5568; /* gray-600 */
  font-weight: 500; /* font-medium */
`;

const ResultValue = styled.span`
  color: #1a202c; /* gray-900 */
  font-weight: 700; /* font-bold */
`;

const StatusBadge = styled.span`
  display: inline-flex;
  padding: 0.25rem 0.75rem; /* px-3 py-1 */
  border-radius: 9999px; /* rounded-full */
  font-size: 0.875rem; /* text-sm */
  font-weight: 600; /* font-semibold */
  ${(props) =&amp;gt; {
    switch (props.type) {
      case 'enabled':
        return css`
          background-color: #dcfce7; /* green-100 */
          color: #16a34a; /* green-700 */
        `;
      case 'disabled':
        return css`
          background-color: #fee2e2; /* red-100 */
          color: #dc2626; /* red-700 */
        `;
      case 'error':
        return css`
          background-color: #fee2e2; /* red-100 */
          color: #dc2626; /* red-700 */
        `;
      default:
        return css`
          background-color: #e2e8f0;
          color: #4a5568;
        `;
    }
  }}
`;

const EmptyState = styled.div`
  text-align: center;
  padding: 3rem; /* p-12 */
  background-color: white;
  border-radius: 0.75rem; /* rounded-xl */
  box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); /* shadow-xl */
  border: 1px solid #e2e8f0; /* border-gray-200 */
  animation: ${fadeIn} 0.5s ease-out;
`;

const EmptyStateIcon = styled.span`
  font-size: 3rem; /* text-5xl */
  margin-bottom: 1rem; /* mb-4 */
  display: block;
`;

const EmptyStateTitle = styled.h3`
  font-size: 1.5rem; /* text-2xl */
  font-weight: 600; /* font-semibold */
  color: #2d3748; /* gray-800 */
  margin-bottom: 0.5rem; /* mb-2 */
`;

const EmptyStateText = styled.p`
  font-size: 1rem; /* text-base */
  color: #4a5568; /* gray-600 */
  margin-bottom: 1rem; /* mb-4 */
`;

const EmptyStateNote = styled.p`
  font-size: 0.875rem; /* text-sm */
  color: #718096; /* gray-500 */
  font-style: italic;
`;

// --- Main Component ---

const IPStrategySimulator = () =&amp;gt; {
  const [featureFlagName, setFeatureFlagName] = useState('geo-targeted-feature'); // Default flag name
  const [simulatedIpAddress, setSimulatedIpAddress] = useState('192.168.1.10'); // Default example IP
  const [testResult, setTestResult] = useState(null); // Stores the result: { ip, enabled, timestamp }
  const [isLoading, setIsLoading] = useState(false);
  const [errorMessage, setErrorMessage] = useState('');

  const updateContext = useUnleashContext();
  const unleashClient = useUnleashClient();

  const testIpAddress = useCallback(async () =&amp;gt; {
    setErrorMessage('');
    setTestResult(null);
    setIsLoading(true);

    if (!simulatedIpAddress) {
      setErrorMessage('Please enter a simulated IP address.');
      setIsLoading(false);
      return;
    }
    if (!featureFlagName) {
      setErrorMessage('Please enter the feature flag name.');
      setIsLoading(false);
      return;
    }

    try {
      // Update Unleash context with the simulated IP address
      // For IP strategy, 'remoteAddress' is the key context field.
      await updateContext({
        remoteAddress: simulatedIpAddress,
        // It's good practice to also provide a userId for consistency,
        // even if the strategy doesn't explicitly use it.
        userId: 'simulator-user-' + simulatedIpAddress.replace(/\./g, '-'),
      });

      // Small delay to ensure context updates are processed
      await new Promise((resolve) =&amp;gt; setTimeout(resolve, 100));

      // Get the actual flag status based on the updated context
      const isEnabled = unleashClient.isEnabled(featureFlagName);

      setTestResult({
        ip: simulatedIpAddress,
        enabled: isEnabled,
        timestamp: new Date().toLocaleTimeString(),
      });

    } catch (error) {
      console.error("Error during IP strategy test:", error);
      setErrorMessage("An error occurred during the test. Check console for details.");
      setTestResult({
        ip: simulatedIpAddress,
        enabled: false,
        timestamp: new Date().toLocaleTimeString(),
        error: true,
      });
    } finally {
      setIsLoading(false);
    }
  }, [simulatedIpAddress, featureFlagName, updateContext, unleashClient]);

  return (
    &amp;lt;Container&amp;gt;
      &amp;lt;MaxWidthWrapper&amp;gt;
        {/* Header */}
        &amp;lt;Card&amp;gt;
          &amp;lt;Header&amp;gt;
            &amp;lt;Title&amp;gt;📍 Unleash IP Strategy Simulator&amp;lt;/Title&amp;gt;
            &amp;lt;Subtitle&amp;gt;
              Test feature flag behavior based on simulated IP addresses.
            &amp;lt;/Subtitle&amp;gt;
          &amp;lt;/Header&amp;gt;
        &amp;lt;/Card&amp;gt;

        {/* Configuration Panel */}
        &amp;lt;Card&amp;gt;
          &amp;lt;SectionTitle&amp;gt;Test Configuration&amp;lt;/SectionTitle&amp;gt;
          &amp;lt;InputGroup&amp;gt;
            &amp;lt;div&amp;gt;
              &amp;lt;Label htmlFor="flagName"&amp;gt;Feature Flag Name&amp;lt;/Label&amp;gt;
              &amp;lt;Input
                id="flagName"
                type="text"
                value={featureFlagName}
                onChange={(e) =&amp;gt; setFeatureFlagName(e.target.value)}
                placeholder="e.g., geo-targeted-feature"
              /&amp;gt;
            &amp;lt;/div&amp;gt;
            &amp;lt;div&amp;gt;
              &amp;lt;Label htmlFor="simulatedIp"&amp;gt;Simulated IP Address&amp;lt;/Label&amp;gt;
              &amp;lt;Input
                id="simulatedIp"
                type="text"
                value={simulatedIpAddress}
                onChange={(e) =&amp;gt; setSimulatedIpAddress(e.target.value)}
                placeholder="e.g., 192.168.1.10 or 203.0.113.50"
              /&amp;gt;
            &amp;lt;/div&amp;gt;
            &amp;lt;Button onClick={testIpAddress} disabled={isLoading}&amp;gt;
              {isLoading ? (
                &amp;lt;&amp;gt;
                  &amp;lt;Spinner /&amp;gt;
                  Testing IP...
                &amp;lt;/&amp;gt;
              ) : (
                &amp;lt;&amp;gt;🌐 Test IP Address&amp;lt;/&amp;gt;
              )}
            &amp;lt;/Button&amp;gt;
          &amp;lt;/InputGroup&amp;gt;
          {errorMessage &amp;amp;&amp;amp; (
            &amp;lt;ErrorMessage&amp;gt;{errorMessage}&amp;lt;/ErrorMessage&amp;gt;
          )}
        &amp;lt;/Card&amp;gt;

        {/* Test Result Display */}
        {testResult &amp;amp;&amp;amp; (
          &amp;lt;Card style={{ animation: `${fadeIn} 0.5s ease-out` }}&amp;gt;
            &amp;lt;SectionTitle&amp;gt;Test Result&amp;lt;/SectionTitle&amp;gt;
            &amp;lt;div className="flex flex-col gap-3"&amp;gt;
              &amp;lt;ResultItem&amp;gt;
                &amp;lt;ResultLabel&amp;gt;Simulated IP:&amp;lt;/ResultLabel&amp;gt;
                &amp;lt;ResultValue&amp;gt;{testResult.ip}&amp;lt;/ResultValue&amp;gt;
              &amp;lt;/ResultItem&amp;gt;
              &amp;lt;ResultItem&amp;gt;
                &amp;lt;ResultLabel&amp;gt;Feature Flag Status:&amp;lt;/ResultLabel&amp;gt;
                {testResult.error ? (
                  &amp;lt;StatusBadge type="error"&amp;gt;❌ Error&amp;lt;/StatusBadge&amp;gt;
                ) : testResult.enabled ? (
                  &amp;lt;StatusBadge type="enabled"&amp;gt;✅ Enabled&amp;lt;/StatusBadge&amp;gt;
                ) : (
                  &amp;lt;StatusBadge type="disabled"&amp;gt;❌ Disabled&amp;lt;/StatusBadge&amp;gt;
                )}
              &amp;lt;/ResultItem&amp;gt;
              &amp;lt;ResultItem&amp;gt;
                &amp;lt;ResultLabel&amp;gt;Test Time:&amp;lt;/ResultLabel&amp;gt;
                &amp;lt;ResultValue&amp;gt;{testResult.timestamp}&amp;lt;/ResultValue&amp;gt;
              &amp;lt;/ResultItem&amp;gt;
            &amp;lt;/div&amp;gt;
          &amp;lt;/Card&amp;gt;
        )}

        {/* Initial Empty State */}
        {!testResult &amp;amp;&amp;amp; !isLoading &amp;amp;&amp;amp; !errorMessage &amp;amp;&amp;amp; (
          &amp;lt;EmptyState&amp;gt;
            &amp;lt;EmptyStateIcon&amp;gt;🧪&amp;lt;/EmptyStateIcon&amp;gt;
            &amp;lt;EmptyStateTitle&amp;gt;Ready to Test IP-Based Features&amp;lt;/EmptyStateTitle&amp;gt;
            &amp;lt;EmptyStateText&amp;gt;
              Enter a feature flag name and a simulated IP address, then click "Test IP Address" to see the result.
            &amp;lt;/EmptyStateText&amp;gt;
            &amp;lt;EmptyStateNote&amp;gt;
              Make sure your feature flag "{featureFlagName}" has an "IP Address" strategy configured in Unleash.
            &amp;lt;/EmptyStateNote&amp;gt;
          &amp;lt;/EmptyState&amp;gt;
        )}
      &amp;lt;/MaxWidthWrapper&amp;gt;
    &amp;lt;/Container&amp;gt;
  );
};

export default IPStrategySimulator;


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

&lt;/div&gt;



</description>
    </item>
  </channel>
</rss>
