Add VS Code UI application (#729)

This commit is contained in:
pollfly 2023-12-19 15:14:37 +02:00 committed by GitHub
parent cf9aff2ded
commit 895fcef3ea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 215 additions and 1 deletions

BIN
docs/img/apps_vs_code.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 KiB

View File

@ -22,6 +22,7 @@ ClearML provides the following applications:
* [**Project Dashboard**](apps_dashboard.md) - High-level project monitoring with Slack alerts
* [**Task Scheduler**](apps_task_scheduler.md) - Schedule tasks for one-shot and/or periodic execution at specified times (available under ClearML Enterprise Plan)
* [**Trigger Manager**](apps_trigger_manager.md) - Define tasks to be run when predefined events occur (available under ClearML Enterprise Plan)
* [**VS Code**](apps_vscode.md) - Launch a VS Code session on a remote machine (available under ClearML Enterprise Plan)
## App Pages Layout
Each application's page is split into two sections:

View File

@ -0,0 +1,49 @@
---
title: VS Code
---
:::important Enterprise Feature
The VS Code application is available under the ClearML Enterprise plan
:::
The VS Code UI application allows you to launch a remote VS Code session on a machine that better meets resource needs.
This feature provides a local link to access VS Code on a remote machine over a secure and encrypted SSH connection,
letting you use the IDE as if you're running on the target machine itself.
The VS Code session is set up using a [ClearML Agent](../../clearml_agent.md). When configuring an app instance,
select a queue, and the agent servicing that queue will download and launch the IDE on its machine. When the server
setup is complete, the dashboard displays a link to access the VS Code session.
Once you have launched an app instance, you can view the following information in its dashboard:
* App status indicator
* <img src="/docs/latest/icons/ico-vscode-loading.svg" alt="VS Code loading" className="icon size-md" /> - Remote IDE is setting up
* <img src="/docs/latest/icons/ico-vscode-active.svg" alt="VS Code active" className="icon size-md" /> - Remote IDE is active
* <img src="/docs/latest/icons/ico-vscode-idle.svg" alt="VS Code idle" className="icon size-md" /> - Remote IDE is idle
* <img src="/docs/latest/icons/ico-vscode-stopped.svg" alt="VS Code stopped" className="icon size-md" /> Remote IDE is stopped
* Open IDE - link to the IDE session
* Idle time
* Servers resources monitoring (CPU / GPU / vMem utilization)
* Console - The console log shows the instance's activity, including server setup progress, server status changes
![VS Code Dashboard](../../img/apps_vs_code.png)
## VS Code App Instance Configuration
* **Git** - To access a git repository remotely, add git information.
* Repository
* Branch
* Commit
* **Docker**
* Image - Docker image used to run the IDE in
* Docker arguments - `docker run` arguments, as a single string
* **Queue** - The queue serviced by the ClearML Agent that will execute the VS Code session
* **Maximum idle time** (hours) - Maximum time of inactivity, after which the session will shut down. Configure idleness
definitions under `Advanced Options`.
* **Advanced Options**
* VSCode Version - VSCode code-server version to download
* VSCode additional extensions - Comma separated list of additional VSCode extensions to install (for example `ms-toolsai.jupyter,ms-python.python`)
* Idle Network Threshold (MB/s) - Throughput under which the session will be considered idle
* Idle CPU Threshold (%) - CPU utilization under which the session will be considered idle
* Idle GPU Threshold (%) - GPU utilization under which the session will be considered idle

View File

@ -111,7 +111,8 @@ module.exports = {
'webapp/applications/apps_hpo',
'webapp/applications/apps_dashboard',
'webapp/applications/apps_task_scheduler',
'webapp/applications/apps_trigger_manager'
'webapp/applications/apps_trigger_manager',
'webapp/applications/apps_vscode'
]
},

View File

