Compare commits

..

5 Commits

Author SHA1 Message Date
nityanandagohain
b65a3fcd3a fix: initalize querier in llmpricing 2026-07-07 00:40:12 +05:30
Vinicius Lourenço
64d0ada495 feat(infrastructure-monitoring): add disk usage chart for hosts (#11990) 2026-07-06 18:29:51 +00:00
Yunus M
60886fd906 fix: opening /ai-assistant opens 2 new conversations instead of one (#11923) 2026-07-06 16:58:00 +00:00
Yunus M
d8954da307 fix: context not being passed when user click suggestions in empty state (#11925) 2026-07-06 16:57:48 +00:00
Shivam Gupta
7476a2cacb feat(onboarding): add NGINX Ingress, FluxCD, Cassandra, Cloudflare Workers, PlanetScale, and Hermes Agent datasources (#11884)
* feat(onboarding): add NGINX Ingress, FluxCD, Cassandra, Cloudflare Workers, PlanetScale, and Hermes Agent datasources

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore(onboarding): optimize new datasource logo SVGs with svgo

Run svgo over cassandra.svg, fluxcd.svg, and planetscale.svg
(viewBox and <title> preserved). Trims coordinate precision and
metadata; fluxcd.svg shrinks ~24%.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 15:18:54 +00:00
32 changed files with 835 additions and 532 deletions

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="#1287b1" viewBox="0 0 24 24"><title>Apache Cassandra</title><path d="M10.374 10.53a3 3 0 0 1-.428-.222l.555.143c0 .02-.01.036-.01.055l-.117.025zm-.283 1.506-.315.253.852-1.079-1.078.391c.002.017.009.033.009.05a.57.57 0 0 1-.184.42q.154.327.375.616a3.2 3.2 0 0 1 .34-.651zm.717-2.347-.652-.82a.43.43 0 0 1-.506.162c-.054.073-.083.162-.13.24l1.258.463zm-1.666.444c-.07.314-.087.637-.05.956a.57.57 0 0 1 .451.475l.946-.606c-.067-.022-.126-.06-.191-.088l-1.119-.08.64-.14a3.2 3.2 0 0 1-.668-.554zM20.1 11.648c-.164.202.833 1.022.833 1.022s-1.654-1.022-2.234-.72c-.278.144.574.811 1.175 1.242-.428-.274-.982-.571-1.175-.408-.328.277 1.565 2.549 1.565 2.549s-2.145-2.322-2.36-2.209c-.214.114.593 1.224.593 1.224s-1.06-1.16-1.35-.959c-.29.202 1.514 3.218 1.514 3.218s-1.956-3.091-2.763-2.574c1.268 2.782.795 3.18.795 3.18s-.162-2.839-1.742-2.764c-.795.038.379 2.12.379 2.12s-1.08-1.902-1.8-1.864c1.326 2.51.854 3.53.854 3.53s.219-2.143-1.58-3.336c.682.606-.427 3.336-.427 3.336s.976-4.023-.719-3.256c-.268.121-.019 2.007-.019 2.007s-.34-2.158-.851-2.045c-.298.066-1.893 2.99-1.893 2.99s1.306-3.16.908-3.027c-.29.096-.833 1.4-.833 1.4s.265-1.287 0-1.363c-.264-.075-1.74 1.363-1.74 1.363s1.097-1.287.908-1.552c-.287-.402-.623-.42-1.022-.265-.581.226-1.363 1.287-1.363 1.287s.78-1.074.643-1.476c-.219-.647-2.46 1.249-2.46 1.249s1.325-1.25 1.022-1.514c-.303-.265-1.947-.183-2.46-.185-1.515-.004-2.039-.36-2.498-.724 1.987.997 3.803-.151 6.094.494l.21.06c-1.3-.558-2.144-1.378-2.226-2.354-.036-.416.074-.827.297-1.222.619-.4 1.29-.773 2.06-1.095a4 4 0 0 0-.064.698c0 2.44 2.203 4.417 4.92 4.417s4.92-1.977 4.92-4.417c0-.45-.083-.881-.223-1.29 1.431.404 2.45.968 3.132 1.335.022.092.045.184.053.279.024.274-.018.547-.11.814.095-.147.198-.288.28-.445.367-.997 1.855.227 1.855.227s-1.085-.454-1.06-.24c.026.215 1.628.96 1.628.96s-1.45-.455-1.362-.114c.088.34 1.817 1.703 1.817 1.703s-1.956-1.489-2.12-1.287zm-7.268 2.65.042-.008-.06.01zM9.256 9.753c.12.13.26.234.396.343l.927-.029-1.064-.788c-.093.154-.195.303-.26.474Zm10.62 3.44c.3.215.54.373.54.373s-.24-.181-.54-.374zM7.507 8.617c-.14.229-.214.492-.215.76a3.99 3.99 0 0 0 2.358 3.64q0-.008.003-.014a3.2 3.2 0 0 1-.58-.788c-.648.099-.926-.794-.336-1.08a3.2 3.2 0 0 1 .138-1.388 3.16 3.16 0 0 1-.52-1.36q-.444.105-.848.23m1.488.82q.163-.36.402-.661a.435.435 0 0 1 .568-.557c.077-.059.166-.099.248-.15a16 16 0 0 0-1.727.284c.114.388.272.76.509 1.084m2.285 3.928c1.4 0 2.633-.723 3.344-1.816a3.4 3.4 0 0 0-1.265-.539l-.297-.023.916.9-1.197-.467.704 1.078-1.074-.832-.012.006.347 1.278-.596-1.134-.098 1.33-.401-1.326-.472 1.261.114-1.359-.015-.008-.814 1.154.286-1.067c-.34.322-.605.713-.781 1.146q.143.153.303.29.484.126 1.008.128m10.145-4.434c.971-.567 1.716-1.955 1.716-1.955s-1.893 1.955-3.205 1.665c1.186-.934 1.766-2.549 1.766-2.549s-1.506 2.325-2.448 2.423c1.086-.959 1.54-2.322 1.54-2.322s-1.237 1.817-2.196 1.944c1.287-1.161 1.338-1.893 1.338-1.893s-1.781 2.302-2.499 1.943c.858-.934 1.439-2.12 1.439-2.12s-1.489 2.019-1.893 1.69c-.277-.05.454-.958.454-.958s-.908.807-1.16.606c.454-.278 1.236-1.64 1.236-1.64S16 7.505 15.621 7.304l.731-1.483s-.73 1.483-1.715 1.23c.454-.58.63-1.112.63-1.112s-.756 1.213-1.69.885c-.22-.077.273-.635.273-.635s-.626.61-1.055.534c-.43-.076.025-.858.025-.858s-.757 1.186-.908 1.136.075-.833.075-.833-.555.908-.858.858 0-.934 0-.934-.328.984-.58.909c-.252-.076-.303-.656-.303-.656s-.068.788-.429.858c-2.725.53-5.728 1.69-9.489 5.45C3.887 10.738 5.3 7.91 11.962 7.659c5.044-.191 7.399 2.137 8.177 2.17C22.51 9.93 24 7.633 24 7.633s-1.489 1.716-2.574 1.3zm-7.74.872-.608.464v.001l.054.003a3.4 3.4 0 0 0 .554-.468m1.583-.426c0-.536-.237-.929-.594-1.217a3.2 3.2 0 0 1-.165.825.393.393 0 0 1-.328.681c-.154.233-.34.445-.549.63l.661.034-.995.237c-.025.018-.045.041-.07.058a3.2 3.2 0 0 1 1.536.691c.32-.574.504-1.235.504-1.94zM10.99 7.996a3.5 3.5 0 0 0-.785.46.43.43 0 0 1-.013.357l.885.643.023-.016-.36-1.262.627 1.12c.018-.006.04-.006.058-.011l-.02-1.251.398 1.163.477-1.15.016 1.268.012.007.713-1.005-.363 1.218.009.01 1.04-.69-.759 1.05.002.005.95-.34.041-.045a.395.395 0 0 1 .394-.632 3.4 3.4 0 0 0 .27-.784 14 14 0 0 0-2.798-.168c-.286.011-.55.033-.817.053"/></svg>

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="48 -2.25 262.5 364"><defs><style>.cls-1{fill:#326ce5}.cls-3{fill:none}</style></defs><path d="M59.724 97.778a10.183 10.183 0 0 1 0-17.073l114.07-74.16a10.18 10.18 0 0 1 11.1 0l114.07 74.16a10.183 10.183 0 0 1 0 17.073l-114.07 74.16a10.18 10.18 0 0 1-11.1 0z" class="cls-1"/><path fill="#c1d2f7" d="M197.356 110.866h7.912a6.003 6.003 0 0 0 5.2-9.005l-25.924-44.902a6.004 6.004 0 0 0-10.399 0l-25.924 44.902a6.003 6.003 0 0 0 5.2 9.005h7.912a6.003 6.003 0 0 1 6.004 6.003v51.257l5.31 3.452a12.29 12.29 0 0 0 13.395 0l5.31-3.452v-51.257a6.003 6.003 0 0 1 6.004-6.003"/><path d="M173.793 353.271a10.1 10.1 0 0 0 3.457 1.402 119 119 0 0 0-6.623-3.46zm-6.456-161.195-11.316 7.356a111 111 0 0 0 11.316 6.6zm24.015 23.716c9.739 3.115 19.813 5.648 30.11 8.186 10.92 2.692 21.973 5.427 32.818 9.009l-35.416-23.025a216 216 0 0 1-27.512-9.41zm0 62.191v.586c0 2.57-2.688 4.652-6.003 4.652H173.34c-3.315 0-6.003-2.083-6.003-4.652v-6.605c-24.906-6.402-49.873-14.485-70.86-33.82l-14.529 9.445c22.468 22.05 50.28 28.933 79.715 36.189 27.178 6.698 55.18 13.651 78.685 33.442l14.68-9.544c-18.532-16.504-40.41-23.687-63.676-29.693M93.315 300.95l38.908 25.295c20.064 5.113 40.2 11.248 58.31 23.36l14.901-9.687c-19.752-13.672-42.55-19.313-66.419-25.197-15.287-3.767-30.835-7.616-45.7-13.771m74.022-82.254a124.3 124.3 0 0 1-21.534-12.62l-14.805 9.625a124.5 124.5 0 0 0 36.339 18.708zm51.41 16.294c-9.106-2.245-18.304-4.524-27.395-7.299v13.682q5.051 1.286 10.177 2.538c29.934 7.379 60.888 15.01 85.708 39.829.61.61 1.162 1.24 1.752 1.857l9.974-6.484a10.1 10.1 0 0 0 3.475-3.8 101 101 0 0 0-3.289-3.486c-22.585-22.585-50.669-29.508-80.402-36.837m-19.933 19.933q-3.722-.918-7.462-1.855v13.21c25.817 6.561 51.803 14.688 73.455 35.04l14.521-9.44-.11-.118c-22.586-22.585-50.67-29.509-80.404-36.837m-31.477-8.587c-16.28-5.278-32.118-12.397-46.344-24.131l-14.682 9.545c17.87 15.557 38.784 22.673 61.026 28.5z" class="cls-3"/><path d="M73.24 254.96c-.348-.348-.658-.71-1-1.06l-12.514 8.136a10 10 0 0 0-1.644 1.397c1.053 1.157 2.115 2.31 3.245 3.44 22.585 22.585 50.67 29.509 80.403 36.837 25.343 6.247 51.401 12.717 73.865 29.603l14.806-9.626c-20.865-16.42-45.53-22.509-71.453-28.898-29.934-7.379-60.888-15.01-85.708-39.83" class="cls-3"/><path d="m218.864 209.962-27.512-17.886v8.476a216 216 0 0 0 27.512 9.41m-27.512 5.83v11.9c9.091 2.774 18.289 5.053 27.395 7.298 29.733 7.329 57.817 14.252 80.402 36.837a101 101 0 0 1 3.29 3.486 10.193 10.193 0 0 0-3.476-13.277l-44.683-29.05c-10.845-3.58-21.898-6.316-32.818-9.008-10.297-2.538-20.371-5.071-30.11-8.186m-24.015-9.76a111 111 0 0 1-11.316-6.6l-10.218 6.644a124.3 124.3 0 0 0 21.534 12.62zm34.192 37.88q-5.125-1.264-10.177-2.539v11.695q3.737.938 7.462 1.855c29.733 7.328 57.818 14.252 80.403 36.837.039.039.073.079.111.118l9.66-6.28c-.589-.618-1.142-1.248-1.751-1.858-24.82-24.82-55.774-32.45-85.708-39.829m-34.192-9.503a124.5 124.5 0 0 1-36.34-18.708l-10.004 6.504c14.226 11.734 30.064 18.853 46.344 24.13zm0 25.842c-22.242-5.828-43.156-12.944-61.026-28.5l-9.834 6.392c20.987 19.336 45.954 27.42 70.86 33.821zm24.015 17.732c23.266 6.006 45.144 13.19 63.675 29.693l9.78-6.358c-21.652-20.352-47.638-28.479-73.455-35.04zM81.948 247.59l-9.707 6.311c.341.35.652.712 1 1.06 24.82 24.82 55.773 32.45 85.707 39.829 25.922 6.39 50.588 12.478 71.452 28.898l9.948-6.467c-23.505-19.791-51.507-26.744-78.685-33.442-29.436-7.256-57.247-14.138-79.715-36.189m-20.621 19.284c-1.13-1.13-2.192-2.283-3.245-3.44a10.154 10.154 0 0 0 1.644 15.68l33.589 21.837c14.865 6.155 30.413 10.004 45.7 13.771 23.869 5.884 46.667 11.525 66.419 25.197l10.16-6.605c-22.463-16.886-48.521-23.356-73.864-29.603-29.733-7.328-57.818-14.252-80.403-36.837m109.3 84.34a119 119 0 0 1 6.623 3.46 10.16 10.16 0 0 0 7.645-1.402l5.639-3.666c-18.11-12.112-38.247-18.247-58.311-23.36z" class="cls-1"/></svg>

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@@ -0,0 +1 @@
<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>

After

Width:  |  Height:  |  Size: 326 B

View File

@@ -20,9 +20,9 @@
padding: 0px 8px;
border-radius: 2px 0px 0px 2px;
border: 1px solid var(--input-with-label-border-color, var(--l2-border));
background: var(--input-with-label-background-color, var(--l2-background));
color: var(--input-with-label-color, var(--l2-foreground));
border: 1px solid var(--l2-border);
background: var(--l2-background);
color: var(--l2-foreground);
display: flex;
justify-content: flex-start;
@@ -35,54 +35,21 @@
min-width: 150px;
font-family: 'Space Mono', monospace !important;
--input-border-radius: 0px;
border: 1px solid var(--input-with-label-border-color, var(--l2-border));
background: var(--input-with-label-background-color, var(--l2-background));
color: var(--input-with-label-color, var(--l2-foreground));
border-radius: 2px 0px 0px 2px;
border: 1px solid var(--l1-border);
background: var(--l2-background);
border-right: none;
border-left: none;
border-top-right-radius: 0px;
border-bottom-right-radius: 0px;
border-top-left-radius: 0px;
border-bottom-left-radius: 0px;
font-size: 12px !important;
line-height: 25px;
position: relative;
&:hover,
&:focus {
z-index: 1;
}
.ant-select-selector {
position: relative;
border-radius: inherit;
}
.ant-select:hover .ant-select-selector,
.ant-select-focused .ant-select-selector {
z-index: 1;
}
&.input__has-label-after {
margin-left: -1px;
.ant-select-selector {
margin-left: -1px;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
}
&.input__has-close-button {
.ant-select-selector {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
~ .close-btn {
margin-left: -1px;
}
}
line-height: 27px;
&::placeholder {
color: var(--input-with-label-color, var(--l3-foreground)) !important;
color: var(--l2-foreground) !important;
font-size: 12px !important;
}
&[type='number']::-webkit-inner-spin-button,
@@ -96,35 +63,25 @@
.close-btn {
border-radius: 0px 2px 2px 0px;
border: 1px solid var(--input-with-label-border-color, var(--l2-border));
background: var(--input-with-label-background-color, var(--l2-background));
height: 100%;
border: 1px solid var(--l2-border);
background: var(--l2-background);
height: 38px;
width: 38px;
position: relative;
&:hover,
&:focus {
z-index: 2;
}
}
&.labelAfter {
.input {
border-radius: 2px;
border: 1px solid var(--input-with-label-border-color, var(--l2-border));
background: var(--input-with-label-background-color, var(--l2-background));
border-radius: 0px 2px 2px 0px;
border: 1px solid var(--l1-border);
background: var(--l2-background);
border-top-right-radius: 0px;
border-bottom-right-radius: 0px;
.ant-select-selector {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
}
.label {
border-left: none;
border-radius: 0px 2px 2px 0px;
border-top-left-radius: 0px;
border-bottom-left-radius: 0px;
}
}
}

View File

@@ -45,10 +45,7 @@ function InputWithLabel({
>
{!labelAfter && <Typography.Text className="label">{label}</Typography.Text>}
<Input
className={cx('input', {
'input__has-label-after': !labelAfter,
'input__has-close-button': !!onClose,
})}
className="input"
placeholder={placeholder}
type={type}
value={inputValue}

View File

@@ -80,8 +80,8 @@
width: 1px;
background: repeating-linear-gradient(
to bottom,
var(--query-builder-v2-border-color, var(--l2-border)),
var(--query-builder-v2-border-color, var(--l2-border)) 4px,
var(--l1-border),
var(--l1-border) 4px,
transparent 4px,
transparent 8px
);
@@ -101,8 +101,7 @@
top: 12px;
width: 6px;
height: 6px;
border-left: 6px dotted
var(--query-builder-v2-border-color, var(--l2-border));
border-left: 6px dotted var(--l1-border);
}
/* Horizontal line pointing from vertical to the item */
@@ -115,8 +114,8 @@
height: 1px;
background: repeating-linear-gradient(
to right,
var(--query-builder-v2-border-color, var(--l2-border)),
var(--query-builder-v2-border-color, var(--l2-border)) 4px,
var(--l1-border),
var(--l1-border) 4px,
transparent 4px,
transparent 8px
);
@@ -242,8 +241,7 @@
top: 12px;
width: 6px;
height: 6px;
border-left: 6px dotted
var(--query-builder-v2-border-color, var(--l2-border));
border-left: 6px dotted var(--l1-border);
}
/* Horizontal line pointing from vertical to the item */
@@ -256,8 +254,8 @@
height: 1px;
background: repeating-linear-gradient(
to right,
var(--query-builder-v2-border-color, var(--l2-border)),
var(--query-builder-v2-border-color, var(--l2-border)) 4px,
var(--l1-border),
var(--l1-border) 4px,
transparent 4px,
transparent 8px
);
@@ -275,16 +273,6 @@
line-height: 16px; /* 128.571% */
resize: none;
background-color: var(
--query-builder-v2-background-color,
var(--l2-background)
);
border: 1px solid var(--query-builder-v2-border-color, var(--l2-border));
&:placeholder {
color: var(--query-builder-v2-placeholder-color, var(--l3-foreground));
}
}
.formula-legend {
@@ -294,42 +282,15 @@
.ant-input-group-addon {
border-top-left-radius: 0px !important;
border-top-right-radius: 0px !important;
background: var(
--query-builder-v2-background-color,
var(--l2-background)
);
color: var(--query-builder-v2-color, var(--l2-foreground));
background: var(--l2-background);
color: var(--l2-foreground);
font-size: 12px;
font-weight: 300;
border: 1px solid var(--query-builder-v2-border-color, var(--l2-border));
position: relative;
}
.ant-input {
border-top-left-radius: 0px !important;
border-top-right-radius: 0px !important;
height: 36px;
background-color: var(
--query-builder-v2-background-color,
var(--l2-background)
);
border: 1px solid var(--query-builder-v2-border-color, var(--l2-border));
position: relative;
margin-left: -1px;
&:hover,
&:focus {
z-index: 1;
border-color: var(--internal-ant-border-color-hover);
}
&:placeholder {
color: var(--query-builder-v2-placeholder-color, var(--l3-foreground));
}
}
}
}
@@ -362,8 +323,8 @@
width: 1px;
background: repeating-linear-gradient(
to bottom,
var(--query-builder-v2-border-color, var(--l2-border)),
var(--query-builder-v2-border-color, var(--l2-border)) 4px,
var(--l1-border),
var(--l1-border) 4px,
transparent 4px,
transparent 8px
);
@@ -434,8 +395,8 @@
width: 1px;
background: repeating-linear-gradient(
to bottom,
var(--query-builder-v2-border-color, var(--l2-border)),
var(--query-builder-v2-border-color, var(--l2-border)) 4px,
var(--l1-border),
var(--l1-border) 4px,
transparent 4px,
transparent 8px
);
@@ -451,7 +412,7 @@
min-width: 120px;
border-radius: 2px;
border: 1px solid var(--query-builder-v2-border-color, var(--l2-border));
border: 1px solid var(--l1-border);
background: var(--l1-background);
box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1);
@@ -496,16 +457,13 @@
.ant-select-selector {
border-radius: 2px;
border: 1px solid var(--query-builder-v2-border-color, var(--l2-border)) !important;
background: var(
--query-builder-v2-background-color,
var(--l2-background)
) !important;
height: 36px !important;
border: 1px solid var(--l1-border) !important;
background: var(--l1-background) !important;
height: 34px !important;
box-sizing: border-box !important;
.ant-select-selection-item {
color: var(--query-builder-v2-color, var(--l1-foreground));
color: var(--l1-foreground);
}
}

View File

@@ -92,11 +92,6 @@
.ant-select {
width: 100%;
.ant-select-selector {
min-height: 36px;
}
.ant-select-selection-search-input {
min-width: max-content !important;
max-width: 100% !important;
@@ -105,12 +100,9 @@
.ant-select-selector {
border-radius: 2px;
border: 1px solid var(--query-builder-v2-border-color, var(--l2-border)) !important;
background-color: var(
--query-builder-v2-background-color,
var(--l2-background)
) !important;
color: var(--query-builder-v2-color, var(--l2-foreground));
border: 1.005px solid var(--l1-border);
background: var(--l1-background);
color: var(--l1-foreground);
font-family: 'Geist Mono';
font-size: 13px;
font-style: normal;
@@ -131,7 +123,6 @@
.input {
flex: initial;
width: 100px !important;
min-height: 36px;
}
}
}

View File

@@ -8,9 +8,9 @@
.ant-select-selection-search-input {
font-size: 12px !important;
line-height: 25px;
line-height: 27px;
&::placeholder {
color: var(--query-builder-v2-color, var(--l2-foreground)) !important;
color: var(--l2-foreground) !important;
font-size: 12px !important;
}
}
@@ -22,12 +22,9 @@
.ant-select-selector {
width: 100%;
border-radius: 2px;
border: 1px solid var(--query-builder-v2-border-color, var(--l2-border)) !important;
background-color: var(
--query-builder-v2-background-color,
var(--l2-background)
) !important;
color: var(--query-builder-v2-color, var(--l2-foreground));
border: 1px solid var(--l1-border) !important;
background: var(--l1-background);
color: var(--l1-foreground);
font-family: 'Geist Mono';
font-size: 13px;
font-style: normal;
@@ -36,49 +33,36 @@
min-height: 36px;
.ant-select-selection-placeholder {
color: var(
--query-builder-v2-placeholder-color,
var(--l3-foreground)
) !important;
color: var(--l2-foreground) !important;
font-size: 12px !important;
}
}
}
.qb-select-popover.ant-select-dropdown {
border-radius: 4px;
border: 1px solid var(--query-builder-v2-border-color, var(--l2-border));
background: var(--query-builder-v2-background-color, var(--l2-background));
box-shadow: 4px 10px 16px 2px rgba(0, 0, 0, 0.2);
backdrop-filter: blur(20px);
.ant-select-dropdown {
border-radius: 4px;
border: 1px solid var(--l1-border);
background: var(--l1-background);
box-shadow: 4px 10px 16px 2px rgba(0, 0, 0, 0.2);
backdrop-filter: blur(20px);
.ant-select-item {
color: var(--query-builder-v2-color, var(--l2-foreground));
font-family: 'Geist Mono';
font-size: 13px;
font-style: normal;
font-weight: 400;
line-height: 20px; /* 142.857% */
.ant-select-item {
color: var(--l1-foreground);
font-family: 'Geist Mono';
font-size: 13px;
font-style: normal;
font-weight: 400;
line-height: 20px; /* 142.857% */
&:not(:last-of-type) {
margin-bottom: 4px;
}
&:hover,
&.ant-select-item-option-active {
background: var(--l3-background) !important;
}
&:hover,
&.ant-select-item-option-active {
background: var(
--query-builder-v2-selected-background-color,
var(--l3-background)
) !important;
}
&.ant-select-item-option-selected {
background: var(
--query-builder-v2-selected-background-color,
var(--l3-background)
) !important;
border: 1px solid var(--query-builder-v2-border-color, var(--l2-border));
font-weight: 600;
&.ant-select-item-option-selected {
background: var(--l3-background) !important;
border: 1px solid var(--l1-border);
font-weight: 600;
}
}
}
}

View File

@@ -142,7 +142,6 @@ export const MetricsSelect = memo(function MetricsSelect({
{signalSourceChangeEnabled && (
<Select
className="source-selector"
popupClassName="qb-select-popover"
placeholder="Source"
options={SOURCE_OPTIONS}
value={source}

View File

@@ -1,23 +1,8 @@
// TODO: Improve the styling of the query aggregation container and its components. - @YounixM , @H4ad
.query-add-ons {
width: 100%;
--toggle-group-secondary-bg: var(
--query-builder-v2-toggle-group-background-color,
var(--l1-background-hover)
);
--toggle-group-secondary-border: var(
--query-builder-v2-toggle-group-border-color,
var(--l2-border)
);
--toggle-group-secondary-active-bg: var(
--query-builder-v2-toggle-group-active-background-color,
var(--l1-background)
);
--toggle-group-secondary-bg-hover: var(
--query-builder-v2-toggle-group-background-color-hover,
var(--l2-background)
);
.add-on-tab-title {
display: flex;
align-items: center;
@@ -44,33 +29,32 @@
font-style: normal;
font-weight: var(--font-weight-normal);
color: var(--query-builder-v2-color, var(--l2-foreground));
color: var(--l2-foreground);
}
> button {
border: 1px solid var(--query-builder-v2-border-color, var(--l2-border));
border: 1px solid var(--l1-border);
border-left: none;
min-width: 120px;
height: 36px;
line-height: 36px;
&:first-child {
border-left: 1px solid
var(--query-builder-v2-border-color, var(--l2-border));
border-left: 1px solid var(--l1-border);
}
&::before {
background: var(--query-builder-v2-border-color, var(--l2-border));
background: var(--l1-border);
}
&[data-state='on'] {
color: var(--text-robin-500);
border: 1px solid var(--query-builder-v2-border-color, var(--l2-border));
border: 1px solid var(--l1-border);
display: none;
&::before {
background: var(--query-builder-v2-border-color, var(--l2-border));
background: var(--l1-border);
}
}
}
@@ -81,7 +65,7 @@
height: 30px;
border-radius: 2px;
border: 1px solid var(--query-builder-v2-border-color, var(--l2-border));
border: 1px solid var(--l1-border);
background: var(--l3-background);
box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1);
}
@@ -94,13 +78,10 @@
align-items: center;
.having-filter-select-container {
position: relative;
width: 100%;
display: flex;
flex-direction: row;
align-items: flex-start;
background: var(--query-builder-v2-background-color, var(--l2-background));
padding-right: 38px;
align-items: center;
.having-filter-select-editor {
border-radius: 2px;
@@ -125,17 +106,15 @@
}
.cm-content {
border: 1px solid var(--query-builder-v2-border-color, var(--l2-border));
border-left-width: 0px;
border-right-width: 0px;
border-radius: 2px;
border: 1px solid var(--l1-border);
border-top-right-radius: 0px;
border-bottom-right-radius: 0px;
padding: 0px !important;
background-color: var(
--query-builder-v2-background-color,
var(--l2-background)
) !important;
background-color: var(--l2-background) !important;
&:focus-within {
border-color: var(--query-builder-v2-border-color, var(--l2-border));
border-color: var(--l1-border);
}
}
@@ -239,32 +218,17 @@
}
.cm-line {
min-height: 34px;
line-height: 32px !important;
line-height: 36px !important;
font-family: 'Space Mono', monospace !important;
background-color: var(
--query-builder-v2-background-color,
var(--l2-background)
) !important;
&,
.ͼ1a {
color: var(--query-builder-v2-color, var(--l2-foreground));
}
background-color: var(--l2-background) !important;
::-moz-selection {
background: var(
--query-builder-v2-selection-background-color,
var(--l3-background)
) !important;
background: var(--l3-background) !important;
opacity: 0.5 !important;
}
::selection {
background: var(
--query-builder-v2-selection-background-color,
var(--l3-background)
) !important;
background: var(--l3-background) !important;
opacity: 0.5 !important;
}
@@ -273,11 +237,8 @@
}
.chip-decorator {
background: var(
--query-builder-v2-chip-decorator-background-color,
var(--l3-background)
) !important;
color: var(--query-builder-v2-color, var(--l2-foreground)) !important;
background: var(--l3-background) !important;
color: var(--l1-foreground) !important;
border-radius: 4px;
padding: 2px 4px;
margin-right: 4px;
@@ -285,38 +246,34 @@
}
.cm-selectionBackground {
background: var(
--query-builder-v2-selection-background-color,
var(--l3-background)
) !important;
background: var(--l3-background) !important;
opacity: 0.5 !important;
}
.cm-activeLine > span {
font-size: 12px !important;
}
.cm-placeholder {
color: var(
--query-builder-v2-placeholder-color,
var(--l3-foreground)
) !important;
}
}
}
.close-btn {
position: absolute;
top: 0;
right: 0;
border-radius: 0px 2px 2px 0px;
border: 1px solid var(--query-builder-v2-border-color, var(--l2-border));
background: var(--query-builder-v2-background-color, var(--l2-background));
height: 100%;
border: 1px solid var(--l2-border);
background: var(--l2-background);
height: 38px;
width: 38px;
border-left: transparent;
border-top-left-radius: 0px;
border-bottom-left-radius: 0px;
&:focus:not(:focus-visible),
&.ant-btn:focus:not(:focus-visible) {
border-color: var(--l2-border);
border-left-color: transparent;
outline: none;
box-shadow: none;
}
}
}
}
@@ -343,8 +300,20 @@
font-size: 12px !important;
}
input {
min-height: 36px;
$add-on-row-height: 38px;
.periscope-input-with-label {
.input {
.ant-select {
height: $add-on-row-height;
}
}
}
.input-with-label {
.input {
height: $add-on-row-height;
}
}
}
}

View File

@@ -23,7 +23,7 @@
flex: 1;
min-width: 0;
font-size: 12px;
color: var(--query-builder-v2-color, var(--l2-foreground)) !important;
color: var(--l2-foreground) !important;
&.error {
.cm-editor {
@@ -51,15 +51,14 @@
.cm-content {
border-radius: 2px;
border: 1px solid var(--query-builder-v2-border-color, var(--l2-border));
border: 1px solid var(--l1-border);
border-top-right-radius: 0px;
border-bottom-right-radius: 0px;
padding: 0px !important;
background-color: var(
--query-builder-v2-background-color,
var(--l2-background)
) !important;
background-color: var(--l1-background) !important;
&:focus-within {
border-color: var(--query-builder-v2-border-color, var(--l2-border));
border-color: var(--l1-border);
}
}
@@ -75,7 +74,7 @@
right: 0px !important;
border-radius: 4px;
border: 1px solid var(--query-builder-v2-border-color, var(--l2-border));
border: 1px solid var(--l1-border);
background: linear-gradient(
139deg,
color-mix(in srgb, var(--card) 80%, transparent) 0%,
@@ -119,7 +118,7 @@
box-sizing: border-box;
overflow: hidden;
color: var(--query-builder-v2-color, var(--l2-foreground)) !important;
color: var(--l2-foreground) !important;
font-family: 'Space Mono', monospace !important;
.cm-completionIcon {
@@ -128,10 +127,7 @@
&:hover,
&[aria-selected='true'] {
background: var(
--query-builder-v2-selection-background-color,
var(--l3-background)
) !important;
background: var(--l3-background) !important;
color: var(--l1-foreground) !important;
font-weight: 600 !important;
}
@@ -146,24 +142,15 @@
.cm-line {
line-height: 36px !important;
font-family: 'Space Mono', monospace !important;
background-color: var(
--query-builder-v2-background-color,
var(--l2-background)
) !important;
background-color: var(--l2-background) !important;
::-moz-selection {
background: var(
--query-builder-v2-selection-background-color,
var(--l3-background)
) !important;
background: var(--l3-background) !important;
opacity: 0.5 !important;
}
::selection {
background: var(
--query-builder-v2-selection-background-color,
var(--l3-background)
) !important;
background: var(--l3-background) !important;
opacity: 0.5 !important;
}
@@ -172,11 +159,8 @@
}
.chip-decorator {
background: var(
--query-builder-v2-chip-decorator-background-color,
var(--l3-background)
) !important;
color: var(--query-builder-v2-color, var(--l1-foreground)) !important;
background: var(--l3-background) !important;
color: var(--l1-foreground) !important;
border-radius: 4px;
padding: 2px 4px;
margin-right: 4px;
@@ -184,10 +168,7 @@
}
.cm-selectionBackground {
background: var(
--query-builder-v2-selection-background-color,
var(--l3-background)
) !important;
background: var(--l3-background) !important;
opacity: 0.5 !important;
}
}
@@ -220,11 +201,12 @@
.close-btn {
border-radius: 0px 2px 2px 0px;
border: 1px solid var(--query-builder-v2-border-color, var(--l2-border));
background: var(--query-builder-v2-background-color, var(--l2-background));
height: 100%;
border: 1px solid var(--l1-border);
background: var(--l1-background);
height: 38px;
width: 38px;
border-left: transparent;
border-top-left-radius: 0px;
border-bottom-left-radius: 0px;
}
@@ -235,13 +217,13 @@
height: 36px;
line-height: 36px;
border-radius: 2px;
border: 1px solid var(--query-builder-v2-border-color, var(--l2-border));
border: 1px solid var(--l1-border);
box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1);
font-family: 'Space Mono', monospace !important;
&::placeholder {
color: var(--query-builder-v2-color, var(--l2-foreground));
color: var(--l1-foreground);
opacity: 0.5;
}
}
@@ -256,10 +238,9 @@
.query-aggregation-interval-input-container {
.query-aggregation-interval-input {
input {
min-height: 36px;
max-width: 120px;
&::placeholder {
color: var(--query-builder-v2-color, var(--l2-foreground));
color: var(--l2-foreground);
}
}
}
@@ -270,8 +251,8 @@
.query-aggregation-error-popover {
.ant-popover-inner {
background-color: var(--query-builder-v2-border-color, var(--l2-border));
border: 1px solid var(--query-builder-v2-border-color, var(--l2-border));
background-color: var(--l1-border);
border: 1px solid var(--l1-border);
border-radius: 4px;
box-shadow: 0px 4px 12px rgba(0, 0, 0, 0.1);
}

View File

@@ -1,7 +1,7 @@
.add-trace-operator-button,
.add-new-query-button,
.add-formula-button {
border: 1px solid var(--query-builder-v2-border-color, var(--l2-border));
background: var(--query-builder-v2-background-color, var(--l2-background));
border: 1px solid var(--l1-border);
background: var(--l2-background);
box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1);
}

View File

@@ -40,14 +40,11 @@ $max-recents-shown: 5;
.query-status-container {
width: 32px;
background-color: var(
--query-builder-v2-background-color,
var(--l2-background)
) !important;
background-color: var(--l1-background) !important;
display: flex;
justify-content: center;
align-items: center;
border: 1px solid var(--query-builder-v2-border-color, var(--l2-border));
border: 1px solid var(--l1-border);
border-radius: 2px;
border-top-left-radius: 0px !important;
border-bottom-left-radius: 0px !important;
@@ -86,16 +83,16 @@ $max-recents-shown: 5;
.cm-content {
border-radius: 2px;
border: 1px solid var(--query-builder-v2-border-color, var(--l2-border));
border: 1px solid var(--l1-border);
padding: 0px !important;
&:focus-within {
border-color: var(--query-builder-v2-border-color, var(--l2-border));
border-color: var(--l1-border);
}
}
&.cm-focused {
outline: 1px solid var(--query-builder-v2-border-color, var(--l2-border));
outline: 1px solid var(--l1-border);
}
.cm-tooltip-autocomplete {
@@ -186,17 +183,11 @@ $max-recents-shown: 5;
font-family: 'Space Mono', monospace !important;
background-color: var(
--query-builder-v2-background-color,
var(--l2-background)
) !important;
color: var(--query-builder-v2-color, var(--l2-foreground)) !important;
background-color: var(--l1-background) !important;
color: var(--l2-foreground) !important;
&:hover {
background: var(
--query-builder-v2-selection-background-color,
var(--l3-background)
) !important;
background: var(--l3-background) !important;
}
.cm-completionIcon {
@@ -214,10 +205,7 @@ $max-recents-shown: 5;
}
&[aria-selected='true'] {
background: var(
--query-builder-v2-selection-background-color,
var(--l3-background)
) !important;
background: var(--l3-background) !important;
font-weight: 600 !important;
}
}
@@ -286,49 +274,25 @@ $max-recents-shown: 5;
}
.cm-line {
line-height: 36px !important;
line-height: 34px !important;
font-family: 'Space Mono', monospace !important;
background-color: var(
--query-builder-v2-background-color,
var(--l2-background)
) !important;
&,
.ͼ1a {
color: var(--query-builder-v2-color, var(--l2-foreground));
}
background-color: var(--l2-background) !important;
::-moz-selection {
background: var(
--query-builder-v2-selection-background-color,
var(--l3-background)
) !important;
background: var(--l3-background) !important;
opacity: 0.5 !important;
}
::selection {
background: var(
--query-builder-v2-selection-background-color,
var(--l3-background)
) !important;
background: var(--l3-background) !important;
opacity: 0.5 !important;
}
}
.cm-selectionBackground {
background: var(
--query-builder-v2-selection-background-color,
var(--l3-background)
) !important;
background: var(--l3-background) !important;
opacity: 0.5 !important;
}
.cm-placeholder {
color: var(
--query-builder-v2-placeholder-color,
var(--l3-foreground)
) !important;
}
}
.cursor-position {

View File

@@ -65,14 +65,6 @@
display: flex;
flex-direction: column;
gap: 8px;
// Meant to fix the query builder colors
--input-background: var(--l2-background);
--input-hover-background: var(--l2-background);
--input-focus-background: var(--l2-background);
--input-border-color: var(--l2-border);
--input-hover-border-color: var(--internal-ant-border-color-hover);
--input-focus-border-color: var(--internal-ant-border-color-hover);
}
&-aggregation-container {

View File

@@ -177,7 +177,13 @@ export default function ConversationView({
conversationId={conversationId}
messages={messages}
isStreaming={isStreamingHere}
onSendSuggestedPrompt={(text): void => handleSend(text)}
onSendSuggestedPrompt={(text): void => {
handleSend(
text,
undefined,
autoContexts.length > 0 ? autoContexts : undefined,
);
}}
/>
{showDisclaimer && (
<div className={disclaimerClass} role="note" aria-live="polite">

View File

@@ -0,0 +1,142 @@
import { MemoryRouter } from 'react-router-dom';
// eslint-disable-next-line no-restricted-imports
import { fireEvent, render } from '@testing-library/react';
import { MessageContext } from 'api/ai-assistant/chat';
import { useAIAssistantStore } from 'container/AIAssistant/store/useAIAssistantStore';
import { VariantContext } from 'container/AIAssistant/VariantContext';
const CHIP_ID = 'recent-errors';
const CHIP_TEXT = 'Show me recent errors';
// Auto-derived page context that a normal (typed) send would attach. The chip
// send must forward the exact same array.
const mockAutoContexts: MessageContext[] = [
{
source: 'auto',
type: 'dashboard',
resourceId: 'dashboard-123',
resourceName: 'Checkout dashboard',
},
];
jest.mock('api/common/logEvent', () => ({
__esModule: true,
default: jest.fn(),
}));
jest.mock('container/AIAssistant/getAutoContexts', () => ({
getAutoContexts: jest.fn(() => mockAutoContexts),
}));
jest.mock('container/AIAssistant/hooks/useAIAssistantAnalyticsContext', () => ({
normalizePage: (page: string): string => page,
useAIAssistantAnalyticsContext: (): unknown => ({ threadId: 'thread-1' }),
}));
// ChatInput is heavy and irrelevant here — the chip path lives entirely in the
// empty state. Provide a lightweight stub plus the `autoContextKey` named export
// ConversationView imports for its dismissed-context filter.
jest.mock('container/AIAssistant/components/ChatInput', () => ({
__esModule: true,
default: (): JSX.Element => <div data-testid="chat-input" />,
autoContextKey: (): string => '',
}));
jest.mock('container/AIAssistant/components/ConversationSkeleton', () => ({
__esModule: true,
default: (): JSX.Element => <div data-testid="skeleton" />,
}));
// VirtualizedMessages renders the real empty-state chips; stub only its
// never-rendered-in-empty-state children and the virtual list.
jest.mock('components/Noz/Noz', () => ({
__esModule: true,
default: (): JSX.Element => <div data-testid="noz" />,
}));
jest.mock('container/AIAssistant/components/MessageBubble', () => ({
__esModule: true,
default: (): null => null,
}));
jest.mock('container/AIAssistant/components/StreamingMessage', () => ({
__esModule: true,
default: (): null => null,
}));
jest.mock('react-virtuoso', () => ({
__esModule: true,
Virtuoso: (): null => null,
}));
jest.mock(
'container/AIAssistant/components/VirtualizedMessages/useEmptyStateChips',
() => ({
useEmptyStateChips: (): { chips: { id: string; text: string }[] } => ({
chips: [{ id: CHIP_ID, text: CHIP_TEXT }],
}),
}),
);
// eslint-disable-next-line import/first
import ConversationView from '../ConversationView';
const CONVERSATION_ID = 'conv-1';
function renderView(variant: 'panel' | 'page' | 'modal'): {
getByTestId: (id: string) => HTMLElement;
} {
return render(
<MemoryRouter initialEntries={['/dashboard/dashboard-123']}>
<VariantContext.Provider value={variant}>
<ConversationView conversationId={CONVERSATION_ID} />
</VariantContext.Provider>
</MemoryRouter>,
);
}
describe('ConversationView — empty-state chip context', () => {
let sendMessage: jest.Mock;
beforeEach(() => {
jest.clearAllMocks();
sendMessage = jest.fn();
useAIAssistantStore.setState({
conversations: {
[CONVERSATION_ID]: {
id: CONVERSATION_ID,
messages: [],
createdAt: 1,
updatedAt: 1,
},
},
streams: {},
activeConversationId: CONVERSATION_ID,
isLoadingThread: false,
sendMessage,
} as unknown as Partial<ReturnType<typeof useAIAssistantStore.getState>>);
});
it('forwards the page auto-contexts when a chip is clicked (embedded variant)', () => {
const { getByTestId } = renderView('panel');
fireEvent.click(getByTestId(`empty-state-chip-${CHIP_ID}`));
// The chip send must carry the same auto-contexts a typed message would.
expect(sendMessage).toHaveBeenCalledTimes(1);
expect(sendMessage).toHaveBeenCalledWith(
CHIP_TEXT,
undefined,
mockAutoContexts,
);
});
it('sends undefined contexts on the standalone page (no page context to attach)', () => {
const { getByTestId } = renderView('page');
fireEvent.click(getByTestId(`empty-state-chip-${CHIP_ID}`));
expect(sendMessage).toHaveBeenCalledTimes(1);
expect(sendMessage).toHaveBeenCalledWith(CHIP_TEXT, undefined, undefined);
});
});

View File

@@ -53,26 +53,6 @@
}
.alert-query-section-container {
--query-builder-v2-color: var(--l2-foreground);
--query-builder-v2-background-color: var(--l3-background);
--query-builder-v2-border-color: var(--l3-border);
--query-builder-v2-selection-background-color: var(--l2-background);
--query-builder-v2-chip-decorator-background-color: var(--l2-background);
--query-builder-v2-placeholder-color: var(--l3-foreground);
--query-builder-v2-selected-background-color: var(--l3-foreground);
--query-search-background-color: var(--l3-background);
--query-search-background-color-selection: var(--l3-background);
--input-with-label-border-color: var(--l3-border);
--input-with-label-background-color: var(--l3-background);
--input-with-label-color: var(--l2-foreground);
--query-builder-v2-toggle-group-background-color: var(--l3-background);
--query-builder-v2-toggle-group-border-color: var(--l3-border);
--query-builder-v2-toggle-group-active-background-color: var(--l2-background);
--query-builder-v2-toggle-group-background-color-hover: var(--l3-background);
--input-height: 36px;
--input-hover-background: var(--l3-background);
--input-hover-border-color: var(--internal-ant-border-color-hover);
.ant-card-body {
padding: 0px;

View File

@@ -3,30 +3,6 @@
overflow-x: auto;
overflow-y: hidden;
--query-builder-v2-color: var(--l2-foreground);
--query-builder-v2-background-color: var(--l3-background);
--query-builder-v2-border-color: var(--l3-border);
--query-builder-v2-selection-background-color: var(--l2-background);
--query-builder-v2-chip-decorator-background-color: var(--l2-background);
--query-builder-v2-placeholder-color: var(--l3-foreground);
--query-builder-v2-selected-background-color: var(--l3-foreground);
--query-search-background-color: var(--l3-background);
--query-search-background-color-selection: var(--l3-background);
--input-with-label-border-color: var(--l3-border);
--input-with-label-background-color: var(--l3-background);
--input-with-label-color: var(--l2-foreground);
--query-builder-v2-toggle-group-background-color: var(--l3-background);
--query-builder-v2-toggle-group-border-color: var(--l3-border);
--query-builder-v2-toggle-group-active-background-color: var(--l2-background);
--query-builder-v2-toggle-group-background-color-hover: var(--l3-background);
--input-height: 36px;
--input-hover-background: var(--l3-background);
--input-hover-border-color: var(--internal-ant-border-color-hover);
--input-focus-border-color: var(--internal-ant-border-color-hover);
--input-background: var(--l3-background);
--input-focus-background: var(--l3-background);
--input-border-color: var(--l3-border);
.full-view-header-container {
display: flex;
flex-direction: column;

View File

@@ -1625,6 +1625,9 @@ export const getHostQueryPayload = (
const diskPendingKey = dotMetricsEnabled
? 'system.disk.pending_operations'
: 'system_disk_pending_operations';
const fsUsageKey = dotMetricsEnabled
? 'system.filesystem.usage'
: 'system_filesystem_usage';
return [
{
@@ -2657,6 +2660,155 @@ export const getHostQueryPayload = (
start,
end,
},
{
selectedTime: 'GLOBAL_TIME',
graphType: PANEL_TYPES.TIME_SERIES,
query: {
builder: {
queryData: [
{
aggregateAttribute: {
dataType: DataTypes.Float64,
id: 'system_filesystem_usage--float64--Gauge--true',
key: fsUsageKey,
type: 'Gauge',
},
aggregateOperator: 'avg',
dataSource: DataSource.METRICS,
disabled: true,
expression: 'A',
filters: {
items: [
{
id: 'fs_f1',
key: {
dataType: DataTypes.String,
id: 'host_name--string--tag--false',
key: hostNameKey,
type: 'tag',
},
op: '=',
value: hostName,
},
{
id: 'fs_f2',
key: {
dataType: DataTypes.String,
id: 'state--string--tag--false',
key: 'state',
type: 'tag',
},
op: '=',
value: 'used',
},
],
op: 'AND',
},
functions: [],
groupBy: [
{
dataType: DataTypes.String,
id: 'mountpoint--string--tag--false',
key: 'mountpoint',
type: 'tag',
},
],
having: [
{
columnName: `SUM(${fsUsageKey})`,
op: '>',
value: 0,
},
],
legend: '{{mountpoint}}',
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
},
{
aggregateAttribute: {
dataType: DataTypes.Float64,
id: 'system_filesystem_usage--float64--Gauge--true',
key: fsUsageKey,
type: 'Gauge',
},
aggregateOperator: 'avg',
dataSource: DataSource.METRICS,
disabled: true,
expression: 'B',
filters: {
items: [
{
id: 'fs_f3',
key: {
dataType: DataTypes.String,
id: 'host_name--string--tag--false',
key: hostNameKey,
type: 'tag',
},
op: '=',
value: hostName,
},
],
op: 'AND',
},
functions: [],
groupBy: [
{
dataType: DataTypes.String,
id: 'mountpoint--string--tag--false',
key: 'mountpoint',
type: 'tag',
},
],
having: [
{
columnName: `SUM(${fsUsageKey})`,
op: '>',
value: 0,
},
],
legend: '{{mountpoint}}',
limit: null,
orderBy: [],
queryName: 'B',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
},
],
queryFormulas: [
{
disabled: false,
expression: 'A/B',
legend: '{{mountpoint}}',
queryName: 'F1',
},
],
queryTraceOperator: [],
},
clickhouse_sql: [{ disabled: false, legend: '', name: 'A', query: '' }],
id: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890',
promql: [{ disabled: false, legend: '', name: 'A', query: '' }],
queryType: EQueryType.QUERY_BUILDER,
},
variables: {},
formatForWeb: false,
start,
end,
},
];
};
@@ -2732,4 +2884,5 @@ export const hostWidgetInfo = [
{ title: 'System disk operations/s', yAxisUnit: 'short' },
{ title: 'Queue size', yAxisUnit: 'short' },
{ title: 'System disk operation time/s', yAxisUnit: 's' },
{ title: 'Disk Usage (%) by mountpoint', yAxisUnit: 'percentunit' },
];

View File

@@ -14,14 +14,6 @@
.meter-explorer-content-section {
width: 100%;
// Meant to fix the query builder colors
--input-background: var(--l2-background);
--input-hover-background: var(--l2-background);
--input-focus-background: var(--l2-background);
--input-border-color: var(--l2-border);
--input-hover-border-color: var(--internal-ant-border-color-hover);
--input-focus-border-color: var(--internal-ant-border-color-hover);
.explore-header {
display: flex;
align-items: center;

View File

@@ -1,14 +1,6 @@
.metrics-explorer-explore-container {
padding-bottom: 80px;
// Meant to fix the query builder colors
--input-background: var(--l2-background);
--input-hover-background: var(--l2-background);
--input-focus-background: var(--l2-background);
--input-border-color: var(--l2-border);
--input-hover-border-color: var(--internal-ant-border-color-hover);
--input-focus-border-color: var(--internal-ant-border-color-hover);
.explore-header {
display: flex;
align-items: center;

View File

@@ -1,12 +1,4 @@
.dashboard-navigation {
// Meant to fix the query builder colors
--input-background: var(--l2-background);
--input-hover-background: var(--l2-background);
--input-focus-background: var(--l2-background);
--input-border-color: var(--l2-border);
--input-hover-border-color: var(--internal-ant-border-color-hover);
--input-focus-border-color: var(--internal-ant-border-color-hover);
.run-query-dashboard-btn {
min-width: 180px;
}

View File

@@ -20,6 +20,7 @@ import azureOpenaiUrl from '@/assets/Logos/azure-openai.svg';
import azureSqlDatabaseMetricsUrl from '@/assets/Logos/azure-sql-database-metrics.svg';
import azureVmUrl from '@/assets/Logos/azure-vm.svg';
import basetenUrl from '@/assets/Logos/baseten.svg';
import cassandraUrl from '@/assets/Logos/cassandra.svg';
import celeryUrl from '@/assets/Logos/celery.svg';
import certManagerUrl from '@/assets/Logos/cert-manager.svg';
import claudeCodeUrl from '@/assets/Logos/claude-code.svg';
@@ -51,6 +52,7 @@ import externalApiMonitoringUrl from '@/assets/Logos/external-api-monitoring.svg
import fluentbitUrl from '@/assets/Logos/fluentbit.svg';
import fluentdUrl from '@/assets/Logos/fluentd.svg';
import flutterMonitoringUrl from '@/assets/Logos/flutter-monitoring.svg';
import fluxcdUrl from '@/assets/Logos/fluxcd.svg';
import flyIoUrl from '@/assets/Logos/fly-io.svg';
import fromLogFileUrl from '@/assets/Logos/from-log-file.svg';
import gcpAppEngineUrl from '@/assets/Logos/gcp-app-engine.svg';
@@ -94,6 +96,7 @@ import langtraceUrl from '@/assets/Logos/langtrace.svg';
import litellmUrl from '@/assets/Logos/litellm.svg';
import livekitUrl from '@/assets/Logos/livekit.svg';
import llamaindexUrl from '@/assets/Logos/llamaindex.svg';
import llmMonitoringUrl from '@/assets/Logos/llm-monitoring.svg';
import logrusUrl from '@/assets/Logos/logrus.svg';
import logsUrl from '@/assets/Logos/logs.svg';
import logstashUrl from '@/assets/Logos/logstash.svg';
@@ -120,6 +123,7 @@ import opentelemetryUrl from '@/assets/Logos/opentelemetry.svg';
import phpUrl from '@/assets/Logos/php.svg';
import pinoUrl from '@/assets/Logos/pino.svg';
import pipecatUrl from '@/assets/Logos/pipecat.svg';
import planetscaleUrl from '@/assets/Logos/planetscale.svg';
import postgresqlUrl from '@/assets/Logos/postgresql.svg';
import prometheusUrl from '@/assets/Logos/prometheus.svg';
import pydanticAiUrl from '@/assets/Logos/pydantic-ai.svg';
@@ -1526,6 +1530,28 @@ const onboardingConfigWithLinks = [
id: 'nginx-tracing',
link: '/docs/instrumentation/opentelemetry-nginx/',
},
{
dataSource: 'nginx-ingress-controller',
label: 'NGINX Ingress Controller',
imgUrl: nginxUrl,
tags: ['infrastructure monitoring'],
module: 'metrics',
relatedSearchKeywords: [
'ingress',
'ingress controller',
'kubernetes ingress',
'monitoring',
'nginx ingress',
'nginx ingress controller',
'nginx ingress metrics',
'nginx ingress monitoring',
'nginx ingress observability',
'observability',
'opentelemetry nginx ingress',
],
id: 'nginx-ingress-controller',
link: '/docs/metrics-management/nginx-ingress-controller/',
},
{
dataSource: 'opentelemetry-cloudflare',
label: 'Cloudflare Tracing',
@@ -1586,6 +1612,119 @@ const onboardingConfigWithLinks = [
id: 'opentelemetry-cloudflare-logs',
link: '/docs/logs-management/send-logs/cloudflare-logs/',
},
{
dataSource: 'cloudflare-workers',
label: 'Cloudflare Workers',
imgUrl: cloudflareUrl,
tags: ['apm/traces'],
module: 'apm',
relatedSearchKeywords: [
'cloudflare',
'cloudflare workers',
'cloudflare workers monitoring',
'cloudflare workers observability',
'cloudflare workers otlp',
'edge computing monitoring',
'monitor cloudflare workers',
'monitoring',
'observability',
'opentelemetry cloudflare workers',
'otlp',
'serverless monitoring',
],
id: 'cloudflare-workers',
link: '/docs/integrations/outposts/cloudflare-workers/',
},
{
dataSource: 'opentelemetry-cassandra',
label: 'Cassandra',
imgUrl: cassandraUrl,
tags: ['database'],
module: 'apm',
relatedSearchKeywords: [
'apache cassandra',
'cassandra',
'cassandra database',
'cassandra logs',
'cassandra metrics',
'cassandra monitoring',
'cassandra observability',
'database',
'monitoring',
'nosql',
'observability',
'opentelemetry cassandra',
],
id: 'opentelemetry-cassandra',
link: '/docs/integrations/opentelemetry-cassandra/',
},
{
dataSource: 'fluxcd',
label: 'FluxCD',
imgUrl: fluxcdUrl,
tags: ['infrastructure monitoring'],
module: 'metrics',
relatedSearchKeywords: [
'continuous delivery',
'flux',
'fluxcd',
'fluxcd dashboard',
'fluxcd metrics',
'fluxcd monitoring',
'fluxcd observability',
'gitops',
'kubernetes',
'monitoring',
'observability',
'opentelemetry fluxcd',
],
id: 'fluxcd',
link: '/docs/metrics-management/fluxcd-metrics/',
},
{
dataSource: 'planetscale',
label: 'PlanetScale',
imgUrl: planetscaleUrl,
tags: ['database'],
module: 'apm',
relatedSearchKeywords: [
'database',
'monitoring',
'mysql',
'observability',
'opentelemetry planetscale',
'planetscale',
'planetscale database',
'planetscale metrics',
'planetscale monitoring',
'planetscale observability',
'serverless database',
],
id: 'planetscale',
link: '/docs/metrics-management/opentelemetry-planetscale/',
},
{
dataSource: 'hermes-agent',
label: 'Hermes Agent',
imgUrl: llmMonitoringUrl,
tags: ['LLM Monitoring'],
module: 'apm',
relatedSearchKeywords: [
'ai agent monitoring',
'hermes',
'hermes agent',
'hermes agent monitoring',
'hermes agent observability',
'hermes monitoring',
'llm monitoring',
'monitoring',
'nous research',
'observability',
'opentelemetry hermes',
],
id: 'hermes-agent',
link: '/docs/hermes-monitoring/',
},
{
dataSource: 'convex-logs',
label: 'Convex Logs',

View File

@@ -31,14 +31,8 @@
min-width: 32px;
border-radius: 2px;
--periscope-btn-border-color: var(
--query-builder-v2-border-color,
var(--l2-border)
);
--periscope-btn-background-color: var(
--query-builder-v2-background-color,
var(--l2-background)
);
border: 1px solid var(--l1-border);
background: var(--l2-background);
box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1);
}

View File

@@ -27,11 +27,8 @@
border-top-left-radius: 0px !important;
border-bottom-left-radius: 0px !important;
background-color: var(
--query-builder-v2-background-color,
var(--l2-background)
) !important;
margin-left: -1px;
background-color: var(--l1-border) !important;
opacity: 0.8;
&:disabled {
opacity: 0.4;
@@ -89,8 +86,8 @@
border-bottom-left-radius: 3px;
.ant-select-selector {
border: 1px solid var(--query-builder-v2-border-color, none);
background: var(--query-builder-v2-background-color, var(--l3-background));
border: none;
background: var(--l3-background);
}
&.showInput {
@@ -104,20 +101,12 @@
.query-function-value {
width: 70px;
border-left: 0;
background: var(--query-builder-v2-background-color, var(--l2-background));
background: var(--l2-background);
border-radius: 0;
border: 1px solid transparent;
border-top: 1px solid var(--query-builder-v2-border-color, var(--l2-border));
border-bottom: 1px solid
var(--query-builder-v2-border-color, var(--l2-border));
height: 32px;
&:focus {
border-color: var(--internal-ant-border-color-focus);
}
&:hover {
border-color: var(--internal-ant-border-color-hover);
border-color: transparent !important;
}
}
@@ -125,7 +114,7 @@
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
border-left: 1px solid var(--query-builder-v2-border-color, var(--l2-border));
border-left: 1px solid var(--l2-border);
border-top-left-radius: 0px !important;
border-bottom-left-radius: 0px !important;

View File

@@ -26,8 +26,8 @@ export default function AIAssistantPage(): JSX.Element {
// Skip the mount-time Opened fire when the user expanded an already-open
// drawer/modal — that surface already emitted Opened with the right source.
// Router state (vs a module flag) survives StrictMode double-mount and
// aborted navigations.
// Router state (vs a module flag) survives page remounts and aborted
// navigations.
const fromInApp = location.state?.fromInApp === true;
useEffect(() => {
if (fromInApp) {
@@ -52,18 +52,34 @@ export default function AIAssistantPage(): JSX.Element {
(s) => s.startNewConversation,
);
// Keep a ref so the effect can read latest conversations without re-firing
// when startNewConversation mutates the store mid-effect.
// Keep refs so the effect can read the latest store state without re-firing
// when it mutates the store mid-effect (it only depends on the URL param).
const conversationsRef = useRef(conversations);
conversationsRef.current = conversations;
const activeConversationIdRef = useRef(activeConversationId);
activeConversationIdRef.current = activeConversationId;
useEffect(() => {
if (conversationsRef.current[conversationId]) {
// URL points at a known conversation → just activate it.
if (conversationId && conversationsRef.current[conversationId]) {
setActiveConversation(conversationId);
} else {
const newId = startNewConversation();
history.replace(ROUTES.AI_ASSISTANT.replace(':conversationId', newId));
return;
}
// The URL has no usable conversation id (bare `/ai-assistant`, or a stale
// param). Prefer resuming the active conversation — including the
// rehydrating placeholder for the persisted thread — over minting a new
// one. This is what stops a throwaway blank chat from flashing as a
// second thread during load, and stops a duplicate when the page
// remounts during startup route churn (the active id is already set, so
// we resume instead of create). Starting fresh is the last resort, only
// when there is genuinely nothing to resume.
const activeId = activeConversationIdRef.current;
const resumeId =
activeId && conversationsRef.current[activeId]
? activeId
: startNewConversation();
history.replace(ROUTES.AI_ASSISTANT.replace(':conversationId', resumeId));
// Only re-run when the URL param changes, not when conversations mutates.
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [conversationId]);

View File

@@ -0,0 +1,181 @@
import { MemoryRouter, Route } from 'react-router-dom';
// eslint-disable-next-line no-restricted-imports
import { render } from '@testing-library/react';
import ROUTES from 'constants/routes';
import { useAIAssistantStore } from 'container/AIAssistant/store/useAIAssistantStore';
jest.mock('api/common/logEvent', () => ({
__esModule: true,
default: jest.fn(),
}));
jest.mock('container/AIAssistant/ConversationView', () => ({
__esModule: true,
default: (): JSX.Element => <div data-testid="conversation-view" />,
}));
jest.mock('container/AIAssistant/components/ConversationsList', () => ({
__esModule: true,
default: (): JSX.Element => <div data-testid="conversations-list" />,
}));
jest.mock('components/Noz/Noz', () => ({
__esModule: true,
default: (): JSX.Element => <div data-testid="noz" />,
}));
jest.mock('container/AIAssistant/hooks/useAIAssistantAnalyticsContext', () => ({
normalizePage: (page: string): string => page,
useAIAssistantAnalyticsContext: (): unknown => ({ mode: 'page' }),
}));
// eslint-disable-next-line import/first
import AIAssistantPage from '../AIAssistantPage';
function renderAt(entry: string): { unmount: () => void } {
return render(
<MemoryRouter initialEntries={[entry]}>
<Route
exact
path={[ROUTES.AI_ASSISTANT_BASE, ROUTES.AI_ASSISTANT]}
component={AIAssistantPage}
/>
</MemoryRouter>,
);
}
function renderAtBase(): { unmount: () => void } {
return renderAt(ROUTES.AI_ASSISTANT_BASE);
}
function conversationCount(): number {
return Object.keys(useAIAssistantStore.getState().conversations).length;
}
function conversationIds(): string[] {
return Object.keys(useAIAssistantStore.getState().conversations);
}
function activeId(): string | null {
return useAIAssistantStore.getState().activeConversationId;
}
describe('AIAssistantPage', () => {
beforeEach(() => {
useAIAssistantStore.setState({
conversations: {},
streams: {},
activeConversationId: null,
});
});
it('opens exactly one conversation when navigating to /ai-assistant', () => {
const { unmount } = renderAtBase();
expect(conversationCount()).toBe(1);
unmount();
});
it('does not stack a second conversation when the page remounts at the bare URL (route churn)', () => {
// First mount at `/ai-assistant` creates one blank conversation and
// redirects to `/ai-assistant/:id`.
const { unmount } = renderAtBase();
expect(conversationCount()).toBe(1);
const firstId = conversationIds()[0];
// Startup route-list churn unmounts and remounts the page while the URL
// is momentarily back at the bare `/ai-assistant`. This previously
// created a second blank conversation — now it reuses the first.
unmount();
const { unmount: unmount2 } = renderAtBase();
expect(conversationCount()).toBe(1);
// The surviving conversation is the original one, resumed — not a fresh mint.
expect(conversationIds()).toStrictEqual([firstId]);
expect(activeId()).toBe(firstId);
unmount2();
});
it('activates the conversation named in the URL without creating a new one', () => {
useAIAssistantStore.setState({
conversations: {
existing: {
id: 'existing',
messages: [],
createdAt: 1,
updatedAt: 1,
},
},
streams: {},
activeConversationId: null,
});
const { unmount } = renderAt(
ROUTES.AI_ASSISTANT.replace(':conversationId', 'existing'),
);
expect(conversationCount()).toBe(1);
expect(activeId()).toBe('existing');
unmount();
});
it('resumes the active conversation on /ai-assistant/new instead of minting a new one', () => {
// The sidenav only routes to `/ai-assistant/new` as a fallback, but if an
// active conversation exists the page must resume it rather than spawn a
// throwaway blank thread for the unknown "new" param.
useAIAssistantStore.setState({
conversations: {
active: {
id: 'active',
messages: [],
createdAt: 1,
updatedAt: 1,
},
},
streams: {},
activeConversationId: 'active',
});
const { unmount } = renderAt(
ROUTES.AI_ASSISTANT.replace(':conversationId', 'new'),
);
expect(conversationCount()).toBe(1);
expect(conversationIds()).toStrictEqual(['active']);
expect(activeId()).toBe('active');
unmount();
});
it('resumes the persisted (hydrating) conversation during load instead of creating a second', () => {
// Simulates `onRehydrateStorage` priming the persisted active
// conversation as a hydrating placeholder before `fetchThreads` resolves.
useAIAssistantStore.setState({
conversations: {
persisted: {
id: 'persisted',
messages: [],
createdAt: 1,
updatedAt: 1,
isHydrating: true,
},
},
streams: {},
activeConversationId: 'persisted',
});
const { unmount } = renderAtBase();
// Opening the bare URL must resume the persisted conversation, not mint a
// throwaway blank alongside it (which flashed as a 2nd thread during load).
expect(conversationCount()).toBe(1);
expect(
Object.keys(useAIAssistantStore.getState().conversations),
).toStrictEqual(['persisted']);
unmount();
});
});

View File

@@ -16,14 +16,6 @@
min-height: 0;
.log-explorer-query-container {
// Meant to fix the query builder colors
--input-background: var(--l2-background);
--input-hover-background: var(--l2-background);
--input-focus-background: var(--l2-background);
--input-border-color: var(--l2-border);
--input-hover-border-color: var(--internal-ant-border-color-hover);
--input-focus-border-color: var(--internal-ant-border-color-hover);
display: flex;
flex-direction: column;
flex: 1;

View File

@@ -67,14 +67,6 @@
.trace-explorer-page {
display: flex;
// Meant to fix the query builder colors
--input-background: var(--l2-background);
--input-hover-background: var(--l2-background);
--input-focus-background: var(--l2-background);
--input-border-color: var(--l2-border);
--input-hover-border-color: var(--internal-ant-border-color-hover);
--input-focus-border-color: var(--internal-ant-border-color-hover);
.filter {
width: 260px;
height: 100%;

View File

@@ -13,9 +13,9 @@
padding: 6px;
border: 1px solid var(--periscope-btn-border-color, var(--l1-border));
border: 1px solid var(--l1-border);
border-radius: 3px;
background: var(--periscope-btn-background-color, var(--l2-background));
background: var(--l2-background);
box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1);
color: var(--l2-foreground);
@@ -135,15 +135,11 @@
display: flex;
flex-direction: row;
border-radius: 2px 0px 0px 2px;
background-color: var(
--input-with-label-background-color,
var(--l2-background)
);
.label {
font-size: 12px;
color: var(--input-with-label-color, var(--l2-foreground));
color: var(--l2-foreground);
font-size: 12px;
font-style: normal;
font-weight: 500;
@@ -157,8 +153,9 @@
text-overflow: ellipsis;
padding: 0px 8px;
border-radius: 2px 0px 0px 2px;
border: 1px solid var(--input-with-label-border-color, var(--l2-border));
background: var(--input-with-label-background-color, var(--l2-background));
border: 1px solid var(--l2-border);
background: var(--l2-background);
color: var(--l1-foreground);
display: flex;
justify-content: flex-start;
align-items: center;
@@ -168,6 +165,7 @@
.input {
flex: 1;
border-radius: 0px 2px 2px 0px;
border: 1px solid var(--l1-border);
border-right: none;
border-left: none;
border-top-right-radius: 0px;
@@ -175,7 +173,7 @@
border-top-left-radius: 0px;
border-bottom-left-radius: 0px;
background: var(--input-with-label-background-color, var(--l2-background));
background: var(--l1-background);
min-width: 0;
@@ -191,44 +189,21 @@
}
.ant-select-selector {
height: 36px;
border-color: var(--input-with-label-border-color, var(--l2-border));
background: var(--input-with-label-background-color, var(--l2-background));
border-radius: 0;
position: relative;
margin-left: -1px;
}
.ant-select:hover .ant-select-selector,
.ant-select-focused .ant-select-selector {
z-index: 1;
}
.ant-select-disabled .ant-select-selector {
background: var(
--input-with-label-background-color,
var(--l2-background)
) !important;
border: none;
background: var(--l2-background);
}
.ant-select-selection-placeholder {
color: var(--input-with-label-color, var(--l2-foreground));
color: var(--l2-foreground);
}
}
.close-btn {
border-radius: 0px 2px 2px 0px;
border: 1px solid var(--input-with-label-border-color, var(--l2-border));
background: var(--input-with-label-background-color, var(--l2-background));
height: 100%;
border: 1px solid var(--l2-border);
background: var(--l2-background);
height: 38px;
width: 38px;
margin-left: -1px;
position: relative;
&:hover,
&:focus {
z-index: 2;
}
&:focus:not(:focus-visible),
&.ant-btn:focus:not(:focus-visible) {

View File

@@ -839,9 +839,6 @@ body.ai-assistant-panel-open {
// design libraries.
--dropdown-menu-content-z-index: 1050;
--dropdown-menu-sub-content-z-index: 1050;
--internal-ant-border-color-focus: #3a52a8;
--internal-ant-border-color-hover: #6e8de8;
}
div[data-slot='callout'] {

View File

@@ -29,7 +29,7 @@ type module struct {
}
func NewModule(store llmpricingruletypes.Store, flagger flagger.Flagger, querier querier.Querier) llmpricingrule.Module {
return &module{store: store, flagger: flagger}
return &module{store: store, flagger: flagger, querier: querier}
}
func (module *module) List(ctx context.Context, orgID valuer.UUID, offset, limit int, search string, isOverride *bool) ([]*llmpricingruletypes.LLMPricingRule, int, error) {