Skip to content

Commit bf73815

Browse files
committed
Automatically convert PromQL code blocks to QueryBrowser graphs
1 parent 283388a commit bf73815

5 files changed

Lines changed: 83 additions & 2 deletions

File tree

src/components/GeneralPage.tsx

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ import ImportAction from './ImportAction';
6464
import NewChatModal from './NewChatModal';
6565
import Prompt from './Prompt';
6666
import ReadinessAlert from './ReadinessAlert';
67+
import QueryBrowserGraph from './QueryBrowserGraph';
6768
import ResponseTools from './ResponseTools';
6869
import WelcomeNotice from './WelcomeNotice';
6970

@@ -94,7 +95,18 @@ const isURL = (s: string): boolean => {
9495
}
9596
};
9697

97-
const Code = ({ children }: { children?: React.ReactNode }) => {
98+
type CodeProps = {
99+
children?: React.ReactNode;
100+
className?: string;
101+
};
102+
103+
const Code: React.FC<CodeProps> = ({ children, className }) => {
104+
const isPromQL = className?.includes('language-promql');
105+
106+
if (isPromQL && children) {
107+
return <QueryBrowserGraph query={String(children).trim()} />;
108+
}
109+
98110
if (!children || !String(children).includes('\n')) {
99111
return <code>{children}</code>;
100112
}

src/components/Prompt.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import { FileCodeIcon, FileUploadIcon, InfoCircleIcon, TaskIcon } from '@pattern
2525

2626
import { AttachmentTypes, toOLSAttachment } from '../attachments';
2727
import { getApiUrl } from '../config';
28+
import { LLM_INSTRUCTIONS } from '../llm-instructions';
2829
import { getFetchErrorMessage } from '../error';
2930
import { getRequestInitWithAuthHeader } from '../hooks/useAuth';
3031
import { useBoolean } from '../hooks/useBoolean';
@@ -498,7 +499,7 @@ const Prompt: React.FC<PromptProps> = ({ scrollIntoView }) => {
498499
conversation_id: conversationID,
499500
// eslint-disable-next-line camelcase
500501
media_type: 'application/json',
501-
query,
502+
query: `${query}\n\n${LLM_INSTRUCTIONS}`,
502503
};
503504

504505
const streamResponse = async () => {
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import * as React from 'react';
2+
import { debounce } from 'lodash';
3+
import { QueryBrowser } from '@openshift-console/dynamic-plugin-sdk';
4+
import { Spinner, TextArea } from '@patternfly/react-core';
5+
6+
const QueryBrowserGraph: React.FC<{ query: string }> = ({ query: initialQuery }) => {
7+
const [inputValue, setInputValue] = React.useState('');
8+
const [query, setQuery] = React.useState(initialQuery);
9+
10+
const debouncedSetQuery = React.useMemo(
11+
() =>
12+
debounce((value: string) => {
13+
setQuery(value);
14+
}, 500),
15+
[],
16+
);
17+
18+
const effectiveQuery = inputValue || initialQuery;
19+
20+
React.useEffect(() => {
21+
debouncedSetQuery(effectiveQuery);
22+
}, [debouncedSetQuery, effectiveQuery]);
23+
24+
const onChange = React.useCallback(
25+
(_event: React.ChangeEvent<HTMLTextAreaElement>, value: string) => {
26+
setInputValue(value);
27+
},
28+
[],
29+
);
30+
31+
return (
32+
<>
33+
<React.Suspense fallback={<Spinner size="md" />}>
34+
<QueryBrowser queries={[query]} showStackedControl />
35+
</React.Suspense>
36+
<TextArea
37+
aria-label="PromQL query"
38+
autoResize
39+
className="ols-plugin__query-browser-input"
40+
onChange={onChange}
41+
resizeOrientation="vertical"
42+
rows={3}
43+
value={inputValue || initialQuery}
44+
/>
45+
</>
46+
);
47+
};
48+
49+
export default QueryBrowserGraph;

src/components/general-page.css

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,3 +124,9 @@
124124
max-width: 30rem;
125125
text-align: center;
126126
}
127+
128+
.ols-plugin__query-browser-input {
129+
font-size: var(--pf-t--global--font--size--body--sm);
130+
margin-bottom: var(--pf-t--global--spacer--lg);
131+
margin-top: -25px;
132+
}

src/llm-instructions.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
export const LLM_INSTRUCTIONS = `
2+
## Frontend rendering capabilities
3+
4+
The OpenShift Lightspeed console UI has special rendering capabilities for certain code block types. When appropriate, use these features to provide more helpful and visual responses, but only when they are more helpful than plain text or code examples.
5+
6+
### PromQL line graphs
7+
8+
The frontend can render Prometheus metrics as line graphs. Each \`\`\`promql code block in your response will automatically generate a corresponding line graph.
9+
10+
Only include PromQL when the user is explicitly asking for Prometheus metrics, monitoring data, alerts, or quantitative troubleshooting (for example: CPU/memory usage, rates, latency, error counts, “show me”, “how much”, “query”, or “graph”). For conceptual or definition questions that do not request metrics (for example: “what is a node?”), do not include PromQL.
11+
12+
When you include PromQL, use a \`\`\`promql code block. Each \`\`\`promql code block must contain exactly one PromQL query and must be valid PromQL that can be run as-is.
13+
`.trim();

0 commit comments

Comments
 (0)