@ -0,0 +1,30 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
<defs>
<mask data-name="mask" x="8.58" y="6.61" width="44" height="43.75" maskUnits="userSpaceOnUse">
<g data-name="mask0">
<path d="m39.79,50.17c.69.27,1.48.25,2.18-.08l9.05-4.36c.95-.46,1.56-1.42,1.56-2.48V13.72c0-1.06-.6-2.02-1.56-2.48l-9.05-4.36c-.92-.44-1.99-.33-2.8.25-.11.08-.22.18-.33.28l-17.33,15.81-7.55-5.73c-.7-.53-1.69-.49-2.34.1l-2.42,2.2c-.8.73-.8,1.98,0,2.71l6.55,5.97-6.55,5.97c-.8.73-.8,1.98,0,2.71l2.42,2.2c.65.59,1.64.64,2.34.1l7.55-5.73,17.33,15.81c.27.27.6.48.94.62Zm1.8-31.67l-13.15,9.98,13.15,9.98v-19.96Z" fill="#fff" fill-rule="evenodd" stroke-width="0"/>
</g>
</mask>
<linearGradient x1="30.57" y1="59.39" x2="30.57" y2="15.64" gradientTransform="translate(0 66) scale(1 -1)" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#fff"/>
<stop offset="1" stop-color="#fff" stop-opacity="0"/>
</linearGradient>
</defs>
<g>
<g mask="url(#b)">
<g>
<path d="m51.02,11.25l-9.06-4.36c-1.05-.5-2.3-.29-3.13.53l-29.66,27.04c-.8.73-.8,1.98,0,2.71l2.42,2.2c.65.59,1.64.64,2.34.1L49.66,12.38c1.2-.91,2.92-.05,2.92,1.45v-.11c0-1.06-.6-2.02-1.56-2.48Z" fill="#0065a9" stroke-width="0"/>
<path d="m51.02,45.72l-9.06,4.36c-1.05.51-2.3.29-3.13-.53L9.18,22.51c-.8-.73-.8-1.98,0-2.71l2.42-2.2c.65-.59,1.64-.64,2.34-.1l35.72,27.1c1.2.91,2.92.05,2.92-1.45v.11c0,1.06-.6,2.02-1.56,2.48Z" fill="#007acc" stroke-width="0"/>
<path d="m41.96,50.09c-1.05.5-2.3.29-3.13-.53,1.01,1.01,2.75.3,2.75-1.14V8.55c0-1.43-1.73-2.15-2.75-1.14.82-.82,2.08-1.04,3.13-.53l9.06,4.36c.95.46,1.56,1.42,1.56,2.48v29.54c0,1.06-.61,2.02-1.56,2.48l-9.06,4.36Z" fill="#1f9cf0" stroke-width="0"/>
<g opacity=".25">
<path d="m39.76,50.17c.69.27,1.48.25,2.18-.08l9.05-4.36c.95-.46,1.56-1.42,1.56-2.48V13.72c0-1.06-.6-2.02-1.56-2.48l-9.05-4.36c-.92-.44-1.99-.33-2.8.25-.11.08-.22.18-.33.28l-17.33,15.81-7.55-5.73c-.7-.53-1.69-.49-2.34.1l-2.42,2.2c-.8.73-.8,1.98,0,2.71l6.55,5.97-6.55,5.97c-.8.73-.8,1.98,0,2.71l2.42,2.2c.65.59,1.64.64,2.34.1l7.55-5.73,17.33,15.81c.27.27.6.48.94.62Zm1.8-31.67l-13.15,9.98,13.15,9.98v-19.96Z" fill="url(#d)" fill-rule="evenodd" stroke-width="0"/>
</g>
</g>
</g>
</g>
<g>
<circle cx="49" cy="49" r="12" fill="#0d0e15" stroke-width="0"/>
<path d="m49,39c-5.52,0-10,4.48-10,10s4.48,10,10,10,10-4.48,10-10-4.48-10-10-10Z" fill="#21b553"/>
<path d="m52.42,48.23l-4.06-3.38c-.65-.54-1.64-.08-1.64.77v6.76c0,.85.99,1.31,1.64.77l4.06-3.38c.48-.4.48-1.14,0-1.54Z" fill="#fff"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -0,0 +1,30 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
<defs>
<mask data-name="mask" x="8.58" y="6.61" width="44" height="43.75" maskUnits="userSpaceOnUse">
<g data-name="mask0">
<path d="m39.79,50.17c.69.27,1.48.25,2.18-.08l9.05-4.36c.95-.46,1.56-1.42,1.56-2.48V13.72c0-1.06-.6-2.02-1.56-2.48l-9.05-4.36c-.92-.44-1.99-.33-2.8.25-.11.08-.22.18-.33.28l-17.33,15.81-7.55-5.73c-.7-.53-1.69-.49-2.34.1l-2.42,2.2c-.8.73-.8,1.98,0,2.71l6.55,5.97-6.55,5.97c-.8.73-.8,1.98,0,2.71l2.42,2.2c.65.59,1.64.64,2.34.1l7.55-5.73,17.33,15.81c.27.27.6.48.94.62Zm1.8-31.67l-13.15,9.98,13.15,9.98v-19.96Z" fill="#fff" fill-rule="evenodd" stroke-width="0"/>
</g>
</mask>
<linearGradient x1="30.57" y1="59.39" x2="30.57" y2="15.64" gradientTransform="translate(0 66) scale(1 -1)" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#fff"/>
<stop offset="1" stop-color="#fff" stop-opacity="0"/>
</linearGradient>
</defs>
<g>
<g mask="url(#b)">
<g>
<path d="m51.02,11.25l-9.06-4.36c-1.05-.5-2.3-.29-3.13.53l-29.66,27.04c-.8.73-.8,1.98,0,2.71l2.42,2.2c.65.59,1.64.64,2.34.1L49.66,12.38c1.2-.91,2.92-.05,2.92,1.45v-.11c0-1.06-.6-2.02-1.56-2.48Z" fill="#0065a9" stroke-width="0"/>
<path d="m51.02,45.72l-9.06,4.36c-1.05.51-2.3.29-3.13-.53L9.18,22.51c-.8-.73-.8-1.98,0-2.71l2.42-2.2c.65-.59,1.64-.64,2.34-.1l35.72,27.1c1.2.91,2.92.05,2.92-1.45v.11c0,1.06-.6,2.02-1.56,2.48Z" fill="#007acc" stroke-width="0"/>
<path d="m41.96,50.09c-1.05.5-2.3.29-3.13-.53,1.01,1.01,2.75.3,2.75-1.14V8.55c0-1.43-1.73-2.15-2.75-1.14.82-.82,2.08-1.04,3.13-.53l9.06,4.36c.95.46,1.56,1.42,1.56,2.48v29.54c0,1.06-.61,2.02-1.56,2.48l-9.06,4.36Z" fill="#1f9cf0" stroke-width="0"/>
<g opacity=".25">
<path d="m39.76,50.17c.69.27,1.48.25,2.18-.08l9.05-4.36c.95-.46,1.56-1.42,1.56-2.48V13.72c0-1.06-.6-2.02-1.56-2.48l-9.05-4.36c-.92-.44-1.99-.33-2.8.25-.11.08-.22.18-.33.28l-17.33,15.81-7.55-5.73c-.7-.53-1.69-.49-2.34.1l-2.42,2.2c-.8.73-.8,1.98,0,2.71l6.55,5.97-6.55,5.97c-.8.73-.8,1.98,0,2.71l2.42,2.2c.65.59,1.64.64,2.34.1l7.55-5.73,17.33,15.81c.27.27.6.48.94.62Zm1.8-31.67l-13.15,9.98,13.15,9.98v-19.96Z" fill="url(#d)" fill-rule="evenodd" stroke-width="0"/>
</g>
</g>
</g>
</g>
<g>
<circle cx="49" cy="49" r="12" fill="#0d0e15" stroke-width="0"/>
<path d="m49,39c-5.52,0-10,4.48-10,10s4.48,10,10,10,10-4.48,10-10-4.48-10-10-10Z" fill="#de3232"/>
<path id="p1" d="m53.67,45.27l-.94-.94-3.73,3.73-3.73-3.73-.94.94,3.73,3.73-3.73,3.73.94.94,3.73-3.73,3.73,3.73.94-.94-3.73-3.73,3.73-3.73Z" fill="#fff"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -0,0 +1,30 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 64 64">
<defs>
<mask data-name="mask" x="8.58" y="6.61" width="44" height="43.75" maskUnits="userSpaceOnUse">
<g data-name="mask0">
<path d="m39.79,50.17c.69.27,1.48.25,2.18-.08l9.05-4.36c.95-.46,1.56-1.42,1.56-2.48V13.72c0-1.06-.6-2.02-1.56-2.48l-9.05-4.36c-.92-.44-1.99-.33-2.8.25-.11.08-.22.18-.33.28l-17.33,15.81-7.55-5.73c-.7-.53-1.69-.49-2.34.1l-2.42,2.2c-.8.73-.8,1.98,0,2.71l6.55,5.97-6.55,5.97c-.8.73-.8,1.98,0,2.71l2.42,2.2c.65.59,1.64.64,2.34.1l7.55-5.73,17.33,15.81c.27.27.6.48.94.62Zm1.8-31.67l-13.15,9.98,13.15,9.98v-19.96Z" fill="#fff" fill-rule="evenodd" stroke-width="0"/>
</g>
</mask>
<linearGradient x1="30.57" y1="59.39" x2="30.57" y2="15.64" gradientTransform="translate(0 66) scale(1 -1)" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#fff"/>
<stop offset="1" stop-color="#fff" stop-opacity="0"/>
</linearGradient>
</defs>
<g>
<g mask="url(#b)">
<g>
<path d="m51.02,11.25l-9.06-4.36c-1.05-.5-2.3-.29-3.13.53l-29.66,27.04c-.8.73-.8,1.98,0,2.71l2.42,2.2c.65.59,1.64.64,2.34.1L49.66,12.38c1.2-.91,2.92-.05,2.92,1.45v-.11c0-1.06-.6-2.02-1.56-2.48Z" fill="#0065a9" stroke-width="0"/>
<path d="m51.02,45.72l-9.06,4.36c-1.05.51-2.3.29-3.13-.53L9.18,22.51c-.8-.73-.8-1.98,0-2.71l2.42-2.2c.65-.59,1.64-.64,2.34-.1l35.72,27.1c1.2.91,2.92.05,2.92-1.45v.11c0,1.06-.6,2.02-1.56,2.48Z" fill="#007acc" stroke-width="0"/>
<path d="m41.96,50.09c-1.05.5-2.3.29-3.13-.53,1.01,1.01,2.75.3,2.75-1.14V8.55c0-1.43-1.73-2.15-2.75-1.14.82-.82,2.08-1.04,3.13-.53l9.06,4.36c.95.46,1.56,1.42,1.56,2.48v29.54c0,1.06-.61,2.02-1.56,2.48l-9.06,4.36Z" fill="#1f9cf0" stroke-width="0"/>
<g opacity=".25">
<path d="m39.76,50.17c.69.27,1.48.25,2.18-.08l9.05-4.36c.95-.46,1.56-1.42,1.56-2.48V13.72c0-1.06-.6-2.02-1.56-2.48l-9.05-4.36c-.92-.44-1.99-.33-2.8.25-.11.08-.22.18-.33.28l-17.33,15.81-7.55-5.73c-.7-.53-1.69-.49-2.34.1l-2.42,2.2c-.8.73-.8,1.98,0,2.71l6.55,5.97-6.55,5.97c-.8.73-.8,1.98,0,2.71l2.42,2.2c.65.59,1.64.64,2.34.1l7.55-5.73,17.33,15.81c.27.27.6.48.94.62Zm1.8-31.67l-13.15,9.98,13.15,9.98v-19.96Z" fill="url(#d)" fill-rule="evenodd" stroke-width="0"/>
</g>
</g>
</g>
</g>
<g>
<circle cx="49" cy="49" r="12" fill="#0d0e15" stroke-width="0"/>
<path d="m49,39c-5.52,0-10,4.48-10,10s4.48,10,10,10,10-4.48,10-10-4.48-10-10-10Z" fill="#50beff" stroke-width="0"/>
<path id="f" data-name="idle-s" d="m50.44,49.24v-4.48c0-.67-.55-1.22-1.22-1.22s-1.22.55-1.22,1.22v4.88s0,.04,0,.05c0,.33.1.66.35.91l4.31,3.61c.12.09.34.25.56.25.43,0,.77-.35.77-.77,0-.21-.1-.39-.23-.55l-3.33-3.91h0Z" fill="#fff" stroke-width="0"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -0,0 +1,29 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
<defs>
<mask data-name="mask" x="8.58" y="6.61" width="44" height="43.75" maskUnits="userSpaceOnUse">
<g data-name="mask0">
<path d="m39.79,50.17c.69.27,1.48.25,2.18-.08l9.05-4.36c.95-.46,1.56-1.42,1.56-2.48V13.72c0-1.06-.6-2.02-1.56-2.48l-9.05-4.36c-.92-.44-1.99-.33-2.8.25-.11.08-.22.18-.33.28l-17.33,15.81-7.55-5.73c-.7-.53-1.69-.49-2.34.1l-2.42,2.2c-.8.73-.8,1.98,0,2.71l6.55,5.97-6.55,5.97c-.8.73-.8,1.98,0,2.71l2.42,2.2c.65.59,1.64.64,2.34.1l7.55-5.73,17.33,15.81c.27.27.6.48.94.62Zm1.8-31.67l-13.15,9.98,13.15,9.98v-19.96Z" fill="#fff" fill-rule="evenodd" stroke-width="0"/>
</g>
</mask>
<linearGradient x1="30.57" y1="59.39" x2="30.57" y2="15.64" gradientTransform="translate(0 66) scale(1 -1)" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#fff"/>
<stop offset="1" stop-color="#fff" stop-opacity="0"/>
</linearGradient>
</defs>
<g>
<g mask="url(#b)">
<g>
<path d="m51.02,11.25l-9.06-4.36c-1.05-.5-2.3-.29-3.13.53l-29.66,27.04c-.8.73-.8,1.98,0,2.71l2.42,2.2c.65.59,1.64.64,2.34.1L49.66,12.38c1.2-.91,2.92-.05,2.92,1.45v-.11c0-1.06-.6-2.02-1.56-2.48Z" fill="#0065a9" stroke-width="0"/>
<path d="m51.02,45.72l-9.06,4.36c-1.05.51-2.3.29-3.13-.53L9.18,22.51c-.8-.73-.8-1.98,0-2.71l2.42-2.2c.65-.59,1.64-.64,2.34-.1l35.72,27.1c1.2.91,2.92.05,2.92-1.45v.11c0,1.06-.6,2.02-1.56,2.48Z" fill="#007acc" stroke-width="0"/>
<path d="m41.96,50.09c-1.05.5-2.3.29-3.13-.53,1.01,1.01,2.75.3,2.75-1.14V8.55c0-1.43-1.73-2.15-2.75-1.14.82-.82,2.08-1.04,3.13-.53l9.06,4.36c.95.46,1.56,1.42,1.56,2.48v29.54c0,1.06-.61,2.02-1.56,2.48l-9.06,4.36Z" fill="#1f9cf0" stroke-width="0"/>
<g opacity=".25">
<path d="m39.76,50.17c.69.27,1.48.25,2.18-.08l9.05-4.36c.95-.46,1.56-1.42,1.56-2.48V13.72c0-1.06-.6-2.02-1.56-2.48l-9.05-4.36c-.92-.44-1.99-.33-2.8.25-.11.08-.22.18-.33.28l-17.33,15.81-7.55-5.73c-.7-.53-1.69-.49-2.34.1l-2.42,2.2c-.8.73-.8,1.98,0,2.71l6.55,5.97-6.55,5.97c-.8.73-.8,1.98,0,2.71l2.42,2.2c.65.59,1.64.64,2.34.1l7.55-5.73,17.33,15.81c.27.27.6.48.94.62Zm1.8-31.67l-13.15,9.98,13.15,9.98v-19.96Z" fill="url(#d)" fill-rule="evenodd" stroke-width="0"/>
</g>
</g>
</g>
</g>
<g>
<circle cx="49" cy="49" r="12" fill="#0d0e15" stroke-width="0"/>
<path d="m49,39c-5.52,0-10,4.48-10,10s4.48,10,10,10,10-4.48,10-10-4.48-10-10-10Z" fill="#d3ff00"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -0,0 +1,44 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
<defs>
<mask data-name="mask" x="8.58" y="6.61" width="44" height="43.75"
maskUnits="userSpaceOnUse">
<g data-name="mask0">
<path
d="m39.79,50.17c.69.27,1.48.25,2.18-.08l9.05-4.36c.95-.46,1.56-1.42,1.56-2.48V13.72c0-1.06-.6-2.02-1.56-2.48l-9.05-4.36c-.92-.44-1.99-.33-2.8.25-.11.08-.22.18-.33.28l-17.33,15.81-7.55-5.73c-.7-.53-1.69-.49-2.34.1l-2.42,2.2c-.8.73-.8,1.98,0,2.71l6.55,5.97-6.55,5.97c-.8.73-.8,1.98,0,2.71l2.42,2.2c.65.59,1.64.64,2.34.1l7.55-5.73,17.33,15.81c.27.27.6.48.94.62Zm1.8-31.67l-13.15,9.98,13.15,9.98v-19.96Z"
fill="#fff" fill-rule="evenodd" stroke-width="0" />
</g>
</mask>
<linearGradient x1="30.57" y1="59.39" x2="30.57" y2="15.64"
gradientTransform="translate(0 66) scale(1 -1)" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#fff" />
<stop offset="1" stop-color="#fff" stop-opacity="0" />
</linearGradient>
</defs>
<g>
<g mask="url(#b)">
<g>
<path
d="m51.02,11.25l-9.06-4.36c-1.05-.5-2.3-.29-3.13.53l-29.66,27.04c-.8.73-.8,1.98,0,2.71l2.42,2.2c.65.59,1.64.64,2.34.1L49.66,12.38c1.2-.91,2.92-.05,2.92,1.45v-.11c0-1.06-.6-2.02-1.56-2.48Z"
fill="#0065a9" stroke-width="0" />
<path
d="m51.02,45.72l-9.06,4.36c-1.05.51-2.3.29-3.13-.53L9.18,22.51c-.8-.73-.8-1.98,0-2.71l2.42-2.2c.65-.59,1.64-.64,2.34-.1l35.72,27.1c1.2.91,2.92.05,2.92-1.45v.11c0,1.06-.6,2.02-1.56,2.48Z"
fill="#007acc" stroke-width="0" />
<path
d="m41.96,50.09c-1.05.5-2.3.29-3.13-.53,1.01,1.01,2.75.3,2.75-1.14V8.55c0-1.43-1.73-2.15-2.75-1.14.82-.82,2.08-1.04,3.13-.53l9.06,4.36c.95.46,1.56,1.42,1.56,2.48v29.54c0,1.06-.61,2.02-1.56,2.48l-9.06,4.36Z"
fill="#1f9cf0" stroke-width="0" />
<g opacity=".25">
<path
d="m39.76,50.17c.69.27,1.48.25,2.18-.08l9.05-4.36c.95-.46,1.56-1.42,1.56-2.48V13.72c0-1.06-.6-2.02-1.56-2.48l-9.05-4.36c-.92-.44-1.99-.33-2.8.25-.11.08-.22.18-.33.28l-17.33,15.81-7.55-5.73c-.7-.53-1.69-.49-2.34.1l-2.42,2.2c-.8.73-.8,1.98,0,2.71l6.55,5.97-6.55,5.97c-.8.73-.8,1.98,0,2.71l2.42,2.2c.65.59,1.64.64,2.34.1l7.55-5.73,17.33,15.81c.27.27.6.48.94.62Zm1.8-31.67l-13.15,9.98,13.15,9.98v-19.96Z"
fill="url(#d)" fill-rule="evenodd" stroke-width="0" />
</g>
</g>
</g>
</g>
<g>
<circle cx="49" cy="49" r="12" fill="#0d0e15" stroke-width="0" />
<path
d="M49 39C43.48 39 39 43.48 39 49C39 54.52 43.48 59 49 59C54.52 59 59 54.52 59 49C59 43.48 54.52 39 49 39Z"
fill="#50BEFF" />
<rect x="45" y="45" width="8" height="8" rx="1" fill="white" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB