Compare commits

..

5 Commits

29 changed files with 464 additions and 1084 deletions

View File

@@ -354,16 +354,6 @@ function App(): JSX.Element {
tunnel: window.signozBootData.settings.sentry.tunnel,
environment: process.env.ENVIRONMENT,
release: process.env.VERSION,
// A tab that outlived a deploy requests hashed assets the new build no longer
// has. `lazyRetry` recovers by reloading once, so this class is not worth
// reporting. The stylesheet message is Vite's own; the module ones are the
// same failure worded differently by Chromium, Firefox and Safari.
ignoreErrors: [
/Unable to preload CSS for/,
/Failed to fetch dynamically imported module/,
/error loading dynamically imported module/,
/Importing a module script failed/,
],
integrations: [
// Kept for the `transaction` tag used in routing, even though
// tracing is disabled. Ref: https://github.com/SigNoz/platform-pod/issues/2393#issuecomment-4603658055

View File

@@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="#9CA3AF" fill-rule="evenodd" style="flex:none;line-height:1" viewBox="0 0 24 24"><title>AWS</title><path d="M6.763 11.212q.002.446.088.71c.064.176.144.368.256.576.04.063.056.127.056.183q.002.12-.152.24l-.503.335a.4.4 0 0 1-.208.072q-.12-.002-.239-.112a2.5 2.5 0 0 1-.287-.375 6 6 0 0 1-.248-.471q-.934 1.101-2.347 1.101c-.67 0-1.205-.191-1.596-.574-.39-.384-.59-.894-.59-1.533 0-.678.24-1.23.726-1.644.487-.415 1.133-.623 1.955-.623.272 0 .551.024.846.064.296.04.6.104.918.176v-.583q-.001-.908-.375-1.277c-.255-.248-.686-.367-1.3-.367-.28 0-.568.031-.863.103s-.583.16-.862.272a2 2 0 0 1-.28.104.5.5 0 0 1-.127.023q-.168.002-.168-.247v-.391c0-.128.016-.224.056-.28a.6.6 0 0 1 .224-.167 4.6 4.6 0 0 1 1.005-.36 4.8 4.8 0 0 1 1.246-.151c.95 0 1.644.216 2.091.647q.661.646.662 1.963v2.586zm-3.24 1.214c.263 0 .534-.048.822-.144a1.8 1.8 0 0 0 .758-.51 1.3 1.3 0 0 0 .272-.512c.047-.191.08-.423.08-.694v-.335a7 7 0 0 0-.735-.136 6 6 0 0 0-.75-.048c-.535 0-.926.104-1.19.32-.263.215-.39.518-.39.917 0 .375.095.655.295.846.191.2.47.296.838.296m6.41.862c-.144 0-.24-.024-.304-.08-.064-.048-.12-.16-.168-.311L7.586 6.726a1.4 1.4 0 0 1-.072-.32c0-.128.064-.2.191-.2h.783q.227-.001.31.08c.065.048.113.16.16.312l1.342 5.284 1.245-5.284q.058-.24.151-.312a.55.55 0 0 1 .32-.08h.638c.152 0 .256.025.32.08.063.048.12.16.151.312l1.261 5.348 1.381-5.348q.074-.24.16-.312a.52.52 0 0 1 .311-.08h.743c.127 0 .2.065.2.2 0 .04-.009.08-.017.128a1 1 0 0 1-.056.2l-1.923 6.17q-.072.24-.168.311a.5.5 0 0 1-.303.08h-.687c-.15 0-.255-.024-.32-.08-.063-.056-.119-.16-.15-.32L12.32 7.747l-1.23 5.14c-.04.16-.087.264-.15.32-.065.056-.177.08-.32.08zm10.256.215c-.415 0-.83-.048-1.229-.143-.399-.096-.71-.2-.918-.32-.128-.071-.215-.151-.247-.223a.6.6 0 0 1-.048-.224v-.407c0-.167.064-.247.183-.247q.072 0 .144.024c.048.016.12.048.2.08q.408.181.878.279c.32.064.63.096.95.096.502 0 .894-.088 1.165-.264a.86.86 0 0 0 .415-.758.78.78 0 0 0-.215-.559c-.144-.151-.416-.287-.807-.415l-1.157-.36c-.583-.183-1.014-.454-1.277-.813a1.9 1.9 0 0 1-.4-1.158q0-.502.216-.886c.144-.255.335-.479.575-.654.24-.184.51-.32.83-.415.32-.096.655-.136 1.006-.136.175 0 .36.008.535.032.183.024.35.056.518.088q.24.058.455.127.216.072.336.144a.7.7 0 0 1 .24.2.43.43 0 0 1 .071.263v.375q-.002.254-.184.256a.8.8 0 0 1-.303-.096 3.65 3.65 0 0 0-1.532-.311c-.455 0-.815.071-1.062.223s-.375.383-.375.71c0 .224.08.416.24.567.16.152.454.304.877.44l1.134.358c.574.184.99.44 1.237.767s.367.702.367 1.117c0 .343-.072.655-.207.926a2.2 2.2 0 0 1-.583.703c-.248.2-.543.343-.886.447-.36.111-.734.167-1.142.167"/><path fill="#f90" d="M.378 15.475c3.384 1.963 7.56 3.153 11.877 3.153 2.914 0 6.114-.607 9.06-1.852.44-.2.814.287.383.607-2.626 1.94-6.442 2.969-9.722 2.969-4.598 0-8.74-1.7-11.87-4.526-.247-.223-.024-.527.272-.351m23.531-.2c.287.36-.08 2.826-1.485 4.007-.215.184-.423.088-.327-.151l.175-.439c.343-.88.802-2.198.52-2.555-.336-.43-2.22-.207-3.074-.103-.255.032-.295-.192-.063-.36 1.5-1.053 3.967-.75 4.254-.399"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" fill-rule="evenodd" style="flex:none;line-height:1" viewBox="0 0 24 24"><title>AWS</title><path d="M6.763 11.212q.002.446.088.71c.064.176.144.368.256.576.04.063.056.127.056.183q.002.12-.152.24l-.503.335a.4.4 0 0 1-.208.072q-.12-.002-.239-.112a2.5 2.5 0 0 1-.287-.375 6 6 0 0 1-.248-.471q-.934 1.101-2.347 1.101c-.67 0-1.205-.191-1.596-.574-.39-.384-.59-.894-.59-1.533 0-.678.24-1.23.726-1.644.487-.415 1.133-.623 1.955-.623.272 0 .551.024.846.064.296.04.6.104.918.176v-.583q-.001-.908-.375-1.277c-.255-.248-.686-.367-1.3-.367-.28 0-.568.031-.863.103s-.583.16-.862.272a2 2 0 0 1-.28.104.5.5 0 0 1-.127.023q-.168.002-.168-.247v-.391c0-.128.016-.224.056-.28a.6.6 0 0 1 .224-.167 4.6 4.6 0 0 1 1.005-.36 4.8 4.8 0 0 1 1.246-.151c.95 0 1.644.216 2.091.647q.661.646.662 1.963v2.586zm-3.24 1.214c.263 0 .534-.048.822-.144a1.8 1.8 0 0 0 .758-.51 1.3 1.3 0 0 0 .272-.512c.047-.191.08-.423.08-.694v-.335a7 7 0 0 0-.735-.136 6 6 0 0 0-.75-.048c-.535 0-.926.104-1.19.32-.263.215-.39.518-.39.917 0 .375.095.655.295.846.191.2.47.296.838.296m6.41.862c-.144 0-.24-.024-.304-.08-.064-.048-.12-.16-.168-.311L7.586 6.726a1.4 1.4 0 0 1-.072-.32c0-.128.064-.2.191-.2h.783q.227-.001.31.08c.065.048.113.16.16.312l1.342 5.284 1.245-5.284q.058-.24.151-.312a.55.55 0 0 1 .32-.08h.638c.152 0 .256.025.32.08.063.048.12.16.151.312l1.261 5.348 1.381-5.348q.074-.24.16-.312a.52.52 0 0 1 .311-.08h.743c.127 0 .2.065.2.2 0 .04-.009.08-.017.128a1 1 0 0 1-.056.2l-1.923 6.17q-.072.24-.168.311a.5.5 0 0 1-.303.08h-.687c-.15 0-.255-.024-.32-.08-.063-.056-.119-.16-.15-.32L12.32 7.747l-1.23 5.14c-.04.16-.087.264-.15.32-.065.056-.177.08-.32.08zm10.256.215c-.415 0-.83-.048-1.229-.143-.399-.096-.71-.2-.918-.32-.128-.071-.215-.151-.247-.223a.6.6 0 0 1-.048-.224v-.407c0-.167.064-.247.183-.247q.072 0 .144.024c.048.016.12.048.2.08q.408.181.878.279c.32.064.63.096.95.096.502 0 .894-.088 1.165-.264a.86.86 0 0 0 .415-.758.78.78 0 0 0-.215-.559c-.144-.151-.416-.287-.807-.415l-1.157-.36c-.583-.183-1.014-.454-1.277-.813a1.9 1.9 0 0 1-.4-1.158q0-.502.216-.886c.144-.255.335-.479.575-.654.24-.184.51-.32.83-.415.32-.096.655-.136 1.006-.136.175 0 .36.008.535.032.183.024.35.056.518.088q.24.058.455.127.216.072.336.144a.7.7 0 0 1 .24.2.43.43 0 0 1 .071.263v.375q-.002.254-.184.256a.8.8 0 0 1-.303-.096 3.65 3.65 0 0 0-1.532-.311c-.455 0-.815.071-1.062.223s-.375.383-.375.71c0 .224.08.416.24.567.16.152.454.304.877.44l1.134.358c.574.184.99.44 1.237.767s.367.702.367 1.117c0 .343-.072.655-.207.926a2.2 2.2 0 0 1-.583.703c-.248.2-.543.343-.886.447-.36.111-.734.167-1.142.167"/><path fill="#f90" d="M.378 15.475c3.384 1.963 7.56 3.153 11.877 3.153 2.914 0 6.114-.607 9.06-1.852.44-.2.814.287.383.607-2.626 1.94-6.442 2.969-9.722 2.969-4.598 0-8.74-1.7-11.87-4.526-.247-.223-.024-.527.272-.351m23.531-.2c.287.36-.08 2.826-1.485 4.007-.215.184-.423.088-.327-.151l.175-.439c.343-.88.802-2.198.52-2.555-.336-.43-2.22-.207-3.074-.103-.255.032-.295-.192-.063-.36 1.5-1.053 3.967-.75 4.254-.399"/></svg>

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@@ -1,3 +1,3 @@
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path fill="#29F1FB" d="M8.932 20.806c-.369 0-.738.007-1.109 0-.35-.007-.587-.206-.623-.5a.587.587 0 0 1 .53-.636c.79-.062 1.582-.063 2.372-.003a.548.548 0 0 1 .522.602c-.024.326-.253.526-.616.54zM1.792 8.345c-.392 0-.782.008-1.173.002-.327-.006-.577-.22-.614-.512-.037-.293.146-.544.499-.615.192-.032.388-.045.583-.039a81.515 81.515 0 0 1 1.597 0c.163 0 .325.019.483.056.288.073.445.318.411.617-.034.298-.214.477-.515.487-.424.014-.848.004-1.272.004zm7.588 8.417H4.292a2.464 2.464 0 0 1-.326-.007c-.294-.04-.48-.209-.508-.506-.029-.298.11-.501.391-.606.179-.065.365-.051.549-.051 3.347 0 6.695.005 10.042-.006 1.174-.004 2.187-.439 2.993-1.3.69-.738 1.053-1.63 1.16-2.635.085-.788-.027-1.513-.516-2.156-.544-.718-1.28-1.078-2.163-1.082-3.163-.013-6.328-.005-9.487-.01-.336 0-.673-.027-1.007-.058-.29-.027-.45-.201-.469-.492-.021-.317.141-.545.429-.6a1.55 1.55 0 0 1 .29-.015h10.177c1.71.004 3.187 1.038 3.726 2.654.383 1.147.246 2.304-.182 3.416-.824 2.135-2.762 3.448-5.055 3.454-1.652.005-3.304 0-4.956 0zm2.906-13.568c1.533 0 3.066-.008 4.598 0 2.935.018 5.629 1.892 6.653 4.626.442 1.181.538 2.403.412 3.657-.185 1.842-.735 3.552-1.776 5.084-1.608 2.365-3.873 3.68-6.679 4.118-.95.148-1.905.13-2.86.13-.397 0-.61-.181-.633-.51-.025-.351.196-.621.587-.645.434-.026.87-.004 1.305-.016 2.641-.072 4.928-.982 6.74-2.935 1.269-1.37 1.912-3.039 2.13-4.878.151-1.275.135-2.544-.37-3.752-.773-1.85-2.159-2.983-4.068-3.509-.74-.204-1.5-.243-2.26-.247-2.837-.017-5.675-.007-8.511-.007-.12 0-.24.004-.359-.006a.57.57 0 0 1-.517-.536.557.557 0 0 1 .456-.557c.13-.018.261-.024.392-.019h4.762Z"/>
<path fill="currentColor" d="M8.932 20.806c-.369 0-.738.007-1.109 0-.35-.007-.587-.206-.623-.5a.587.587 0 0 1 .53-.636c.79-.062 1.582-.063 2.372-.003a.548.548 0 0 1 .522.602c-.024.326-.253.526-.616.54zM1.792 8.345c-.392 0-.782.008-1.173.002-.327-.006-.577-.22-.614-.512-.037-.293.146-.544.499-.615.192-.032.388-.045.583-.039a81.515 81.515 0 0 1 1.597 0c.163 0 .325.019.483.056.288.073.445.318.411.617-.034.298-.214.477-.515.487-.424.014-.848.004-1.272.004zm7.588 8.417H4.292a2.464 2.464 0 0 1-.326-.007c-.294-.04-.48-.209-.508-.506-.029-.298.11-.501.391-.606.179-.065.365-.051.549-.051 3.347 0 6.695.005 10.042-.006 1.174-.004 2.187-.439 2.993-1.3.69-.738 1.053-1.63 1.16-2.635.085-.788-.027-1.513-.516-2.156-.544-.718-1.28-1.078-2.163-1.082-3.163-.013-6.328-.005-9.487-.01-.336 0-.673-.027-1.007-.058-.29-.027-.45-.201-.469-.492-.021-.317.141-.545.429-.6a1.55 1.55 0 0 1 .29-.015h10.177c1.71.004 3.187 1.038 3.726 2.654.383 1.147.246 2.304-.182 3.416-.824 2.135-2.762 3.448-5.055 3.454-1.652.005-3.304 0-4.956 0zm2.906-13.568c1.533 0 3.066-.008 4.598 0 2.935.018 5.629 1.892 6.653 4.626.442 1.181.538 2.403.412 3.657-.185 1.842-.735 3.552-1.776 5.084-1.608 2.365-3.873 3.68-6.679 4.118-.95.148-1.905.13-2.86.13-.397 0-.61-.181-.633-.51-.025-.351.196-.621.587-.645.434-.026.87-.004 1.305-.016 2.641-.072 4.928-.982 6.74-2.935 1.269-1.37 1.912-3.039 2.13-4.878.151-1.275.135-2.544-.37-3.752-.773-1.85-2.159-2.983-4.068-3.509-.74-.204-1.5-.243-2.26-.247-2.837-.017-5.675-.007-8.511-.007-.12 0-.24.004-.359-.006a.57.57 0 0 1-.517-.536.557.557 0 0 1 .456-.557c.13-.018.261-.024.392-.019h4.762Z"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -1,3 +0,0 @@
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path fill="#D22128" d="M17.805 2.197v.066h.156v.44h.072v-.44h.156v-.066zm.9 0l-.175.353-.172-.353h-.087v.506h.067V2.3l.172.35h.045l.172-.35v.404h.066v-.506zm-4.257 1c-.204.31-.424.66-.66 1.06l-.04.062a44.457 44.457 0 00-1.265 2.29c-.187.36-.38.742-.577 1.146l2.267-.25c.66-.302.955-.578 1.242-.976a15.5 15.5 0 00.23-.342c.23-.363.46-.763.663-1.16.197-.386.37-.767.505-1.11.083-.22.15-.422.198-.6.042-.158.074-.307.1-.45-.884.15-1.965.295-2.668.33zM11.894 7.78l-.077.16c-.078.16-.157.32-.236.488-.086.18-.172.364-.26.552l-.132.287a75.265 75.265 0 00-1.427 3.3c-.163.397-.327.807-.493 1.23-.15.38-.297.765-.45 1.164l-.02.06c-.15.396-.3.802-.453 1.22l-.01.027.72-.08a.213.213 0 01-.042-.006c.863-.106 2.01-.75 2.75-1.547.342-.367.652-.8.94-1.306.213-.377.413-.795.604-1.258.168-.405.328-.843.48-1.318-.196.105-.423.18-.673.235a2.184 2.184 0 01-.273.046c.806-.31 1.314-.905 1.683-1.64a2.816 2.816 0 01-.968.428c-.06.012-.116.022-.174.03l-.043.006h.002c.278-.118.514-.248.718-.403a2.571 2.571 0 00.637-.698l.063-.104.077-.154a8.107 8.107 0 00.367-.85l.03-.088a3.04 3.04 0 00.123-.463.733.733 0 01-.094.065c-.243.145-.66.277-.996.34l.663-.074-.664.073h-.017l-.1.017c.006-.003.01-.006.017-.008l-2.265.25-.013.022zM8.27 16.45c-.117.323-.236.654-.355.992l-.005.015c-.016.046-.032.094-.05.142-.08.227-.15.432-.31.9.264.12.475.435.675.793a1.44 1.44 0 00-.466-.99c1.293.06 2.41-.27 2.99-1.217.05-.084.096-.173.14-.268-.26.333-.59.474-1.2.44 0 0-.004 0-.005.002l.004-.002c.9-.404 1.354-.79 1.754-1.433.094-.153.186-.32.28-.503-.788.81-1.702 1.04-2.664.865l-.72.078a6.43 6.43 0 00-.067.183zM15.42.112c-.376.222-1 .85-1.748 1.763l.686 1.294c.48-.687.97-1.307 1.462-1.836l.058-.062c-.02.02-.04.04-.057.062-.16.176-.644.74-1.375 1.863.703-.035 1.784-.18 2.666-.33.262-1.47-.258-2.142-.258-2.142s-.66-1.07-1.436-.61zm-3.084 6.402a40.253 40.253 0 011.306-2.26l.04-.064c.224-.352.45-.693.677-1.02l-.685-1.293-.157.192c-.197.245-.403.51-.613.79a39.853 39.853 0 00-2.016 2.97l-.022.038.893 1.763c.19-.378.38-.752.575-1.118zm-3.73 8.32c.158-.406.319-.81.483-1.225.156-.394.32-.79.484-1.19a91.133 91.133 0 011.6-3.604l.205-.424c.12-.243.237-.485.36-.724a.125.125 0 01.02-.04l-.895-1.763-.044.07c-.207.34-.414.687-.617 1.042a38.056 38.056 0 00-1.092 2.04l-.094.193a24.573 24.573 0 00-1.258 3.087 18.492 18.492 0 00-.52 1.997l.896 1.77c.117-.317.24-.638.364-.963zm-1.376-.476a13.38 13.38 0 00-.234 1.692c0 .02-.004.04-.005.06-.28-.45-1.03-.888-1.026-.884.537.778.944 1.55 1.005 2.31-.29.058-.684-.027-1.14-.195.475.436.83.556.97.588-.434.03-.89.328-1.346.67.668-.27 1.21-.38 1.596-.29-.61 1.74-1.23 3.655-1.843 5.69a.538.538 0 00.364-.354c.11-.368.84-2.786 1.978-5.965l.097-.27.028-.078c.12-.332.246-.672.374-1.02l.09-.237v-.004L7.24 14.3c-.003.02-.01.04-.012.06z"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.8 KiB

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="#EB5424" d="M21.98 7.448 19.62 0H4.347L2.02 7.448c-1.352 4.312.03 9.206 3.815 12.015L12.007 24l6.157-4.552c3.755-2.81 5.182-7.688 3.815-12.015l-6.16 4.58 2.343 7.45-6.157-4.597-6.158 4.58 2.358-7.433-6.188-4.55 7.63-.045L12.008 0l2.356 7.404 7.615.044z"/></svg>

Before

Width:  |  Height:  |  Size: 333 B

View File

@@ -1,3 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="#9CA3AF" height="34" viewBox="0 0 131 34">
<path fill="#9CA3AF" d="M.36 8.6h16.7v5.6H6.04c-.2 0-.35.16-.35.35v4.9c0 .2.16.35.35.35h11.02v5.6h-5.33c-.2 0-.35.16-.35.35v4.9c0 .2.16.35.35.35h4.98c.2 0 .35-.15.35-.35V25.4h5.34c.2 0 .35-.16.35-.35v-4.9c0-.2-.16-.35-.35-.35h-5.34v-5.6h5.34c.2 0 .35-.16.35-.35v-4.9c0-.2-.16-.35-.35-.35h-5.34V3.35c0-.2-.16-.35-.35-.35H.36c-.2 0-.36.16-.36.35v4.9c0 .2.16.35.36.35ZM44.41 14.7c-.5-.5-1.1-.9-1.76-1.18a5.62 5.62 0 0 0-4.6.17c-.73.37-1.32.91-1.75 1.62h-.17V8.59H34.1v16.83h2.04v-1.81h.17c.21.36.47.67.77.94.31.25.65.48 1.01.67.37.18.77.31 1.18.39a6.2 6.2 0 0 0 3.39-.24 5.36 5.36 0 0 0 3.02-3.1c.29-.75.44-1.62.44-2.6v-.47c0-.96-.16-1.83-.47-2.58-.3-.75-.7-1.4-1.23-1.9v-.01Zm-5.87.66a3.9 3.9 0 0 1 4.34.84c.36.35.64.8.83 1.3.2.5.3 1.07.3 1.7v.47c0 .64-.1 1.23-.3 1.74a3.75 3.75 0 0 1-2.06 2.15 4.27 4.27 0 0 1-3.12-.03 3.86 3.86 0 0 1-2.09-2.2c-.2-.52-.3-1.11-.3-1.75v-.29c0-.62.1-1.2.3-1.7v-.01c.21-.53.5-.99.84-1.36.36-.37.78-.66 1.26-.86ZM97.04 8.59H95v4.86h-2.94v1.86H95v8.17c0 .56.17 1.03.53 1.4.37.35.84.54 1.4.54h4.18v-1.87h-3.5c-.2 0-.33-.05-.43-.15-.1-.1-.14-.27-.14-.49v-7.6h4.65v-1.86h-4.65V8.59ZM114.61 15a5.48 5.48 0 0 0-1.8-1.33 5.6 5.6 0 0 0-2.57-.56 6.17 6.17 0 0 0-4.26 1.7 5.6 5.6 0 0 0-1.72 4.2v.57c0 .9.15 1.75.44 2.5a5.58 5.58 0 0 0 5.5 3.67c1.55 0 2.8-.35 3.72-1.04a5.35 5.35 0 0 0 1.91-2.73l.03-.07-1.94-.52-.02.07c-.11.33-.27.64-.46.94-.17.27-.4.52-.7.74-.28.22-.63.39-1.04.51-.41.13-.9.19-1.46.19a3.8 3.8 0 0 1-2.84-1.05 4.07 4.07 0 0 1-1.1-2.7h9.68v-1.6c0-.54-.11-1.12-.34-1.75a5.04 5.04 0 0 0-1.03-1.74Zm-8.25 3.21a3.8 3.8 0 0 1 1.22-2.25 4.19 4.19 0 0 1 3.99-.7c.44.16.83.38 1.17.66.34.27.62.62.82 1.02.21.38.34.8.38 1.27h-7.58ZM129.09 14.42a4.47 4.47 0 0 0-3.37-1.3c-.93 0-1.73.2-2.4.59-.64.39-1.15.97-1.52 1.74h-.17v-2h-2.04v11.97h2.04v-6.23c0-1.26.32-2.28.95-3.02a3.31 3.31 0 0 1 2.65-1.14c.94 0 1.7.3 2.24.9.56.6.83 1.52.83 2.74v6.75h2.04v-7.13c0-1.71-.42-3.02-1.25-3.87ZM88.1 15a5.48 5.48 0 0 0-1.78-1.33 5.6 5.6 0 0 0-2.58-.56 6.17 6.17 0 0 0-4.27 1.7 5.59 5.59 0 0 0-1.71 4.2v.56c0 .92.14 1.76.44 2.51a5.6 5.6 0 0 0 5.5 3.67c1.55 0 2.8-.35 3.72-1.04a5.36 5.36 0 0 0 1.91-2.73l.03-.07-1.94-.52-.03.07c-.1.32-.26.64-.45.94-.17.27-.4.52-.7.74-.29.21-.64.39-1.05.51-.4.12-.9.19-1.45.19a3.8 3.8 0 0 1-2.85-1.05 4.07 4.07 0 0 1-1.09-2.7h9.68v-1.61c0-.53-.12-1.12-.34-1.74A5.03 5.03 0 0 0 88.1 15Zm-8.24 3.21a3.83 3.83 0 0 1 1.22-2.25 4.2 4.2 0 0 1 3.99-.7c.44.16.83.38 1.16.66.35.27.62.62.83 1.02.2.38.33.8.37 1.27h-7.57ZM73.65 19.42a6.11 6.11 0 0 0-3.23-1.02 6.63 6.63 0 0 1-2.68-.58c-.47-.3-.7-.7-.7-1.25 0-.27.08-.5.21-.7.14-.2.33-.38.56-.52a4.05 4.05 0 0 1 1.78-.42c.85 0 1.54.21 2.06.63.53.41.83 1 .91 1.73l.01.1 1.95-.47-.01-.07c-.07-.45-.22-.91-.45-1.36a3.46 3.46 0 0 0-.94-1.2 4.6 4.6 0 0 0-1.52-.84 6.05 6.05 0 0 0-2.1-.34c-.58 0-1.13.07-1.65.22-.52.14-1 .36-1.43.65-.41.3-.74.66-.99 1.1a2.9 2.9 0 0 0-.37 1.49v.14c0 1.06.38 1.87 1.14 2.42a6.2 6.2 0 0 0 3.24.97c1.18.08 2.04.26 2.56.54.5.28.75.72.75 1.36 0 .6-.25 1.06-.78 1.4-.52.32-1.22.48-2.1.48a3.68 3.68 0 0 1-2.46-.79 3.13 3.13 0 0 1-1.04-2.14v-.09l-1.93.46h-.02v.07a4.4 4.4 0 0 0 3.1 4c.7.24 1.52.36 2.46.36.7 0 1.35-.09 1.93-.27.6-.16 1.12-.4 1.53-.72A3.38 3.38 0 0 0 74.8 22v-.14c0-1.07-.39-1.9-1.14-2.44ZM60.25 23.4c-.1-.1-.14-.27-.14-.49v-9.46h-2.05v1.85h-.16a3.78 3.78 0 0 0-1.61-1.63 4.62 4.62 0 0 0-2.26-.56c-.77 0-1.5.14-2.19.41a5.27 5.27 0 0 0-3.02 3.12c-.29.75-.44 1.63-.44 2.6v.38c0 .99.15 1.87.44 2.63.3.75.7 1.4 1.2 1.93a5.48 5.48 0 0 0 4.05 1.57c.8 0 1.51-.2 2.2-.58.69-.38 1.24-.97 1.63-1.75h.16v.06c0 .56.18 1.03.53 1.4.37.35.85.54 1.41.54h1.36v-1.87h-.68c-.2 0-.34-.05-.43-.15Zm-4.46.13c-.46.2-.97.3-1.52.3a3.68 3.68 0 0 1-2.75-1.09 4.42 4.42 0 0 1-1.05-3.12v-.38c0-.62.1-1.2.29-1.71a3.65 3.65 0 0 1 5-2.17c.47.2.88.49 1.21.86.35.37.62.83.8 1.36.2.5.3 1.08.3 1.7v.3c0 .63-.1 1.23-.3 1.76-.18.5-.45.96-.78 1.33-.33.37-.73.66-1.2.86Z"/>
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" height="34" viewBox="0 0 131 34">
<path fill="currentColor" d="M.36 8.6h16.7v5.6H6.04c-.2 0-.35.16-.35.35v4.9c0 .2.16.35.35.35h11.02v5.6h-5.33c-.2 0-.35.16-.35.35v4.9c0 .2.16.35.35.35h4.98c.2 0 .35-.15.35-.35V25.4h5.34c.2 0 .35-.16.35-.35v-4.9c0-.2-.16-.35-.35-.35h-5.34v-5.6h5.34c.2 0 .35-.16.35-.35v-4.9c0-.2-.16-.35-.35-.35h-5.34V3.35c0-.2-.16-.35-.35-.35H.36c-.2 0-.36.16-.36.35v4.9c0 .2.16.35.36.35ZM44.41 14.7c-.5-.5-1.1-.9-1.76-1.18a5.62 5.62 0 0 0-4.6.17c-.73.37-1.32.91-1.75 1.62h-.17V8.59H34.1v16.83h2.04v-1.81h.17c.21.36.47.67.77.94.31.25.65.48 1.01.67.37.18.77.31 1.18.39a6.2 6.2 0 0 0 3.39-.24 5.36 5.36 0 0 0 3.02-3.1c.29-.75.44-1.62.44-2.6v-.47c0-.96-.16-1.83-.47-2.58-.3-.75-.7-1.4-1.23-1.9v-.01Zm-5.87.66a3.9 3.9 0 0 1 4.34.84c.36.35.64.8.83 1.3.2.5.3 1.07.3 1.7v.47c0 .64-.1 1.23-.3 1.74a3.75 3.75 0 0 1-2.06 2.15 4.27 4.27 0 0 1-3.12-.03 3.86 3.86 0 0 1-2.09-2.2c-.2-.52-.3-1.11-.3-1.75v-.29c0-.62.1-1.2.3-1.7v-.01c.21-.53.5-.99.84-1.36.36-.37.78-.66 1.26-.86ZM97.04 8.59H95v4.86h-2.94v1.86H95v8.17c0 .56.17 1.03.53 1.4.37.35.84.54 1.4.54h4.18v-1.87h-3.5c-.2 0-.33-.05-.43-.15-.1-.1-.14-.27-.14-.49v-7.6h4.65v-1.86h-4.65V8.59ZM114.61 15a5.48 5.48 0 0 0-1.8-1.33 5.6 5.6 0 0 0-2.57-.56 6.17 6.17 0 0 0-4.26 1.7 5.6 5.6 0 0 0-1.72 4.2v.57c0 .9.15 1.75.44 2.5a5.58 5.58 0 0 0 5.5 3.67c1.55 0 2.8-.35 3.72-1.04a5.35 5.35 0 0 0 1.91-2.73l.03-.07-1.94-.52-.02.07c-.11.33-.27.64-.46.94-.17.27-.4.52-.7.74-.28.22-.63.39-1.04.51-.41.13-.9.19-1.46.19a3.8 3.8 0 0 1-2.84-1.05 4.07 4.07 0 0 1-1.1-2.7h9.68v-1.6c0-.54-.11-1.12-.34-1.75a5.04 5.04 0 0 0-1.03-1.74Zm-8.25 3.21a3.8 3.8 0 0 1 1.22-2.25 4.19 4.19 0 0 1 3.99-.7c.44.16.83.38 1.17.66.34.27.62.62.82 1.02.21.38.34.8.38 1.27h-7.58ZM129.09 14.42a4.47 4.47 0 0 0-3.37-1.3c-.93 0-1.73.2-2.4.59-.64.39-1.15.97-1.52 1.74h-.17v-2h-2.04v11.97h2.04v-6.23c0-1.26.32-2.28.95-3.02a3.31 3.31 0 0 1 2.65-1.14c.94 0 1.7.3 2.24.9.56.6.83 1.52.83 2.74v6.75h2.04v-7.13c0-1.71-.42-3.02-1.25-3.87ZM88.1 15a5.48 5.48 0 0 0-1.78-1.33 5.6 5.6 0 0 0-2.58-.56 6.17 6.17 0 0 0-4.27 1.7 5.59 5.59 0 0 0-1.71 4.2v.56c0 .92.14 1.76.44 2.51a5.6 5.6 0 0 0 5.5 3.67c1.55 0 2.8-.35 3.72-1.04a5.36 5.36 0 0 0 1.91-2.73l.03-.07-1.94-.52-.03.07c-.1.32-.26.64-.45.94-.17.27-.4.52-.7.74-.29.21-.64.39-1.05.51-.4.12-.9.19-1.45.19a3.8 3.8 0 0 1-2.85-1.05 4.07 4.07 0 0 1-1.09-2.7h9.68v-1.61c0-.53-.12-1.12-.34-1.74A5.03 5.03 0 0 0 88.1 15Zm-8.24 3.21a3.83 3.83 0 0 1 1.22-2.25 4.2 4.2 0 0 1 3.99-.7c.44.16.83.38 1.16.66.35.27.62.62.83 1.02.2.38.33.8.37 1.27h-7.57ZM73.65 19.42a6.11 6.11 0 0 0-3.23-1.02 6.63 6.63 0 0 1-2.68-.58c-.47-.3-.7-.7-.7-1.25 0-.27.08-.5.21-.7.14-.2.33-.38.56-.52a4.05 4.05 0 0 1 1.78-.42c.85 0 1.54.21 2.06.63.53.41.83 1 .91 1.73l.01.1 1.95-.47-.01-.07c-.07-.45-.22-.91-.45-1.36a3.46 3.46 0 0 0-.94-1.2 4.6 4.6 0 0 0-1.52-.84 6.05 6.05 0 0 0-2.1-.34c-.58 0-1.13.07-1.65.22-.52.14-1 .36-1.43.65-.41.3-.74.66-.99 1.1a2.9 2.9 0 0 0-.37 1.49v.14c0 1.06.38 1.87 1.14 2.42a6.2 6.2 0 0 0 3.24.97c1.18.08 2.04.26 2.56.54.5.28.75.72.75 1.36 0 .6-.25 1.06-.78 1.4-.52.32-1.22.48-2.1.48a3.68 3.68 0 0 1-2.46-.79 3.13 3.13 0 0 1-1.04-2.14v-.09l-1.93.46h-.02v.07a4.4 4.4 0 0 0 3.1 4c.7.24 1.52.36 2.46.36.7 0 1.35-.09 1.93-.27.6-.16 1.12-.4 1.53-.72A3.38 3.38 0 0 0 74.8 22v-.14c0-1.07-.39-1.9-1.14-2.44ZM60.25 23.4c-.1-.1-.14-.27-.14-.49v-9.46h-2.05v1.85h-.16a3.78 3.78 0 0 0-1.61-1.63 4.62 4.62 0 0 0-2.26-.56c-.77 0-1.5.14-2.19.41a5.27 5.27 0 0 0-3.02 3.12c-.29.75-.44 1.63-.44 2.6v.38c0 .99.15 1.87.44 2.63.3.75.7 1.4 1.2 1.93a5.48 5.48 0 0 0 4.05 1.57c.8 0 1.51-.2 2.2-.58.69-.38 1.24-.97 1.63-1.75h.16v.06c0 .56.18 1.03.53 1.4.37.35.85.54 1.41.54h1.36v-1.87h-.68c-.2 0-.34-.05-.43-.15Zm-4.46.13c-.46.2-.97.3-1.52.3a3.68 3.68 0 0 1-2.75-1.09 4.42 4.42 0 0 1-1.05-3.12v-.38c0-.62.1-1.2.29-1.71a3.65 3.65 0 0 1 5-2.17c.47.2.88.49 1.21.86.35.37.62.83.8 1.36.2.5.3 1.08.3 1.7v.3c0 .63-.1 1.23-.3 1.76-.18.5-.45.96-.78 1.33-.33.37-.73.66-1.2.86Z"/>
</svg>

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path fill="#355146" fill-rule="evenodd" d="M6.82 11.908c.525 0 1.57-.03 3.013-.639 1.682-.71 5.029-2 7.443-3.323 1.689-.926 2.429-2.151 2.429-3.8 0-2.29-1.81-4.146-4.043-4.146H6.307C3.1 0 .5 2.666.5 5.954s2.434 5.954 6.32 5.954" clip-rule="evenodd"/><path fill="#d18ee2" fill-rule="evenodd" d="M8.402 16.01c0-1.611.947-3.064 2.399-3.682l2.946-1.254c2.98-1.268 6.26.977 6.26 4.286 0 2.563-2.027 4.64-4.527 4.64l-3.19-.002c-2.147 0-3.888-1.785-3.888-3.987" clip-rule="evenodd"/><path fill="#ff7759" d="M3.848 12.691C1.998 12.691.5 14.228.5 16.124v.444C.5 18.464 1.999 20 3.848 20s3.347-1.536 3.347-3.432v-.444c0-1.896-1.499-3.433-3.347-3.433"/></svg>

Before

Width:  |  Height:  |  Size: 709 B

View File

@@ -1,9 +1,9 @@
<svg width="109" height="24" viewBox="0 0 109 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_125_22125)">
<path d="M0 -2.08616e-07V24H17.9352C22.9911 24 26.0999 21.0858 26.0999 17.04V6.96C26.0999 2.91432 22.9911 -2.08616e-07 17.9352 -2.08616e-07H0ZM6.76413 5.82864H19.1992V18.1714H6.76413V5.82864Z" fill="#9CA3AF"/>
<path d="M46.7659 18.6172H35.0824V14.16H46.7659V18.6172ZM46.595 5.38296V9.5658H35.0824V5.38296H46.595ZM50.2846 12.1373V11.5886C52.5734 10.5258 53.7008 8.8458 53.7008 6.13728C53.7008 2.64012 50.9337 0.000116183 45.5361 0.000116183H28.3184V24H45.7752C51.1728 24 53.9399 21.8401 53.9399 18.0685C53.9399 15.0172 52.6418 13.2001 50.2846 12.1373Z" fill="#9CA3AF"/>
<path d="M62.397 18.1714H74.8319V5.82864H62.397V18.1714ZM63.6609 24C58.6049 24 55.4961 21.0858 55.4961 17.04V6.96012C55.4961 2.91432 58.6049 0.000116183 63.6609 0.000116183H73.568C78.6238 0.000116183 81.7326 2.91432 81.7326 6.96012V17.04C81.7326 21.0858 78.6238 24 73.568 24H63.6609Z" fill="#9CA3AF"/>
<path d="M101.66 15.12L90.8995 14.3658C85.5361 13.9886 83.418 11.1772 83.418 7.47432V6.96012C83.418 2.91432 86.5266 0.000116183 91.5827 0.000116183H100.157C105.214 0.000116183 108.323 2.91432 108.323 6.96012V7.98864H101.968V5.14284H90.2504V8.43432L100.601 9.18864C105.999 9.56568 108.493 12.8572 108.493 16.5257V17.04C108.493 20.7428 105.384 24 100.328 24H91.5827C86.5266 24 83.418 20.7428 83.418 17.04V16.0115H89.7722V18.8572H101.66V15.12Z" fill="#9CA3AF"/>
<path d="M0 -2.08616e-07V24H17.9352C22.9911 24 26.0999 21.0858 26.0999 17.04V6.96C26.0999 2.91432 22.9911 -2.08616e-07 17.9352 -2.08616e-07H0ZM6.76413 5.82864H19.1992V18.1714H6.76413V5.82864Z" fill="currentColor"/>
<path d="M46.7659 18.6172H35.0824V14.16H46.7659V18.6172ZM46.595 5.38296V9.5658H35.0824V5.38296H46.595ZM50.2846 12.1373V11.5886C52.5734 10.5258 53.7008 8.8458 53.7008 6.13728C53.7008 2.64012 50.9337 0.000116183 45.5361 0.000116183H28.3184V24H45.7752C51.1728 24 53.9399 21.8401 53.9399 18.0685C53.9399 15.0172 52.6418 13.2001 50.2846 12.1373Z" fill="currentColor"/>
<path d="M62.397 18.1714H74.8319V5.82864H62.397V18.1714ZM63.6609 24C58.6049 24 55.4961 21.0858 55.4961 17.04V6.96012C55.4961 2.91432 58.6049 0.000116183 63.6609 0.000116183H73.568C78.6238 0.000116183 81.7326 2.91432 81.7326 6.96012V17.04C81.7326 21.0858 78.6238 24 73.568 24H63.6609Z" fill="currentColor"/>
<path d="M101.66 15.12L90.8995 14.3658C85.5361 13.9886 83.418 11.1772 83.418 7.47432V6.96012C83.418 2.91432 86.5266 0.000116183 91.5827 0.000116183H100.157C105.214 0.000116183 108.323 2.91432 108.323 6.96012V7.98864H101.968V5.14284H90.2504V8.43432L100.601 9.18864C105.999 9.56568 108.493 12.8572 108.493 16.5257V17.04C108.493 20.7428 105.384 24 100.328 24H91.5827C86.5266 24 83.418 20.7428 83.418 17.04V16.0115H89.7722V18.8572H101.66V15.12Z" fill="currentColor"/>
</g>
<defs>
<clipPath id="clip0_125_22125">

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -1,9 +0,0 @@
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<g fill="none" stroke="#EF4136" stroke-width="1.1" stroke-linecap="round" stroke-linejoin="round">
<rect x="2.2" y="2.2" width="19.6" height="19.6" rx="0.6"/>
<path d="M12 2.2V4.7a1.75 1.75 0 1 0 0 3.5V12"/>
<path d="M12 12v2.5a1.75 1.75 0 1 1 0 3.5v3.8"/>
<path d="M2.2 12h2.5a1.75 1.75 0 1 0 3.5 0H12"/>
<path d="M12 12h2.8a1.75 1.75 0 1 1 3.5 0h3.5"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 463 B

View File

@@ -1,3 +0,0 @@
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path fill="#00BFB3" d="M13.394 0C8.683 0 4.609 2.716 2.644 6.667h15.641a4.77 4.77 0 0 0 3.073-1.11c.446-.375.864-.785 1.247-1.243l.001-.002A11.974 11.974 0 0 0 13.394 0zM1.804 8.889a12.009 12.009 0 0 0 0 6.222h14.7a3.111 3.111 0 1 0 0-6.222zm.84 8.444C4.61 21.283 8.684 24 13.395 24c3.701 0 7.011-1.677 9.212-4.312l-.001-.002a9.958 9.958 0 0 0-1.247-1.243 4.77 4.77 0 0 0-3.073-1.11z"/>
</svg>

Before

Width:  |  Height:  |  Size: 469 B

View File

@@ -1 +1 @@
<svg fill="#F55036" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Groq</title><path d="M12.036 2c-3.853-.035-7 3-7.036 6.781-.035 3.782 3.055 6.872 6.908 6.907h2.42v-2.566h-2.292c-2.407.028-4.38-1.866-4.408-4.23-.029-2.362 1.901-4.298 4.308-4.326h.1c2.407 0 4.358 1.915 4.365 4.278v6.305c0 2.342-1.944 4.25-4.323 4.279a4.375 4.375 0 01-3.033-1.252l-1.851 1.818A7 7 0 0012.029 22h.092c3.803-.056 6.858-3.083 6.879-6.816v-6.5C18.907 4.963 15.817 2 12.036 2z"></path></svg>
<svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Groq</title><path d="M12.036 2c-3.853-.035-7 3-7.036 6.781-.035 3.782 3.055 6.872 6.908 6.907h2.42v-2.566h-2.292c-2.407.028-4.38-1.866-4.408-4.23-.029-2.362 1.901-4.298 4.308-4.326h.1c2.407 0 4.358 1.915 4.365 4.278v6.305c0 2.342-1.944 4.25-4.323 4.279a4.375 4.375 0 01-3.033-1.252l-1.851 1.818A7 7 0 0012.029 22h.092c3.803-.056 6.858-3.083 6.879-6.816v-6.5C18.907 4.963 15.817 2 12.036 2z"></path></svg>

Before

Width:  |  Height:  |  Size: 563 B

After

Width:  |  Height:  |  Size: 568 B

View File

@@ -1,74 +0,0 @@
<svg role="img" viewBox="0 0 102.04 102.04" xmlns="http://www.w3.org/2000/svg">
<rect x="45.34" y="23.92" width=".41" height="15.95" transform="translate(-9.7 38.24) rotate(-41.55)" fill="#106DA9"/>
<rect x="32.04" y="45.06" width="11.92" height="11.92" transform="translate(-13.28 88.67) rotate(-89.6)" fill="#106DA9"/>
<rect x="45.04" y="32.06" width="11.92" height="11.92" transform="translate(12.63 88.76) rotate(-89.6)" fill="#106DA9"/>
<rect x="45.04" y="58.06" width="11.92" height="11.92" transform="translate(-13.37 114.58) rotate(-89.6)" fill="#106DA9"/>
<rect x="58.04" y="45.06" width="11.92" height="11.92" transform="translate(12.54 114.67) rotate(-89.6)" fill="#106DA9"/>
<rect x="57.03" y="22.05" width="7.94" height="7.94" transform="translate(34.56 86.84) rotate(-89.6)" fill="#106DA9"/>
<rect x="36.03" y="22.05" width="7.94" height="7.94" transform="translate(13.7 65.84) rotate(-89.6)" fill="#106DA9"/>
<rect x="22.03" y="37.05" width="7.94" height="7.94" transform="translate(-15.2 66.73) rotate(-89.6)" fill="#106DA9"/>
<rect x="22.03" y="58.05" width="7.94" height="7.94" transform="translate(-36.2 87.59) rotate(-89.6)" fill="#106DA9"/>
<rect x="72.03" y="58.05" width="7.94" height="7.94" transform="translate(13.45 137.58) rotate(-89.6)" fill="#106DA9"/>
<rect x="72.03" y="37.05" width="7.94" height="7.94" transform="translate(34.45 116.73) rotate(-89.6)" fill="#106DA9"/>
<rect x="15.02" y="26.04" width="5.96" height="5.96" transform="translate(-11.15 46.82) rotate(-89.6)" fill="#106DA9"/>
<rect x="25.02" y="14.04" width="5.96" height="5.96" transform="translate(10.79 44.9) rotate(-89.61)" fill="#106DA9"/>
<rect x="40.02" y="9.04" width="5.96" height="5.96" transform="translate(30.68 54.94) rotate(-89.6)" fill="#106DA9"/>
<rect x="11.02" y="41.04" width="5.96" height="5.96" transform="translate(-30.12 57.71) rotate(-89.6)" fill="#106DA9"/>
<rect x="81.98" y="26" width="5.04" height="5.04" transform="translate(-.2 .59) rotate(-.4)" fill="#106DA9"/>
<rect x="70.98" y="15" width="5.04" height="5.04" transform="translate(-.12 .51) rotate(-.4)" fill="#106DA9"/>
<rect x="55.98" y="9" width="5.04" height="5.04" transform="translate(-.08 .41) rotate(-.4)" fill="#106DA9"/>
<rect x="84.98" y="41" width="5.04" height="5.03" transform="translate(-.3 .6) rotate(-.4)" fill="#106DA9"/>
<rect x="36.03" y="72.05" width="7.94" height="7.94" transform="translate(-36.3 115.49) rotate(-89.6)" fill="#106DA9"/>
<rect x="57.03" y="72.05" width="7.94" height="7.94" transform="translate(-15.44 136.49) rotate(-89.6)" fill="#106DA9"/>
<rect x="81.02" y="70.04" width="5.96" height="5.96" transform="translate(10.39 156.51) rotate(-89.6)" fill="#106DA9"/>
<rect x="70.02" y="82.04" width="5.96" height="5.96" transform="translate(-12.52 157.43) rotate(-89.6)" fill="#106DA9"/>
<rect x="56.02" y="87.04" width="5.96" height="5.96" transform="translate(-31.44 148.37) rotate(-89.59)" fill="#106DA9"/>
<rect x="84.02" y="55.04" width="5.96" height="5.96" transform="translate(28.35 144.6) rotate(-89.59)" fill="#106DA9"/>
<rect x="14.98" y="71" width="5.04" height="5.04" transform="translate(-.51 .12) rotate(-.4)" fill="#106DA9"/>
<rect x="25.98" y="82" width="5.03" height="5.04" transform="translate(-.61 .21) rotate(-.41)" fill="#106DA9"/>
<rect x="40.98" y="87" width="5.04" height="5.04" transform="translate(-.62 .3) rotate(-.4)" fill="#106DA9"/>
<rect x="11.98" y="55" width="5.04" height="5.04" transform="translate(-.4 .1) rotate(-.4)" fill="#106DA9"/>
<rect x="18.01" y="12.03" width="2.98" height="2.98" transform="translate(5.85 32.93) rotate(-89.61)" fill="#106DA9"/>
<rect x=".01" y="45.03" width="2.98" height="2.98" transform="translate(-45.03 47.71) rotate(-89.61)" fill="#106DA9"/>
<rect x="2.01" y="35.03" width="2.98" height="2.98" transform="translate(-33.04 39.77) rotate(-89.61)" fill="#106DA9"/>
<rect x="35.01" y="2.03" width="2.98" height="2.98" transform="translate(32.73 40) rotate(-89.61)" fill="#106DA9"/>
<rect x="6.01" y="26.03" width="2.98" height="2.98" transform="translate(-20.07 34.83) rotate(-89.61)" fill="#106DA9"/>
<rect x="11.01" y="18.03" width="2.98" height="2.98" transform="translate(-7.11 31.89) rotate(-89.61)" fill="#106DA9"/>
<rect x="25.99" y="6.01" width="3.02" height="3.02" transform="translate(-.05 .19) rotate(-.39)" fill="#106DA9"/>
<rect x="44.01" y=".03" width="2.98" height="2.98" transform="translate(0 .31) rotate(-.39)" fill="#106DA9"/>
<rect x="93.01" y="26.03" width="2.98" height="2.98" transform="translate(66.34 121.83) rotate(-89.61)" fill="#106DA9"/>
<rect x="97.01" y="35.03" width="2.98" height="2.98" transform="translate(61.31 134.77) rotate(-89.61)" fill="#106DA9"/>
<rect x="88.01" y="18.03" width="2.98" height="2.98" transform="translate(69.37 108.89) rotate(-89.61)" fill="#106DA9"/>
<rect x="98.01" y="45.03" width="2.98" height="2.98" transform="translate(52.3 145.7) rotate(-89.61)" fill="#106DA9"/>
<rect x="53.99" y=".01" width="3.02" height="3.02" transform="translate(53.6 57.01) rotate(-89.61)" fill="#106DA9"/>
<rect x="64.01" y="2.03" width="2.98" height="2.98" transform="translate(61.53 69) rotate(-89.61)" fill="#106DA9"/>
<rect x="18.01" y="12.03" width="2.98" height="2.98" transform="translate(5.85 32.93) rotate(-89.61)" fill="#106DA9"/>
<rect x=".01" y="45.03" width="2.98" height="2.98" transform="translate(-45.03 47.71) rotate(-89.61)" fill="#106DA9"/>
<rect x="81.01" y="12.03" width="2.98" height="2.98" transform="translate(68.42 95.93) rotate(-89.61)" fill="#106DA9"/>
<rect x="2.01" y="35.03" width="2.98" height="2.98" transform="translate(-33.04 39.77) rotate(-89.61)" fill="#106DA9"/>
<rect x="35.01" y="2.03" width="2.98" height="2.98" transform="translate(32.73 40) rotate(-89.61)" fill="#106DA9"/>
<rect x="6.01" y="26.03" width="2.98" height="2.98" transform="translate(-20.07 34.83) rotate(-89.61)" fill="#106DA9"/>
<rect x="11.01" y="18.03" width="2.98" height="2.98" transform="translate(-7.11 31.89) rotate(-89.61)" fill="#106DA9"/>
<rect x="25.99" y="6.01" width="3.02" height="3.02" transform="translate(-.05 .19) rotate(-.39)" fill="#106DA9"/>
<rect x="44.01" y=".03" width="2.98" height="2.98" transform="translate(0 .31) rotate(-.39)" fill="#106DA9"/>
<rect x="73.01" y="6.03" width="2.98" height="2.98" transform="translate(66.47 81.97) rotate(-89.61)" fill="#106DA9"/>
<rect x="98.01" y="45.03" width="2.98" height="2.98" transform="translate(52.3 145.7) rotate(-89.61)" fill="#106DA9"/>
<rect x="53.99" y=".01" width="3.02" height="3.02" transform="translate(53.6 57.01) rotate(-89.61)" fill="#106DA9"/>
<rect x="64.01" y="2.03" width="2.98" height="2.98" transform="translate(61.53 69) rotate(-89.61)" fill="#106DA9"/>
<rect x="81.01" y="88.03" width="2.98" height="2.98" transform="translate(-7.58 171.41) rotate(-89.61)" fill="#106DA9"/>
<rect x="98.01" y="54.03" width="2.98" height="2.98" transform="translate(43.31 154.64) rotate(-89.61)" fill="#106DA9"/>
<rect x="18.01" y="88.03" width="2.98" height="2.98" transform="translate(-70.15 108.42) rotate(-89.61)" fill="#106DA9"/>
<rect x="97.01" y="64.03" width="2.98" height="2.98" transform="translate(32.32 163.58) rotate(-89.61)" fill="#106DA9"/>
<rect x="64.01" y="97.04" width="2.97" height="2.97" transform="translate(-33.67 163.03) rotate(-89.43)" fill="#106DA9"/>
<rect x="93.01" y="73.03" width="2.98" height="2.98" transform="translate(19.31 168.49) rotate(-89.59)" fill="#106DA9"/>
<rect x="88.01" y="81.03" width="2.98" height="2.98" transform="translate(6.37 171.45) rotate(-89.61)" fill="#106DA9"/>
<rect x="72.99" y="93.01" width="3.02" height="3.02" transform="translate(-.65 .51) rotate(-.39)" fill="#106DA9"/>
<rect x="53.99" y="99.01" width="3.02" height="3.02" transform="translate(-.68 .38) rotate(-.39)" fill="#106DA9"/>
<rect x="26.01" y="93.03" width="2.98" height="2.98" transform="translate(-67.21 121.37) rotate(-89.61)" fill="#106DA9"/>
<rect x="6.01" y="73.03" width="2.98" height="2.98" transform="translate(-67.07 81.51) rotate(-89.61)" fill="#106DA9"/>
<rect x="2.01" y="64.03" width="2.98" height="2.98" transform="translate(-62.04 68.57) rotate(-89.61)" fill="#106DA9"/>
<rect x="11.01" y="81.03" width="2.98" height="2.98" transform="translate(-70.1 94.46) rotate(-89.61)" fill="#106DA9"/>
<rect x=".01" y="54.03" width="2.98" height="2.98" transform="translate(-54.03 56.65) rotate(-89.61)" fill="#106DA9"/>
<rect x="45.01" y="99.03" width="2.98" height="2.98" transform="translate(-54.33 146.34) rotate(-89.61)" fill="#106DA9"/>
<rect x="35.01" y="97.03" width="2.98" height="2.98" transform="translate(-62.27 134.34) rotate(-89.61)" fill="#106DA9"/>
</svg>

Before

Width:  |  Height:  |  Size: 8.5 KiB

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="#FFEC6E" d="m0 0 11.955 24L24 0zm13.366 4.827h1.393v1.38h-1.393zm-2.77 5.569H9.22V8.993h1.389zm0-2.087H9.22V6.906h1.389zm0-2.086H9.22V4.819h1.389zm2.087 6.263h-1.377V11.08h1.388zm0-2.09h-1.377V8.993h1.388zm0-2.087h-1.377V6.906h1.388zm0-2.086h-1.377V4.819h1.388zm.683.683h1.393v1.389h-1.393zm0 3.475V8.993h1.389v1.388Z"/></svg>

Before

Width:  |  Height:  |  Size: 398 B

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="#9CA3AF" d="M9.755 1.52h-.001c-.31 0-.608.124-.828.343L4.037 6.752a1.17 1.17 0 0 1-.827.343H1.17A1.17 1.17 0 0 0 0 8.295l.052 1.984a1.17 1.17 0 0 0 1.17 1.14h2.37c.31 0 .607-.124.827-.344l4.93-4.93c.22-.22.517-.343.827-.343h2.874a1.17 1.17 0 0 0 1.17-1.17V2.69a1.17 1.17 0 0 0-1.17-1.17zm9.78 2.503c-.31 0-.608.123-.828.343l-4.889 4.889a1.17 1.17 0 0 1-.827.342h-2.756c-.31 0-.608.124-.827.344L4.15 15.197a1.17 1.17 0 0 1-.827.343H1.32a1.17 1.17 0 0 0-1.17 1.17v1.996c0 .646.524 1.17 1.17 1.17h2.017c.302 0 .592-.116.81-.325l5.535-5.304a1.17 1.17 0 0 1 .81-.326h2.88c.31 0 .607-.123.827-.342l4.93-4.93c.22-.22.517-.344.827-.344h2.873A1.17 1.17 0 0 0 24 7.135V5.193a1.17 1.17 0 0 0-1.17-1.17h-3.294zm0 8.559c-.31 0-.608.123-.828.343l-4.889 4.889a1.17 1.17 0 0 1-.827.343h-2.04a1.17 1.17 0 0 0-1.17 1.2l.052 1.984a1.17 1.17 0 0 0 1.17 1.14h2.37c.31 0 .607-.124.827-.343l4.93-4.93c.22-.22.517-.343.827-.343h2.873a1.17 1.17 0 0 0 1.17-1.17v-1.943a1.17 1.17 0 0 0-1.17-1.17h-3.294Z"/></svg>

Before

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -1,5 +0,0 @@
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<rect x="2.34" y="2.34" width="19.27" height="19.27" rx="4.69" fill="#fff"/>
<circle cx="10.41" cy="11.95" r="2.77" fill="none" stroke="#000" stroke-width="1.36"/>
<rect x="15" y="8.53" width="1.36" height="6.94" fill="#000"/>
</svg>

Before

Width:  |  Height:  |  Size: 312 B

View File

@@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="#9CA3AF" viewBox="0 0 24 24"><title>PlanetScale</title><path d="M0 12C0 5.373 5.373 0 12 0c4.873 0 9.067 2.904 10.947 7.077l-15.87 15.87a12 12 0 0 1-1.935-1.099L14.99 12H12l-8.485 8.485A11.96 11.96 0 0 1 0 12m12.004 12L24 12.004C23.998 18.628 18.628 23.998 12.004 24"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24"><title>PlanetScale</title><path d="M0 12C0 5.373 5.373 0 12 0c4.873 0 9.067 2.904 10.947 7.077l-15.87 15.87a12 12 0 0 1-1.935-1.099L14.99 12H12l-8.485 8.485A11.96 11.96 0 0 1 0 12m12.004 12L24 12.004C23.998 18.628 18.628 23.998 12.004 24"/></svg>

Before

Width:  |  Height:  |  Size: 321 B

After

Width:  |  Height:  |  Size: 326 B

View File

@@ -1,3 +0,0 @@
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path fill="#FF6600" d="M23.035 9.601h-7.677a.956.956 0 01-.962-.962V.962a.956.956 0 00-.962-.956H10.56a.956.956 0 00-.962.956V8.64a.956.956 0 01-.962.962H5.762a.956.956 0 01-.961-.962V.962A.956.956 0 003.839 0H.959a.956.956 0 00-.956.962v22.076A.956.956 0 00.965 24h22.07a.956.956 0 00.962-.962V10.58a.956.956 0 00-.962-.98zm-3.86 8.152a1.437 1.437 0 01-1.437 1.443h-1.924a1.437 1.437 0 01-1.436-1.443v-1.917a1.437 1.437 0 011.436-1.443h1.924a1.437 1.437 0 011.437 1.443z"/>
</svg>

Before

Width:  |  Height:  |  Size: 557 B

View File

@@ -1,3 +1,3 @@
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path fill="#9CA3AF" d="M.113 10.27A13.026 13.026 0 000 11.48h18.23c-.064-.125-.15-.237-.235-.347-3.117-4.027-4.793-3.677-7.19-3.78-.8-.034-1.34-.048-4.524-.048-1.704 0-3.555.005-5.358.01-.234.63-.459 1.24-.567 1.737h9.342v1.216H.113v.002zm18.26 2.426H.009c.02.326.05.645.094.961h16.955c.754 0 1.179-.429 1.315-.96zm-17.318 4.28s2.81 6.902 10.93 7.024c4.855 0 9.027-2.883 10.92-7.024H1.056zM11.988 0C7.5 0 3.593 2.466 1.531 6.108l4.75-.005v-.002c3.71 0 3.849.016 4.573.047l.448.016c1.563.052 3.485.22 4.996 1.364.82.621 2.007 1.99 2.712 2.965.654.902.842 1.94.396 2.934-.408.914-1.289 1.458-2.353 1.458H.391s.099.42.249.886h22.748A12.026 12.026 0 0024 12.005C24 5.377 18.621 0 11.988 0z"/>
<path fill="currentColor" d="M.113 10.27A13.026 13.026 0 000 11.48h18.23c-.064-.125-.15-.237-.235-.347-3.117-4.027-4.793-3.677-7.19-3.78-.8-.034-1.34-.048-4.524-.048-1.704 0-3.555.005-5.358.01-.234.63-.459 1.24-.567 1.737h9.342v1.216H.113v.002zm18.26 2.426H.009c.02.326.05.645.094.961h16.955c.754 0 1.179-.429 1.315-.96zm-17.318 4.28s2.81 6.902 10.93 7.024c4.855 0 9.027-2.883 10.92-7.024H1.056zM11.988 0C7.5 0 3.593 2.466 1.531 6.108l4.75-.005v-.002c3.71 0 3.849.016 4.573.047l.448.016c1.563.052 3.485.22 4.996 1.364.82.621 2.007 1.99 2.712 2.965.654.902.842 1.94.396 2.934-.408.914-1.289 1.458-2.353 1.458H.391s.099.42.249.886h22.748A12.026 12.026 0 0024 12.005C24 5.377 18.621 0 11.988 0z"/>
</svg>

Before

Width:  |  Height:  |  Size: 771 B

After

Width:  |  Height:  |  Size: 776 B

View File

@@ -1,13 +1,13 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 590 270">
<path d="M30.36,109.14v.48h0A3.73,3.73,0,0,1,30.36,109.14Z" fill="#de3423" fill-rule="evenodd"/>
<path d="M30.36,109.14v.48h0A3.73,3.73,0,0,1,30.36,109.14Z" fill="currentColor" fill-rule="evenodd"/>
<path d="M138.66,28.78C107.2,37.87,57.29,43,30.4,43h0V94.35a.8.8,0,0,0,.19.48c18.35,0,75-6,109.18-15.4a129,129,0,0,0,17.49-5.81c4.18-1.88,6.88-3.86,6.88-5.92V15.91C164.1,20.79,151.39,25.11,138.66,28.78Z" fill="#de3423" fill-rule="evenodd"/>
<path d="M138.66,95.37c-18.83,5.43-44.24,9.47-67.39,11.83-15.54,1.59-30.06,2.42-40.87,2.42h0v51.31a.8.8,0,0,0,.19.48c18.35,0,75-6,109.18-15.39a130.38,130.38,0,0,0,17.49-5.81c4.18-1.89,6.88-3.86,6.88-5.92V82.5C164.1,87.37,151.39,91.69,138.66,95.37Z" fill="#de3423" fill-rule="evenodd"/>
<path d="M138.66,162c-18.83,5.43-44.24,9.46-67.39,11.83-15.56,1.59-30.1,2.42-40.91,2.42V228c18.16,0,75.1-5.95,109.37-15.39,12.63-3.48,24.37-7.44,24.37-11.74V149.08C164.1,154,151.39,158.28,138.66,162Z" fill="#de3423" fill-rule="evenodd"/>
<path d="M30.55,94.83C32.4,97.38,48,102.19,71.27,107.2c23.27,4.46,47.47,22.07,66.29,16.64,12.73-3.68,26.54-36.47,26.54-41.34V82c0-3.4-2.55-6.13-6.88-8.4-17.75-9.07-21.11-12.41-27.69-10.6C95.37,72.43,35.06,67.61,30.55,94.83Z" fill="#de3423" fill-rule="evenodd"/>
<path d="M30.55,161.41C32.4,164,48,168.77,71.27,173.79c26,4.74,48.61,20.19,67.44,14.75,12.73-3.68,25.39-34.58,25.39-39.46v-.48c0-3.39-2.55-6.13-6.88-8.39-13.54-7.2-31.43-15.13-38-13.32C85,136.3,39.26,138.37,30.55,161.41Z" fill="#de3423" fill-rule="evenodd"/>
<path d="M200.7,142.39c6,11.79,15.6,17.6,29.05,17.6,14.44,0,19.59-7.64,19.59-15.11,0-5.15-1.83-8.63-6.64-11.79-4.82-3.32-8.3-4.81-16.93-8-10.63-4-16.77-7-23.41-12.29-6.64-5.48-9.79-13-9.79-22.74a28.28,28.28,0,0,1,10.29-22.58c7-5.81,15.44-8.63,25.56-8.63,15.77,0,27.72,6.31,35.69,18.76L249.34,87.78c-4.48-6.81-11.29-10.3-20.59-10.3-9.13,0-15.77,5.15-15.77,12.29,0,4.81,2,7.14,4.82,10,1.82,1.33,6.47,3.32,8.63,4.48l6,2.32,6.8,2.66c11,4.48,18.76,9.3,23.57,14.44s7.31,12.12,7.31,20.75c0,20.42-14.11,34.2-40.51,34.2-21.41,0-37.18-10-44.48-26.4Z" fill="#de3423"/>
<path d="M354.25,104.71,342,117.49a28.14,28.14,0,0,0-21.24-9.13,25,25,0,0,0-18.43,7.47,27.76,27.76,0,0,0,0,37.52,25,25,0,0,0,18.43,7.47A28.14,28.14,0,0,0,342,151.69l12.29,12.78c-9,9.63-20.09,14.44-33.53,14.44-12.79,0-23.58-4.15-32.37-12.62s-13.12-19.09-13.12-31.7,4.32-23.08,13.12-31.54,19.58-12.78,32.37-12.78C334.16,90.27,345.28,95.08,354.25,104.71Z" fill="#de3423"/>
<path d="M393.88,125.62C408,124.3,413,122.47,413,116c0-5.15-4.64-9.13-13.94-9.13q-13.44,0-22.41,10.95l-12.28-10.46c8.13-11.45,19.58-17.09,34.36-17.09,20.75,0,33.7,10,33.7,27.05v37c0,5.81,2.15,6.48,7,6.48h.5v15.43c-2,1.17-5.15,1.83-9.3,1.83-4.48,0-8-1.33-10.62-4a14.06,14.06,0,0,1-3-5.48c-5.81,6.8-15.27,10.29-28.39,10.29-18.42,0-30.87-10.13-30.87-25.4C357.7,136.41,369.15,127.78,393.88,125.62ZM391.56,162c13.28,0,21.41-6,21.41-16.6v-9.3a9.75,9.75,0,0,1-4.14,2.49c-3.82,1.33-6.31,1.66-14.28,2.49-11.62,1.33-17.43,5-17.43,10.79C377.12,158.33,382.43,162,391.56,162Z" fill="#de3423"/>
<path d="M444.84,60.88h19.92V149.2c0,8.13,2.66,11.62,10,11.62a21.15,21.15,0,0,0,6-.67v17.76a35.56,35.56,0,0,1-9.47,1c-17.59,0-26.39-9-26.39-27.06Z" fill="#de3423"/>
<path d="M521.71,125.62c14.11-1.32,19.09-3.15,19.09-9.62,0-5.15-4.64-9.13-13.94-9.13q-13.44,0-22.41,10.95l-12.28-10.46c8.13-11.45,19.58-17.09,34.36-17.09,20.75,0,33.7,10,33.7,27.05v37c0,5.81,2.15,6.48,7,6.48h.5v15.43c-2,1.17-5.15,1.83-9.3,1.83-4.48,0-8-1.33-10.62-4a13.94,13.94,0,0,1-3-5.48c-5.81,6.8-15.27,10.29-28.39,10.29-18.42,0-30.87-10.13-30.87-25.4C485.53,136.41,497,127.78,521.71,125.62ZM519.39,162c13.28,0,21.41-6,21.41-16.6v-9.3a9.73,9.73,0,0,1-4.15,2.49c-3.81,1.33-6.3,1.66-14.27,2.49-11.62,1.33-17.43,5-17.43,10.79C505,158.33,510.26,162,519.39,162Z" fill="#de3423"/>
<path d="M30.55,94.83C32.4,97.38,48,102.19,71.27,107.2c23.27,4.46,47.47,22.07,66.29,16.64,12.73-3.68,26.54-36.47,26.54-41.34V82c0-3.4-2.55-6.13-6.88-8.4-17.75-9.07-21.11-12.41-27.69-10.6C95.37,72.43,35.06,67.61,30.55,94.83Z" fill="currentColor" fill-rule="evenodd"/>
<path d="M30.55,161.41C32.4,164,48,168.77,71.27,173.79c26,4.74,48.61,20.19,67.44,14.75,12.73-3.68,25.39-34.58,25.39-39.46v-.48c0-3.39-2.55-6.13-6.88-8.39-13.54-7.2-31.43-15.13-38-13.32C85,136.3,39.26,138.37,30.55,161.41Z" fill="currentColor" fill-rule="evenodd"/>
<path d="M200.7,142.39c6,11.79,15.6,17.6,29.05,17.6,14.44,0,19.59-7.64,19.59-15.11,0-5.15-1.83-8.63-6.64-11.79-4.82-3.32-8.3-4.81-16.93-8-10.63-4-16.77-7-23.41-12.29-6.64-5.48-9.79-13-9.79-22.74a28.28,28.28,0,0,1,10.29-22.58c7-5.81,15.44-8.63,25.56-8.63,15.77,0,27.72,6.31,35.69,18.76L249.34,87.78c-4.48-6.81-11.29-10.3-20.59-10.3-9.13,0-15.77,5.15-15.77,12.29,0,4.81,2,7.14,4.82,10,1.82,1.33,6.47,3.32,8.63,4.48l6,2.32,6.8,2.66c11,4.48,18.76,9.3,23.57,14.44s7.31,12.12,7.31,20.75c0,20.42-14.11,34.2-40.51,34.2-21.41,0-37.18-10-44.48-26.4Z" fill="currentColor"/>
<path d="M354.25,104.71,342,117.49a28.14,28.14,0,0,0-21.24-9.13,25,25,0,0,0-18.43,7.47,27.76,27.76,0,0,0,0,37.52,25,25,0,0,0,18.43,7.47A28.14,28.14,0,0,0,342,151.69l12.29,12.78c-9,9.63-20.09,14.44-33.53,14.44-12.79,0-23.58-4.15-32.37-12.62s-13.12-19.09-13.12-31.7,4.32-23.08,13.12-31.54,19.58-12.78,32.37-12.78C334.16,90.27,345.28,95.08,354.25,104.71Z" fill="currentColor"/>
<path d="M393.88,125.62C408,124.3,413,122.47,413,116c0-5.15-4.64-9.13-13.94-9.13q-13.44,0-22.41,10.95l-12.28-10.46c8.13-11.45,19.58-17.09,34.36-17.09,20.75,0,33.7,10,33.7,27.05v37c0,5.81,2.15,6.48,7,6.48h.5v15.43c-2,1.17-5.15,1.83-9.3,1.83-4.48,0-8-1.33-10.62-4a14.06,14.06,0,0,1-3-5.48c-5.81,6.8-15.27,10.29-28.39,10.29-18.42,0-30.87-10.13-30.87-25.4C357.7,136.41,369.15,127.78,393.88,125.62ZM391.56,162c13.28,0,21.41-6,21.41-16.6v-9.3a9.75,9.75,0,0,1-4.14,2.49c-3.82,1.33-6.31,1.66-14.28,2.49-11.62,1.33-17.43,5-17.43,10.79C377.12,158.33,382.43,162,391.56,162Z" fill="currentColor"/>
<path d="M444.84,60.88h19.92V149.2c0,8.13,2.66,11.62,10,11.62a21.15,21.15,0,0,0,6-.67v17.76a35.56,35.56,0,0,1-9.47,1c-17.59,0-26.39-9-26.39-27.06Z" fill="currentColor"/>
<path d="M521.71,125.62c14.11-1.32,19.09-3.15,19.09-9.62,0-5.15-4.64-9.13-13.94-9.13q-13.44,0-22.41,10.95l-12.28-10.46c8.13-11.45,19.58-17.09,34.36-17.09,20.75,0,33.7,10,33.7,27.05v37c0,5.81,2.15,6.48,7,6.48h.5v15.43c-2,1.17-5.15,1.83-9.3,1.83-4.48,0-8-1.33-10.62-4a13.94,13.94,0,0,1-3-5.48c-5.81,6.8-15.27,10.29-28.39,10.29-18.42,0-30.87-10.13-30.87-25.4C485.53,136.41,497,127.78,521.71,125.62ZM519.39,162c13.28,0,21.41-6,21.41-16.6v-9.3a9.73,9.73,0,0,1-4.15,2.49c-3.81,1.33-6.3,1.66-14.27,2.49-11.62,1.33-17.43,5-17.43,10.79C505,158.33,510.26,162,519.39,162Z" fill="currentColor"/>
</svg>

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@@ -140,7 +140,6 @@ function Hosts(): JSX.Element {
records: data.records,
total: data.total,
endTimeBeforeRetention: data.endTimeBeforeRetention,
warning: data.warning,
};
} catch (error) {
return {

View File

@@ -5,11 +5,9 @@ import androidJavaMonitoringUrl from '@/assets/Logos/android-java-monitoring.svg
import androidKotlinMonitoringUrl from '@/assets/Logos/android-kotlin-monitoring.svg';
import anthropicApiMonitoringUrl from '@/assets/Logos/anthropic-api-monitoring.svg';
import apacheDruidUrl from '@/assets/Logos/apache-druid.svg';
import apacheUrl from '@/assets/Logos/apache.svg';
import apiGatewayUrl from '@/assets/Logos/api-gateway.svg';
import argocdUrl from '@/assets/Logos/argocd.svg';
import aspnetUrl from '@/assets/Logos/aspnet.svg';
import auth0Url from '@/assets/Logos/auth0.svg';
import autogenUrl from '@/assets/Logos/autogen.svg';
import awsAlbUrl from '@/assets/Logos/aws-alb.svg';
import azureAppServiceUrl from '@/assets/Logos/azure-app-service.svg';
@@ -29,7 +27,6 @@ import claudeCodeUrl from '@/assets/Logos/claude-code.svg';
import clickhouseUrl from '@/assets/Logos/clickhouse.svg';
import cloudflareUrl from '@/assets/Logos/cloudflare.svg';
import cloudwatchLogsUrl from '@/assets/Logos/cloudwatch-logs.svg';
import cohereUrl from '@/assets/Logos/cohere.svg';
import confluentKafkaUrl from '@/assets/Logos/confluent-kafka.svg';
import convexLogoUrl from '@/assets/Logos/convex-logo.svg';
import cppUrl from '@/assets/Logos/cpp.svg';
@@ -42,13 +39,11 @@ import denoUrl from '@/assets/Logos/deno.svg';
import dockerUrl from '@/assets/Logos/docker.svg';
import documentLoadUrl from '@/assets/Logos/document-load.svg';
import dotnetUrl from '@/assets/Logos/dotnet.svg';
import dspyUrl from '@/assets/Logos/dspy.svg';
import dynamodbUrl from '@/assets/Logos/dynamodb.svg';
import ec2Url from '@/assets/Logos/ec2.svg';
import ecsUrl from '@/assets/Logos/ecs.svg';
import eksUrl from '@/assets/Logos/eks.svg';
import elasticacheUrl from '@/assets/Logos/elasticache.svg';
import elasticsearchUrl from '@/assets/Logos/elasticsearch.svg';
import elbUrl from '@/assets/Logos/elb.svg';
import elixirUrl from '@/assets/Logos/elixir.svg';
import elkUrl from '@/assets/Logos/elk.svg';
@@ -78,10 +73,8 @@ import grafanaUrl from '@/assets/Logos/grafana.svg';
import graphqlUrl from '@/assets/Logos/graphql.svg';
import grokUrl from '@/assets/Logos/grok.svg';
import groqUrl from '@/assets/Logos/groq.svg';
import haproxyUrl from '@/assets/Logos/haproxy.svg';
import hasuraUrl from '@/assets/Logos/hasura.svg';
import haystackUrl from '@/assets/Logos/haystack.svg';
import hcpVaultUrl from '@/assets/Logos/hcp-vault.svg';
import herokuUrl from '@/assets/Logos/heroku.svg';
import honeycombUrl from '@/assets/Logos/honeycomb.svg';
import hostmetricsUrl from '@/assets/Logos/hostmetrics.svg';
@@ -99,7 +92,6 @@ import kafkaUrl from '@/assets/Logos/kafka.svg';
import kubernetesUrl from '@/assets/Logos/kubernetes.svg';
import lambdaUrl from '@/assets/Logos/lambda.svg';
import langchainUrl from '@/assets/Logos/langchain.svg';
import langflowUrl from '@/assets/Logos/langflow.svg';
import langtraceUrl from '@/assets/Logos/langtrace.svg';
import litellmUrl from '@/assets/Logos/litellm.svg';
import livekitUrl from '@/assets/Logos/livekit.svg';
@@ -125,7 +117,6 @@ import ollamaUrl from '@/assets/Logos/ollama.svg';
import openaiUrl from '@/assets/Logos/openai.svg';
import openclawUrl from '@/assets/Logos/openclaw.svg';
import opencodeUrl from '@/assets/Logos/opencode.svg';
import openWebuiUrl from '@/assets/Logos/open-webui.svg';
import openlitUrl from '@/assets/Logos/openlit.svg';
import openrouterUrl from '@/assets/Logos/openrouter.svg';
import opentelemetryUrl from '@/assets/Logos/opentelemetry.svg';
@@ -140,7 +131,6 @@ import pythonUrl from '@/assets/Logos/python.svg';
import quarkusUrl from '@/assets/Logos/quarkus.svg';
import quickstartUrl from '@/assets/Logos/quickstart.svg';
import qwenUrl from '@/assets/Logos/qwen.svg';
import rabbitmqUrl from '@/assets/Logos/rabbitmq.svg';
import railwayUrl from '@/assets/Logos/railway.svg';
import rdsUrl from '@/assets/Logos/rds.svg';
import reactjsUrl from '@/assets/Logos/reactjs.svg';
@@ -3947,58 +3937,6 @@ const onboardingConfigWithLinks = [
],
link: '/docs/claude-code-monitoring/',
},
{
dataSource: 'cohere',
label: 'Cohere',
imgUrl: cohereUrl,
tags: ['LLM Monitoring'],
module: 'apm',
relatedSearchKeywords: [
'cohere',
'cohere api',
'cohere logs',
'cohere metrics',
'cohere monitoring',
'cohere observability',
'cohere traces',
'llm',
'llm monitoring',
'logging',
'logs',
'metrics',
'monitoring',
'observability',
'otel cohere integration',
'telemetry',
],
link: '/docs/cohere-monitoring/',
},
{
dataSource: 'langflow',
label: 'Langflow',
imgUrl: langflowUrl,
tags: ['LLM Monitoring'],
module: 'apm',
relatedSearchKeywords: [
'langflow',
'langflow logs',
'langflow metrics',
'langflow monitoring',
'langflow observability',
'langflow traces',
'llm',
'llm monitoring',
'logging',
'logs',
'low code ai',
'metrics',
'monitoring',
'observability',
'otel langflow integration',
'telemetry',
],
link: '/docs/langflow-observability/',
},
{
dataSource: 'deepseek-api',
label: 'DeepSeek API',
@@ -5545,32 +5483,12 @@ const onboardingConfigWithLinks = [
relatedSearchKeywords: [
'infrastructure',
'traefik',
'traefik access logs',
'traefik logs',
'traefik metrics',
'traefik monitoring',
'traefik observability',
'traefik tracing',
],
link: '/docs/tutorial/traefik-observability/',
question: {
desc: 'Which Traefik signals do you want to send to SigNoz?',
type: 'select',
options: [
{
key: 'traefik-metrics-traces',
label: 'Metrics & Traces',
imgUrl: opentelemetryUrl,
link: '/docs/tutorial/traefik-observability/',
},
{
key: 'traefik-logs',
label: 'Access Logs',
imgUrl: opentelemetryUrl,
link: '/docs/integrations/opentelemetry-traefik/',
},
],
},
},
{
dataSource: 'mongodb-atlas',
@@ -5600,32 +5518,11 @@ const onboardingConfigWithLinks = [
relatedSearchKeywords: [
'database',
'mysql',
'mysql error log',
'mysql logs',
'mysql metrics',
'mysql monitoring',
'mysql observability',
'mysql slow query log',
],
link: '/docs/metrics-management/mysql-metrics/',
question: {
desc: 'Which MySQL signals do you want to send to SigNoz?',
type: 'select',
options: [
{
key: 'mysql-metrics',
label: 'Metrics',
imgUrl: opentelemetryUrl,
link: '/docs/metrics-management/mysql-metrics/',
},
{
key: 'mysql-logs',
label: 'Logs',
imgUrl: opentelemetryUrl,
link: '/docs/integrations/opentelemetry-mysql/',
},
],
},
},
{
dataSource: 'jmx',
@@ -6570,30 +6467,6 @@ const onboardingConfigWithLinks = [
id: 'cert-manager',
link: '/docs/infrastructure-monitoring/cert-manager/',
},
{
dataSource: 'pgbouncer',
label: 'PgBouncer',
imgUrl: postgresqlUrl,
tags: ['infrastructure monitoring', 'metrics'],
module: 'metrics',
relatedSearchKeywords: [
'connection pooler',
'connection pooling',
'database',
'metrics',
'monitoring',
'observability',
'opentelemetry pgbouncer',
'pgbouncer',
'pgbouncer metrics',
'pgbouncer monitoring',
'pgbouncer observability',
'postgres',
'postgresql',
],
id: 'pgbouncer',
link: '/docs/metrics-management/opentelemetry-pgbouncer/',
},
{
dataSource: 'graphql',
label: 'GraphQL',
@@ -6618,28 +6491,6 @@ const onboardingConfigWithLinks = [
id: 'graphql',
link: '/docs/instrumentation/javascript/opentelemetry-graphql/',
},
{
dataSource: 'opentelemetry-ebpf',
label: 'OpenTelemetry eBPF (OBI)',
imgUrl: opentelemetryUrl,
tags: ['apm/traces'],
module: 'apm',
relatedSearchKeywords: [
'auto instrumentation',
'ebpf',
'obi',
'opentelemetry ebpf',
'opentelemetry obi',
'otel ebpf',
'zero code instrumentation',
'monitoring',
'observability',
'traces',
'tracing',
],
id: 'opentelemetry-ebpf',
link: '/docs/instrumentation/opentelemetry-ebpf/',
},
{
dataSource: 'railway',
label: 'Railway',
@@ -6662,54 +6513,6 @@ const onboardingConfigWithLinks = [
id: 'railway',
link: '/docs/integrations/outposts/railway/',
},
{
dataSource: 'hcp-vault',
label: 'HCP Vault',
imgUrl: hcpVaultUrl,
tags: ['logs'],
module: 'logs',
relatedSearchKeywords: [
'hashicorp',
'hashicorp vault',
'hcp',
'hcp vault',
'hcp vault logs',
'hcp vault monitoring',
'hcp vault observability',
'log forwarding',
'logging',
'logs',
'monitoring',
'observability',
'secrets management',
'vault',
],
id: 'hcp-vault',
link: '/docs/integrations/outposts/hcp-vault/',
},
{
dataSource: 'auth0',
label: 'Auth0',
imgUrl: auth0Url,
tags: ['logs'],
module: 'logs',
relatedSearchKeywords: [
'auth0',
'auth0 logs',
'auth0 monitoring',
'auth0 observability',
'authentication',
'authorization',
'identity',
'log forwarding',
'logging',
'logs',
'monitoring',
'observability',
],
id: 'auth0',
link: '/docs/integrations/outposts/auth0/',
},
{
dataSource: 'aspnet-core-metrics',
label: 'ASP.NET Core Metrics',
@@ -6829,164 +6632,5 @@ const onboardingConfigWithLinks = [
id: 'apache-druid',
link: '/docs/integrations/opentelemetry-apache-druid/',
},
{
dataSource: 'apache',
label: 'Apache HTTP Server',
imgUrl: apacheUrl,
tags: ['infrastructure monitoring', 'metrics', 'logs'],
module: 'metrics',
relatedSearchKeywords: [
'apache',
'apache access logs',
'apache error logs',
'apache http server',
'apache httpd',
'apache logs',
'apache metrics',
'apache monitoring',
'apache observability',
'httpd',
'infrastructure monitoring',
'logs',
'metrics',
'mod_status',
'monitoring',
'observability',
'opentelemetry apache',
'web server',
],
id: 'apache',
link: '/docs/integrations/opentelemetry-apache/',
},
{
dataSource: 'haproxy',
label: 'HAProxy',
imgUrl: haproxyUrl,
tags: ['infrastructure monitoring', 'metrics', 'logs'],
module: 'metrics',
relatedSearchKeywords: [
'haproxy',
'haproxy logs',
'haproxy metrics',
'haproxy monitoring',
'haproxy observability',
'infrastructure monitoring',
'load balancer',
'logs',
'metrics',
'monitoring',
'observability',
'opentelemetry haproxy',
'proxy',
'reverse proxy',
'syslog',
],
id: 'haproxy',
link: '/docs/integrations/opentelemetry-haproxy/',
},
{
dataSource: 'elasticsearch',
label: 'Elasticsearch',
imgUrl: elasticsearchUrl,
tags: ['database'],
module: 'metrics',
relatedSearchKeywords: [
'cluster health',
'database',
'elastic',
'elasticsearch',
'elasticsearch logs',
'elasticsearch metrics',
'elasticsearch monitoring',
'elasticsearch observability',
'logs',
'metrics',
'monitoring',
'observability',
'opentelemetry elasticsearch',
'search engine',
],
id: 'elasticsearch',
link: '/docs/integrations/opentelemetry-elasticsearch/',
},
{
dataSource: 'rabbitmq',
label: 'RabbitMQ',
imgUrl: rabbitmqUrl,
tags: ['Messaging Queues'],
module: 'metrics',
relatedSearchKeywords: [
'amqp',
'broker',
'logs',
'messaging',
'messaging queues',
'metrics',
'monitoring',
'observability',
'opentelemetry rabbitmq',
'queues',
'rabbitmq',
'rabbitmq logs',
'rabbitmq metrics',
'rabbitmq monitoring',
'rabbitmq observability',
],
id: 'rabbitmq',
link: '/docs/integrations/opentelemetry-rabbitmq/',
},
{
dataSource: 'open-webui',
label: 'Open WebUI',
imgUrl: openWebuiUrl,
tags: ['LLM Monitoring'],
module: 'apm',
relatedSearchKeywords: [
'llm',
'llm monitoring',
'logs',
'metrics',
'monitoring',
'observability',
'open webui',
'open webui logs',
'open webui metrics',
'open webui monitoring',
'open webui observability',
'open webui traces',
'openlit',
'openwebui',
'otel open webui integration',
'self hosted chat ui',
'traces',
'tracing',
],
id: 'open-webui',
link: '/docs/open-webui-monitoring/',
},
{
dataSource: 'dspy',
label: 'DSPy',
imgUrl: dspyUrl,
tags: ['LLM Monitoring'],
module: 'apm',
relatedSearchKeywords: [
'dspy',
'dspy monitoring',
'dspy observability',
'dspy traces',
'llm',
'llm monitoring',
'monitoring',
'observability',
'openinference',
'otel dspy integration',
'prompt optimization',
'traces',
'tracing',
],
id: 'dspy',
link: '/docs/dspy-observability/',
},
];
export default onboardingConfigWithLinks;

View File

@@ -648,176 +648,3 @@ describe('getQueryContextAtCursor - trailing dot in key/value', () => {
expect(ctx.keyToken).toBe('k8s.namespace');
});
});
describe('getQueryContextAtCursor - partial operator', () => {
it('treats text after an incomplete key as an operator prefix', () => {
const q = 'service.name c';
const ctx = getQueryContextAtCursor(q, q.length);
expect(ctx.isInOperator).toBe(true);
expect(ctx.isInKey).toBe(false);
expect(ctx.keyToken).toBe('service.name');
expect(ctx.operatorToken).toBe('c');
expect(ctx.currentPair).toStrictEqual(
expect.objectContaining({
key: 'service.name',
operator: 'c',
position: expect.objectContaining({
operatorStart: 13,
operatorEnd: 13,
}),
}),
);
});
it('keeps the operator context while completing contains', () => {
const q = 'service.name cont';
const ctx = getQueryContextAtCursor(q, q.length);
expect(ctx.isInOperator).toBe(true);
expect(ctx.keyToken).toBe('service.name');
expect(ctx.operatorToken).toBe('cont');
});
it('treats cursor mid-token as operator context', () => {
const q = 'service.name cont';
// cursor sits between "con" and "t" — user still typing the operator
const ctx = getQueryContextAtCursor(q, 15);
expect(ctx.isInOperator).toBe(true);
expect(ctx.isInKey).toBe(false);
expect(ctx.keyToken).toBe('service.name');
expect(ctx.operatorToken).toBe('cont');
});
it('keeps operator context when an AND conjunction precedes the pair', () => {
const q = 'a = 1 AND service.name c';
const ctx = getQueryContextAtCursor(q, q.length);
expect(ctx.isInOperator).toBe(true);
expect(ctx.isInKey).toBe(false);
expect(ctx.keyToken).toBe('service.name');
expect(ctx.operatorToken).toBe('c');
expect(ctx.currentPair).toStrictEqual(
expect.objectContaining({
key: 'service.name',
operator: 'c',
position: expect.objectContaining({
operatorStart: 23,
operatorEnd: 23,
}),
}),
);
});
it('keeps operator context when an open parenthesis precedes the pair', () => {
const q = '(service.name c';
const ctx = getQueryContextAtCursor(q, q.length);
expect(ctx.isInOperator).toBe(true);
expect(ctx.isInKey).toBe(false);
expect(ctx.keyToken).toBe('service.name');
expect(ctx.operatorToken).toBe('c');
});
it('re-glues a partial operator that follows a NOT negation', () => {
const q = 'service.name NOT c';
const ctx = getQueryContextAtCursor(q, q.length);
expect(ctx.isInOperator).toBe(true);
expect(ctx.isInKey).toBe(false);
expect(ctx.keyToken).toBe('service.name');
expect(ctx.operatorToken).toBe('NOT c');
// operatorStart points at the partial operator (post-NOT), not at the
// negation — so suggestion selection only replaces the partial, never
// the user's typed NOT.
expect(ctx.currentPair).toStrictEqual(
expect.objectContaining({
key: 'service.name',
operator: 'NOT c',
hasNegation: true,
position: expect.objectContaining({
negationStart: 13,
negationEnd: 15,
operatorStart: 17,
operatorEnd: 17,
}),
}),
);
});
it('re-glues a multi-character partial operator after NOT', () => {
const q = 'service.name NOT lik';
const ctx = getQueryContextAtCursor(q, q.length);
expect(ctx.isInOperator).toBe(true);
expect(ctx.keyToken).toBe('service.name');
expect(ctx.operatorToken).toBe('NOT lik');
expect(ctx.currentPair?.hasNegation).toBe(true);
});
it('re-glues an uppercase partial operator after NOT', () => {
const q = 'service.name NOT EXI';
const ctx = getQueryContextAtCursor(q, q.length);
expect(ctx.isInOperator).toBe(true);
expect(ctx.keyToken).toBe('service.name');
expect(ctx.operatorToken).toBe('NOT EXI');
expect(ctx.currentPair?.hasNegation).toBe(true);
});
it('preserves original NOT casing in the operator text', () => {
const q = 'service.name not c';
const ctx = getQueryContextAtCursor(q, q.length);
expect(ctx.isInOperator).toBe(true);
expect(ctx.keyToken).toBe('service.name');
expect(ctx.operatorToken).toBe('not c');
expect(ctx.currentPair?.hasNegation).toBe(true);
});
it('tolerates extra whitespace between NOT and the partial operator', () => {
const q = 'service.name NOT c';
const ctx = getQueryContextAtCursor(q, q.length);
expect(ctx.isInOperator).toBe(true);
expect(ctx.keyToken).toBe('service.name');
// Display text uses a canonical single space between NOT and the
// partial, regardless of how many spaces the user typed.
expect(ctx.operatorToken).toBe('NOT c');
expect(ctx.currentPair?.hasNegation).toBe(true);
});
it('keeps operator context for NOT-prefixed partial inside parentheses', () => {
const q = '(service.name NOT c';
const ctx = getQueryContextAtCursor(q, q.length);
expect(ctx.isInOperator).toBe(true);
expect(ctx.keyToken).toBe('service.name');
expect(ctx.operatorToken).toBe('NOT c');
expect(ctx.currentPair?.hasNegation).toBe(true);
});
it('keeps operator context for NOT-prefixed partial after an AND conjunction', () => {
const q = 'a = 1 AND service.name NOT c';
const ctx = getQueryContextAtCursor(q, q.length);
expect(ctx.isInOperator).toBe(true);
expect(ctx.keyToken).toBe('service.name');
expect(ctx.operatorToken).toBe('NOT c');
expect(ctx.currentPair?.hasNegation).toBe(true);
});
it('re-glues the most recent incomplete pair when three partial tokens are typed', () => {
// Pins documented behavior: with two trailing partial pairs (`c` and
// `k`), the heuristic pairs the most recent two — `c` becomes the
// key, `k` becomes the partial operator. The earlier `service.name`
// is dropped from the current pair view.
const q = 'service.name c k';
const ctx = getQueryContextAtCursor(q, q.length);
expect(ctx.isInOperator).toBe(true);
expect(ctx.keyToken).toBe('c');
expect(ctx.operatorToken).toBe('k');
});
});

View File

@@ -16,14 +16,9 @@ export const lazyRetry = (componentImport: ComponentImport): Promise<any> =>
resolve(component);
})
.catch((error: Error) => {
// A stale chunk reference right after a deploy self-heals: one reload pulls a
// fresh index.html with the new hashed asset names. That reload is only
// once-only if the flag persists, so a failed write (sessionStorage blocked in
// an iframe, storage disabled) must not reload at all — it would loop forever.
if (
!hasRefreshed &&
setSessionStorageApi(SESSIONSTORAGE.RETRY_LAZY_REFRESHED, 'true')
) {
if (!hasRefreshed) {
setSessionStorageApi(SESSIONSTORAGE.RETRY_LAZY_REFRESHED, 'true');
window.location.reload();
}

View File

@@ -605,98 +605,6 @@ export function getQueryContextAtCursor(
queryPairs,
);
// Re-glue a partial operator that ANTLR has lexed as a second key.
//
// When the user types `service.name c` (or `service.name NOT c`), the
// lexer sees two KEY tokens (`service.name`, `c`) instead of a key +
// partial operator, so `extractQueryPairs` emits two consecutive
// key-only incomplete pairs. Downstream, that makes the dropdown
// suggest keys when it should be suggesting operators.
//
// Detect that pattern — a previous incomplete key-only pair followed
// by another incomplete key-only `currentPair`, separated only by
// whitespace (or by a negation token attached to the previous pair) —
// and rebuild a single synthetic pair where the previous pair's key
// is the key and the current pair's key is treated as the partial
// operator. The synthetic pair inherits the previous pair's negation
// flag and positions via the spread, so `NOT <partial>` propagates
// correctly to consumers.
const previousIncompletePair = queryPairs
.filter(
(pair) =>
!pair.isComplete &&
!!pair.key &&
!pair.operator &&
pair.position.keyEnd < (currentPair?.position.keyStart ?? cursorIndex),
)
.sort((a, b) => b.position.keyEnd - a.position.keyEnd)[0];
if (
previousIncompletePair &&
currentPair &&
currentPair !== previousIncompletePair &&
!currentPair.operator &&
currentPair.position.keyStart > previousIncompletePair.position.keyEnd
) {
const negationStart = previousIncompletePair.position.negationStart ?? 0;
const negationEnd = previousIncompletePair.position.negationEnd ?? 0;
const negationAfterKey =
previousIncompletePair.hasNegation &&
negationStart > previousIncompletePair.position.keyEnd;
const gapStart = negationAfterKey
? negationEnd + 1
: previousIncompletePair.position.keyEnd + 1;
const textBetweenPairs = query.slice(
gapStart,
currentPair.position.keyStart,
);
if (textBetweenPairs.trim() === '') {
// The replacement range (operatorStart/operatorEnd) must point
// at the partial operator only, NOT the leading negation.
// Consumers like QuerySearch use it to splice the chosen
// suggestion in-place, so including the negation would let a
// `NOT lik` -> `LIKE` selection erase the user's typed `NOT`.
// Matches the convention used for complete pairs in
// extractQueryPairs, where operatorStart starts after the
// negation token.
const operatorStart = currentPair.position.keyStart;
const operatorEnd = currentPair.position.keyEnd;
const partialOperator = query.slice(operatorStart, operatorEnd + 1);
const operatorText = negationAfterKey
? `${query.slice(negationStart, negationEnd + 1)} ${partialOperator}`
: partialOperator;
return {
tokenType: -1,
text: '',
start: cursorIndex,
stop: cursorIndex,
currentToken: operatorText,
isInKey: false,
isInNegation: false,
isInOperator: true,
isInValue: false,
isInConjunction: false,
isInFunction: false,
isInParenthesis: false,
isInBracketList: false,
keyToken: previousIncompletePair.key,
operatorToken: operatorText,
queryPairs,
currentPair: {
...previousIncompletePair,
operator: operatorText,
position: {
...previousIncompletePair.position,
operatorStart,
operatorEnd,
},
},
};
}
}
// Check if cursor is within any of the specific context boundaries
// FIXED: Include the case where the cursor is exactly at the end of a boundary
const isInKeyBoundary =

View File

@@ -335,27 +335,69 @@ def _is_json_subset(subset, superset) -> bool:
return subset == superset
def _match_query_params(expected: dict, req: dict) -> bool:
"""Match a wiremock request's query params. Each expected value may be a string
(exact), an re.Pattern (search), or None (presence only, e.g. a dynamic hash)."""
query_params = req.get("queryParams", {})
for name, want in expected.items():
if name not in query_params:
return False
values = query_params[name].get("values", [])
if want is None:
if not values:
return False
elif isinstance(want, re.Pattern):
if not any(want.search(v) for v in values):
return False
elif want not in values:
return False
return True
def verify_webhook_notification_expectation(
notification_channel: types.TestContainerDocker,
validation_data: dict,
) -> bool:
"""Check if wiremock received a request at the given path
whose JSON body is a superset of the expected json_body."""
"""Check that wiremock received the expected request(s) at the given path.
validation_data supports (all optional except path):
- path: request url path (matched as urlPath, so query strings are ignored)
- json_body: expected JSON subset of the request body
- query_params: {name: str|re.Pattern|None} matched against the request query
- count: exact number of requests required at the path
- min_count: minimum number of requests required (e.g. retries)
Body/query constraints must be satisfied by a single request; count constraints
apply to the total at the path."""
path = validation_data["path"]
json_body = validation_data["json_body"]
json_body = validation_data.get("json_body")
query_params = validation_data.get("query_params")
url = notification_channel.host_configs["8080"].get("__admin/requests/find")
try:
res = requests.post(url, json={"method": "POST", "url": path}, timeout=10)
# urlPath matches the path only; the notifier appends a dynamic threadKey.
res = requests.post(url, json={"method": "POST", "urlPath": path}, timeout=10)
except requests.exceptions.RequestException:
return False
if res.status_code != HTTPStatus.OK:
return False
for req in res.json()["requests"]:
body = json.loads(base64.b64decode(req["bodyAsBase64"]).decode("utf-8"))
if _is_json_subset(json_body, body):
return True
reqs = res.json()["requests"]
if "count" in validation_data and len(reqs) != validation_data["count"]:
return False
if "min_count" in validation_data and len(reqs) < validation_data["min_count"]:
return False
if json_body is None and query_params is None:
return True
for req in reqs:
if json_body is not None:
body = json.loads(base64.b64decode(req["bodyAsBase64"]).decode("utf-8"))
if not _is_json_subset(json_body, body):
continue
if query_params is not None and not _match_query_params(query_params, req):
continue
return True
return False
@@ -416,7 +458,7 @@ def _received_notifications(
continue
url = notification_channel.host_configs["8080"].get("__admin/requests/find")
try:
res = requests.post(url, json={"method": "POST", "url": validation.validation_data["path"]}, timeout=10)
res = requests.post(url, json={"method": "POST", "urlPath": validation.validation_data["path"]}, timeout=10)
webhook_bodies.extend(json.loads(base64.b64decode(req["bodyAsBase64"]).decode("utf-8")) for req in res.json()["requests"])
except requests.exceptions.RequestException as exc:
webhook_bodies.append(f"<failed to fetch wiremock journal: {exc}>")
@@ -455,4 +497,11 @@ def update_raw_channel_config(
path = urlparse(original_url).path
entry[url_field] = notification_channel.container_configs["8080"].get(path)
# Google Chat validates the webhook host, so route via the https alias config
# (chat.googleapis.com:8443) keeping the path, and skip tls for wiremock's cert.
for entry in config.get("googlechat_configs", []):
path = urlparse(entry["webhook_url"]).path
entry["webhook_url"] = notification_channel.container_configs["8443"].get(path)
entry.setdefault("http_config", {}).setdefault("tls_config", {})["insecure_skip_verify"] = True
return config

View File

@@ -18,6 +18,10 @@ from fixtures.maildev import MAILDEV_INCOMING_PASS, SMTP_TEST_FROM
logger = setup_logger(__name__)
# Google Chat validates the webhook host, so the WireMock container is aliased as
# this hostname on the docker network and channels point at https://<host>:8443/...
GOOGLE_CHAT_HOST = "chat.googleapis.com"
EMAIL_TRANSPORT_KEYS = [
"from",
@@ -124,6 +128,19 @@ email_default_config = {
}
def googlechat_config(space: str) -> dict:
"""Google Chat channel config for a per-test WireMock space path. Title/text are
omitted so the backend applies its default templates. The host + tls-skip are
injected at runtime by update_raw_channel_config."""
return {
"googlechat_configs": [
{
"webhook_url": f"/v1/spaces/{space}/messages", # host set on runtime
}
],
}
@pytest.fixture(name="notification_channel", scope="package")
def notification_channel(
network: Network,
@@ -134,9 +151,27 @@ def notification_channel(
Package-scoped fixture for WireMock container to receive notifications for Alert rules.
"""
# A --reuse cache from before the https:8443 alias was added lacks the "8443"
# config that Google Chat delivery needs (and its container lacks the port/alias).
# Drop such a stale cache + container so the fixture recreates a correct one,
# instead of raising KeyError on container_configs["8443"].
cached = pytestconfig.cache.get("notification_channel", None)
if cached and "8443" not in (cached.get("container_configs") or {}):
logger.info("Recreating stale notification_channel (cache missing https:8443)")
try:
docker.from_env().containers.get(cached["id"]).remove(force=True)
except docker.errors.NotFound:
pass
pytestconfig.cache.set("notification_channel", None)
def create() -> types.TestContainerDocker:
# http:8080 admin/webhook delivery, plus https:8443 aliased as
# chat.googleapis.com so Google Chat's validated webhook host routes here.
container = WireMockContainer(image="wiremock/wiremock:2.35.1-1", secure=False)
container.with_cli_arg("--https-port", "8443")
container.with_exposed_ports(8080) # 8443 reached in-network via the alias, no host mapping needed
container.with_network(network)
container.with_network_aliases(GOOGLE_CHAT_HOST)
container.start()
return types.TestContainerDocker(
@@ -148,7 +183,11 @@ def notification_channel(
container.get_exposed_port(8080),
)
},
container_configs={"8080": types.TestContainerUrlConfig("http", container.get_wrapped_container().name, 8080)},
container_configs={
"8080": types.TestContainerUrlConfig("http", container.get_wrapped_container().name, 8080),
# Google Chat delivery: https to the validated host via the network alias.
"8443": types.TestContainerUrlConfig("https", GOOGLE_CHAT_HOST, 8443),
},
)
def delete(container: types.TestContainerDocker):

View File

@@ -0,0 +1,232 @@
"""Google Chat notifier integration tests driven through the real alerting path:
create a rule pointing at a Google Chat channel, insert breaching telemetry, let
the ruler fire, and assert on the cardsV2 payload WireMock received.
WireMock stands in for chat.googleapis.com (network alias + https:8443, see the
notification_channel fixture). Assertions check the actual card structure, deep
links and threading query params so behavioural regressions are caught.
"""
import json
import re
import time
import uuid
from collections.abc import Callable
from datetime import UTC, datetime, timedelta
import pytest
from wiremock.client import HttpMethods, Mapping, MappingRequest, MappingResponse
from fixtures import types
from fixtures.alerts import (
get_testdata_file_path,
update_raw_channel_config,
update_rule_channel_name,
verify_notification_expectation,
)
from fixtures.logger import setup_logger
from fixtures.notification_channel import googlechat_config
logger = setup_logger(__name__)
METRICS_DATA = "alerts/test_scenarios/threshold_above_at_least_once/alert_data.jsonl"
METRICS_RULE = "alerts/test_scenarios/threshold_above_at_least_once/rule.json"
LOGS_DATA = "alerts/test_scenarios/threshold_below_at_least_once/alert_data.jsonl"
LOGS_RULE = "alerts/test_scenarios/threshold_below_at_least_once/rule.json"
TRACES_DATA = "alerts/test_scenarios/threshold_above_average/alert_data.jsonl"
TRACES_RULE = "alerts/test_scenarios/threshold_above_average/rule.json"
# threading query params the notifier always appends
THREAD_QUERY = {
"messageReplyOption": "REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD",
"threadKey": None, # dynamic hash; presence only
}
def _path(space: str) -> str:
return f"/v1/spaces/{space}/messages"
def _stub_200(path: str) -> list[Mapping]:
return [
Mapping(
request=MappingRequest(method=HttpMethods.POST, url_path=path),
response=MappingResponse(status=200, json_body={"name": "spaces/x/messages/x"}),
persistent=True,
)
]
def _stub_retry(path: str) -> list[Mapping]:
"""429 on the first call then 200, via a wiremock scenario transition."""
scenario = f"gc-retry-{path}"
return [
Mapping(
request=MappingRequest(method=HttpMethods.POST, url_path=path),
response=MappingResponse(status=429, json_body={"error": {"code": 429, "status": "RESOURCE_EXHAUSTED"}}),
scenario_name=scenario,
required_scenario_state="Started",
new_scenario_state="ok",
persistent=True,
),
Mapping(
request=MappingRequest(method=HttpMethods.POST, url_path=path),
response=MappingResponse(status=200, json_body={"name": "spaces/x/messages/x"}),
scenario_name=scenario,
required_scenario_state="ok",
persistent=True,
),
]
def _card_subset(alertname: str, buttons: list[tuple[str, str]]) -> dict:
"""A cardsV2 subset asserting title, firing banner, rendered body, and each
button's text AND deep-link url (as a regex), so a broken link is caught too.
buttons: list of (text, url_regex)."""
return {
"text": f"[FIRING:1] {alertname}",
"cardsV2": [
{
"cardId": "signoz-alert",
"card": {
"header": {"title": f"[FIRING:1] {alertname}"},
"sections": [
# firing banner
{"widgets": [{"textParagraph": {"text": re.compile("FIRING")}}]},
# rendered alert body mentions the alertname
{"widgets": [{"textParagraph": {"text": re.compile(re.escape(alertname))}}]},
]
+ [{"widgets": [{"buttonList": {"buttons": [{"text": text, "onClick": {"openLink": {"url": re.compile(url)}}}]}}]} for text, url in buttons],
},
}
],
}
GOOGLECHAT_CASES = [
types.AlertManagerNotificationTestCase(
name="googlechat_default_metrics_firing",
rule_path=METRICS_RULE,
alert_data=[types.AlertData(type="metrics", data_path=METRICS_DATA)],
channel_config=googlechat_config("gc-metrics"),
notification_expectation=types.AMNotificationExpectation(
should_notify=True,
wait_time_seconds=150,
notification_validations=[
types.NotificationValidation(
destination_type="webhook",
validation_data={
"path": _path("gc-metrics"),
"query_params": THREAD_QUERY,
"json_body": _card_subset("threshold_above_at_least_once", [("Open in SigNoz", r"/alerts/overview\?ruleId=")]),
},
),
],
),
),
types.AlertManagerNotificationTestCase(
name="googlechat_rich_card_logs",
rule_path=LOGS_RULE,
alert_data=[types.AlertData(type="logs", data_path=LOGS_DATA)],
channel_config=googlechat_config("gc-logs"),
notification_expectation=types.AMNotificationExpectation(
should_notify=True,
wait_time_seconds=150,
notification_validations=[
types.NotificationValidation(
destination_type="webhook",
validation_data={
"path": _path("gc-logs"),
"json_body": _card_subset(
"threshold_below_at_least_once",
[("View Related Logs", r"/logs/logs-explorer\?"), ("Open in SigNoz", r"/alerts/overview\?ruleId=")],
),
},
),
],
),
),
types.AlertManagerNotificationTestCase(
name="googlechat_rich_card_traces",
rule_path=TRACES_RULE,
alert_data=[types.AlertData(type="traces", data_path=TRACES_DATA)],
channel_config=googlechat_config("gc-traces"),
notification_expectation=types.AMNotificationExpectation(
should_notify=True,
wait_time_seconds=150,
notification_validations=[
types.NotificationValidation(
destination_type="webhook",
validation_data={
"path": _path("gc-traces"),
"json_body": _card_subset(
"threshold_above_average",
[("View Related Traces", r"traces-explorer\?"), ("Open in SigNoz", r"/alerts/overview\?ruleId=")],
),
},
),
],
),
),
types.AlertManagerNotificationTestCase(
name="googlechat_retry_429_then_200",
rule_path=METRICS_RULE,
alert_data=[types.AlertData(type="metrics", data_path=METRICS_DATA)],
channel_config=googlechat_config("gc-retry"),
notification_expectation=types.AMNotificationExpectation(
should_notify=True,
wait_time_seconds=150,
notification_validations=[
types.NotificationValidation(
destination_type="webhook",
validation_data={
# a retryable 429 is followed by a successful re-POST => >=2 hits
"path": _path("gc-retry"),
"min_count": 2,
"json_body": {"cardsV2": [{"cardId": "signoz-alert"}]},
},
),
],
),
),
]
# per-case wiremock stubs (retry needs a stateful scenario, the rest a plain 200)
CASE_STUBS: dict[str, Callable[[str], list[Mapping]]] = {
"googlechat_retry_429_then_200": _stub_retry,
}
@pytest.mark.parametrize(
"gc_test_case",
GOOGLECHAT_CASES,
ids=lambda c: c.name,
)
def test_googlechat_notifier( # pylint: disable=too-many-arguments,too-many-positional-arguments
notification_channel: types.TestContainerDocker,
make_http_mocks: Callable[[types.TestContainerDocker, list[Mapping]], None],
create_notification_channel: Callable[[dict], str],
create_alert_rule: Callable[[dict], str],
insert_alert_data: Callable[[list[types.AlertData], datetime], None],
maildev: types.TestContainerDocker,
gc_test_case: types.AlertManagerNotificationTestCase,
) -> None:
channel_name = str(uuid.uuid4())
path = gc_test_case.notification_expectation.notification_validations[0].validation_data["path"]
channel_config = update_raw_channel_config(gc_test_case.channel_config, channel_name, notification_channel)
stub_factory = CASE_STUBS.get(gc_test_case.name, _stub_200)
make_http_mocks(notification_channel, stub_factory(path))
create_notification_channel(channel_config)
time.sleep(12) # org registration in alertmanager
insert_alert_data(gc_test_case.alert_data, base_time=datetime.now(tz=UTC) - timedelta(minutes=5))
with open(get_testdata_file_path(gc_test_case.rule_path), encoding="utf-8") as f:
rule_data = json.loads(f.read())
update_rule_channel_name(rule_data, channel_name)
create_alert_rule(rule_data)
verify_notification_expectation(notification_channel, maildev, gc_test_case.notification_expectation)

View File

@@ -0,0 +1,112 @@
"""Google Chat coverage for the testChannel API (POST /api/v1/testChannel).
testChannel drives the notifier once, synchronously, with a hardcoded test alert
and no retry. It is the button users click in the UI, and the deterministic place
to assert permanent-failure / no-retry behaviour. Rich-card and retry behaviour is
covered via the firing-rule path in alertmanager/04_googlechat.py.
"""
import base64
import json
import re
import time
import uuid
from collections.abc import Callable
from http import HTTPStatus
import pytest
import requests
from wiremock.client import HttpMethods, Mapping, MappingRequest, MappingResponse
from fixtures import types
from fixtures.alerts import update_raw_channel_config
from fixtures.auth import USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD
from fixtures.logger import setup_logger
from fixtures.notification_channel import googlechat_config
logger = setup_logger(__name__)
def _path(space: str) -> str:
return f"/v1/spaces/{space}/messages"
# name, space, stub status, stub body, expect testChannel 204
TEST_CHANNEL_CASES = [
("googlechat_test_channel_success", "gc-tc-ok", 200, {"name": "spaces/x/messages/x"}, True),
("googlechat_test_channel_permanent_400", "gc-tc-400", 400, {"error": {"code": 400, "status": "INVALID_ARGUMENT", "message": "Message cannot be empty."}}, False),
("googlechat_test_channel_permission_403", "gc-tc-403", 403, {"error": {"code": 403, "status": "PERMISSION_DENIED", "message": "Method doesn't allow unregistered callers"}}, False),
]
@pytest.mark.parametrize(
"name,space,status,body,expect_delivered",
TEST_CHANNEL_CASES,
ids=lambda v: v if isinstance(v, str) else "",
)
def test_googlechat_test_channel( # pylint: disable=too-many-arguments,too-many-positional-arguments,too-many-locals
signoz: types.SigNoz,
get_token: Callable[[str, str], str],
create_user_admin: None, # pylint: disable=unused-argument
notification_channel: types.TestContainerDocker,
make_http_mocks: Callable[[types.TestContainerDocker, list[Mapping]], None],
name: str, # pylint: disable=unused-argument
space: str,
status: int,
body: dict,
expect_delivered: bool,
) -> None:
path = _path(space)
make_http_mocks(
notification_channel,
[
Mapping(
request=MappingRequest(method=HttpMethods.POST, url_path=path),
response=MappingResponse(status=status, json_body=body),
persistent=True,
)
],
)
channel_name = str(uuid.uuid4())
receiver = update_raw_channel_config(googlechat_config(space), channel_name, notification_channel)
admin_token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
# org registration in alertmanager
time.sleep(10)
response = requests.post(
signoz.self.host_configs["8080"].get("/api/v1/testChannel"),
json=receiver,
headers={"Authorization": f"Bearer {admin_token}"},
timeout=30,
)
if expect_delivered:
assert response.status_code == HTTPStatus.NO_CONTENT, f"expected 204, got {response.status_code}: {response.text}"
else:
# a 400/403 is a permanent failure: testChannel surfaces it, does not retry
assert response.status_code != HTTPStatus.NO_CONTENT, f"expected failure status, got 204 for {status} stub"
# exactly one delivery attempt either way (testChannel never retries)
count = requests.post(
notification_channel.host_configs["8080"].get("/__admin/requests/count"),
json={"method": "POST", "urlPath": path},
timeout=10,
)
assert count.json()["count"] == 1, f"expected exactly 1 request (no retry), got {count.text}"
if expect_delivered:
find = requests.post(
notification_channel.host_configs["8080"].get("/__admin/requests/find"),
json={"method": "POST", "urlPath": path},
timeout=10,
)
req = find.json()["requests"][0]
# threading query params are always appended
assert "messageReplyOption=REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD" in req["url"]
assert "threadKey=" in req["url"]
# cardsV2 shape with the hardcoded test alert
card = json.loads(base64.b64decode(req["bodyAsBase64"]).decode("utf-8"))
assert card["cardsV2"][0]["cardId"] == "signoz-alert"
assert re.search(r"Test Alert \(", card["cardsV2"][0]["card"]["header"]["title"])

View File

@@ -1,314 +0,0 @@
"""Pins the keyless-row contract for filter operators, per signal.
The contract (deliberate product semantics, enforced by
`FilterOperator.AddDefaultExistsFilter` in
pkg/types/querybuildertypes/querybuildertypesv5/builder_elements.go):
- Negative operators (!=, NOT IN, NOT LIKE, NOT CONTAINS, ...) are a set
complement over ALL rows: a row that does not carry the key at all MUST
match. Users opt into presence explicitly with `AND key EXISTS`.
- Positive operators carry an implicit existence guard: a keyless row must
NOT match `key = ''`-style comparisons against sentinel defaults.
- EXISTS / NOT EXISTS partition rows exactly by key presence.
- Numeric attributes inherit the map-default sentinel: a missing key reads
as 0, so `num != 0` excludes keyless rows while `num != 5` includes them.
This conflation is deliberate and pinned here as the reference for any
value-expression change (for example coalesce tails in semconv families).
Any implementation change that makes these assertions fail is a behavior
break, not a cleanup. Family-field behavior must mirror this matrix; see
queriertraces/13_semconv_evolution.py.
The attribute names used here are deliberately outside every semantic
convention family so this file pins the base contract regardless of the
semconv overlay state.
"""
from collections.abc import Callable, Generator
from datetime import UTC, datetime, timedelta
from http import HTTPStatus
import pytest
from fixtures import types
from fixtures.auth import USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD
from fixtures.logs import Logs
from fixtures.metrics import Metrics
from fixtures.querier import (
BuilderQuery,
OrderBy,
RequestType,
TelemetryFieldKey,
aligned_epoch,
build_builder_query,
get_all_series,
get_column_data_from_response,
make_query_request,
)
from fixtures.traces import TraceIdGenerator, Traces, TracesKind, TracesStatusCode
PREFIX = "keyless-sem"
STRING_KEY = "tenant.tier"
NUMBER_KEY = "retry.count"
METRIC_NAME = "keyless_semantics_gauge"
METRIC_LABEL = "tenant_tier"
# Row identities, keyed by which value of the string key they carry.
GOLD = f"{PREFIX}-gold"
SILVER = f"{PREFIX}-silver"
NONE = f"{PREFIX}-none" # carries neither the string nor the number key
# One matrix, three signals. Each case: (filter over the string key, expected
# row identities). The keyless row's membership is the point of every case.
STRING_MATRIX = [
pytest.param("{key} = 'gold'", {GOLD}, id="eq_excludes_keyless"),
pytest.param("{key} != 'gold'", {SILVER, NONE}, id="neq_includes_keyless"),
pytest.param("{key} NOT IN ['gold', 'silver']", {NONE}, id="not_in_includes_keyless"),
pytest.param("NOT {key} LIKE '%gold%'", {SILVER, NONE}, id="not_like_includes_keyless"),
pytest.param("{key} NOT CONTAINS 'gol'", {SILVER, NONE}, id="not_contains_includes_keyless"),
pytest.param("{key} EXISTS", {GOLD, SILVER}, id="exists_partitions"),
pytest.param("{key} NOT EXISTS", {NONE}, id="not_exists_partitions"),
# The documented idiom for "present and not X": composition, not a new
# operator semantic.
pytest.param("{key} != 'gold' AND {key} EXISTS", {SILVER}, id="neq_composed_with_exists"),
]
# Numeric attributes read the map default (0) for missing keys. `!= 0` is the
# deliberate blind spot: a keyless row is indistinguishable from a stored 0.
NUMBER_MATRIX = [
pytest.param("{key} = 0", {GOLD}, id="numeric_eq_zero_excludes_keyless"),
pytest.param("{key} != 5", {GOLD, NONE}, id="numeric_neq_includes_keyless"),
pytest.param("{key} != 0", {SILVER}, id="numeric_neq_zero_sentinel_conflation"),
]
@pytest.fixture(name="keyless_rows")
def keyless_rows(
insert_logs: Callable[[list[Logs]], None],
insert_traces: Callable[[list[Traces]], None],
) -> Generator[datetime]:
now = datetime.now(tz=UTC).replace(microsecond=0) - timedelta(minutes=1)
def resources(identity: str, tier: str | None) -> dict:
base = {"service.name": identity}
if tier is not None:
base[STRING_KEY] = tier
return base
def attributes(tier: str | None, retries: int | None) -> dict:
attrs: dict = {}
if tier is not None:
attrs[STRING_KEY] = tier
if retries is not None:
attrs[NUMBER_KEY] = retries
return attrs
rows = [
(GOLD, "gold", 0, timedelta(seconds=3)),
(SILVER, "silver", 5, timedelta(seconds=2)),
(NONE, None, None, timedelta(seconds=1)),
]
insert_traces(
[
Traces(
timestamp=now - offset,
duration=timedelta(milliseconds=10),
trace_id=TraceIdGenerator.trace_id(),
span_id=TraceIdGenerator.span_id(),
name=identity,
kind=TracesKind.SPAN_KIND_SERVER,
status_code=TracesStatusCode.STATUS_CODE_OK,
resources=resources(identity, tier),
attributes=attributes(tier, retries),
)
for identity, tier, retries, offset in rows
]
)
insert_logs(
[
Logs(
timestamp=now - offset,
body=identity,
resources=resources(identity, tier),
attributes=attributes(tier, retries),
)
for identity, tier, retries, offset in rows
]
)
yield now
@pytest.fixture(name="keyless_series")
def keyless_series(insert_metrics: Callable[[list[Metrics]], None]) -> Generator[tuple[int, int]]:
start = aligned_epoch(timedelta(minutes=30))
points = 5
def labels(identity: str, tier: str | None) -> dict:
base = {"service": identity}
if tier is not None:
base[METRIC_LABEL] = tier
return base
insert_metrics(
[
Metrics(
metric_name=METRIC_NAME,
labels=labels(identity, tier),
timestamp=datetime.fromtimestamp(start + minute * 60, tz=UTC),
value=10.0,
type_="Gauge",
is_monotonic=False,
)
for identity, tier in ((GOLD, "gold"), (SILVER, "silver"), (NONE, None))
for minute in range(points)
]
)
yield start, start + points * 60
def _matching_rows(
signoz: types.SigNoz,
token: str,
now: datetime,
signal: str,
identity_field: str,
identity_column: str,
expression: str,
) -> set[str]:
response = make_query_request(
signoz,
token,
start_ms=int((now - timedelta(minutes=2)).timestamp() * 1000),
end_ms=int((now + timedelta(minutes=1)).timestamp() * 1000),
request_type=RequestType.RAW,
queries=[
BuilderQuery(
signal=signal,
name="A",
limit=100,
filter_expression=expression,
select_fields=[TelemetryFieldKey(identity_field)],
order=[OrderBy(TelemetryFieldKey("timestamp"), "asc")],
).to_dict()
],
)
assert response.status_code == HTTPStatus.OK, response.text
# Set semantics keep the assertions stable when the shared stack is reused
# across runs and older rows with the same identities are still present.
return {
value
for value in get_column_data_from_response(response.json(), identity_column)
if isinstance(value, str) and value.startswith(PREFIX)
}
@pytest.mark.parametrize("expression_template,expected", STRING_MATRIX)
@pytest.mark.parametrize("context", ["resource", "attribute"])
@pytest.mark.parametrize(
"signal,identity_field,identity_column",
[
pytest.param("traces", "span.name", "name", id="traces"),
pytest.param("logs", "body", "body", id="logs"),
],
)
def test_negative_operators_include_keyless_rows(
signoz: types.SigNoz,
create_user_admin: None, # pylint: disable=unused-argument
get_token: Callable[[str, str], str],
keyless_rows: datetime,
signal: str,
identity_field: str,
identity_column: str,
context: str,
expression_template: str,
expected: set[str],
) -> None:
"""Negative operators are a set complement over all rows; presence is an
explicit EXISTS opt-in. Holds identically for resource and attribute
contexts on traces and logs."""
token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
expression = expression_template.format(key=f"{context}.{STRING_KEY}")
assert (
_matching_rows(signoz, token, keyless_rows, signal, identity_field, identity_column, expression) == expected
), expression
@pytest.mark.parametrize("expression_template,expected", NUMBER_MATRIX)
@pytest.mark.parametrize(
"signal,identity_field,identity_column",
[
pytest.param("traces", "span.name", "name", id="traces"),
pytest.param("logs", "body", "body", id="logs"),
],
)
def test_numeric_sentinel_semantics(
signoz: types.SigNoz,
create_user_admin: None, # pylint: disable=unused-argument
get_token: Callable[[str, str], str],
keyless_rows: datetime,
signal: str,
identity_field: str,
identity_column: str,
expression_template: str,
expected: set[str],
) -> None:
"""A missing numeric key reads as the map default 0. `!= 0` therefore
excludes keyless rows while every other negative comparison includes
them. Inherited sentinel behavior, pinned on purpose."""
token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
expression = expression_template.format(key=f"attribute.{NUMBER_KEY}")
assert (
_matching_rows(signoz, token, keyless_rows, signal, identity_field, identity_column, expression) == expected
), expression
def _matching_series(
signoz: types.SigNoz,
token: str,
window: tuple[int, int],
expression: str,
) -> set[str]:
start, end = window
response = make_query_request(
signoz,
token,
start_ms=start * 1000,
end_ms=end * 1000,
queries=[
build_builder_query(
"A",
METRIC_NAME,
"avg",
"sum",
group_by=["service"],
filter_expression=expression,
)
],
)
assert response.status_code == HTTPStatus.OK, response.text
matched = set()
for series in get_all_series(response.json(), "A"):
for label in series.get("labels") or []:
key = label.get("key")
name = key.get("name") if isinstance(key, dict) else key
value = label.get("value")
if name == "service" and isinstance(value, str) and value.startswith(PREFIX):
matched.add(value)
return matched
@pytest.mark.parametrize("expression_template,expected", STRING_MATRIX)
def test_metrics_negative_operators_include_keyless_series(
signoz: types.SigNoz,
create_user_admin: None, # pylint: disable=unused-argument
get_token: Callable[[str, str], str],
keyless_series: tuple[int, int],
expression_template: str,
expected: set[str],
) -> None:
"""The same contract holds for metric labels: a series without the label
matches every negative filter on it, and EXISTS opts into presence."""
token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
expression = expression_template.format(key=METRIC_LABEL)
assert _matching_series(signoz, token, keyless_series, expression) == expected, expression