Skip to content

Commit 33e076a

Browse files
Merge pull request #163 from alanconway/save-result
NO-JIRA: Persist query result
2 parents 5bef71e + 4100d64 commit 33e076a

15 files changed

Lines changed: 106 additions & 95 deletions

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ install-frontend-ci-clean: install-frontend-ci
1818
cd web && npm cache clean --force
1919

2020
.PHONY: build-frontend
21-
build-frontend:
21+
build-frontend: lint-frontend
2222
cd web && npm run i18n && npm run build
2323

2424
.PHONY: start-frontend

devspace.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ dev:
3131
sync:
3232
- path: ./web/dist:/opt/app-root/web/dist
3333
startContainer: true
34+
printLogs: true
3435
command: ["make"]
3536
args: ["start-devspace-backend"]
3637
# Inject a lightweight SSH server into the container (so your IDE can connect to the remote dev env)

web/locales/en/plugin__troubleshooting-panel-console-plugin.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
"Create a graph of correlated items from resources in the current view.": "Create a graph of correlated items from resources in the curret view.",
55
"Distance": "Distance",
66
"Find all paths to items of the specified goal class.": "Find all paths to items of the specified goal class.",
7-
"Find all related data that can be reached by following up to N correlation rules. Follows rules from the start to directly related data, then from there to indirectly related data, up to the disance you specify.": "Find all related data that can be reached by following up to N correlation rules. Follows rules from the start to directly related data, then from there to indirectly related data, up to the disance you specify.",
87
"Focus": "Focus",
8+
"Follows correlation rules from the starting point to find related data, then continues the search from that data, up to the number of steps you specify.": "Follows correlation rules from the starting point to find related data, then continues the search from that data, up to the number of steps you specify.",
99
"Goal Class": "Goal Class",
1010
"Korrel8r Error": "Korrel8r Error",
1111
"Logging Plugin Disabled": "Logging Plugin Disabled",
@@ -28,4 +28,4 @@
2828
"Troubleshooting": "Troubleshooting",
2929
"Troubleshooting Panel": "Troubleshooting Panel",
3030
"Unable to find Console Link": "Unable to find Console Link"
31-
}
31+
}

web/src/__tests__/alert.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ describe('AlertNode.fromURL', () => {
99
'container=bad-deployment&endpoint=https-main&job=kube-state-metrics&namespace=default&pod=bad-deployment&' +
1010
'reason=CrashLoopBackOff&service=kube-state-metrics&uid=00000000-0000-0000-0000-000000000000',
1111
query:
12-
'alert:alert:{"prometheus":"openshift-monitoring/k8s","severity":"warning","alertname":"KubePodCrashLooping","container":"bad-deployment",' +
12+
'alert:alert:{"severity":"warning","alertname":"KubePodCrashLooping","container":"bad-deployment",' +
1313
'"endpoint":"https-main","job":"kube-state-metrics","namespace":"default","pod":"bad-deployment",' +
1414
'"reason":"CrashLoopBackOff","service":"kube-state-metrics","uid":"00000000-0000-0000-0000-000000000000"}',
1515
},

web/src/__tests__/all-domains.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ it.each([
2929
},
3030
},
3131
{
32-
url: 'k8s/ns/default/pods/bad-deployment-000000000-00000',
32+
url: 'k8s/ns/default/core~v1~Pod/bad-deployment-000000000-00000',
3333
query: 'k8s:Pod.v1:{"namespace":"default","name":"bad-deployment-000000000-00000"}',
3434
constraint: {
3535
start: null,

web/src/__tests__/k8s.spec.ts

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -77,16 +77,19 @@ describe('K8sNode.fromURL', () => {
7777
query: 'k8s:Deployment.v1.apps:{"namespace":"korrel8r","name":"korrel8r"}',
7878
},
7979
{
80-
url: 'k8s/ns/default/pods/bad-deployment-000000000-00000',
80+
url: 'k8s/ns/default/core~v1~Pod/bad-deployment-000000000-00000',
8181
query: 'k8s:Pod.v1:{"namespace":"default","name":"bad-deployment-000000000-00000"}',
8282
},
8383
{
84-
url: 'k8s/ns/default/pods/bad-deployment-000000000-00000/events',
84+
url: 'k8s/ns/default/core~v1~Pod/bad-deployment-000000000-00000/events',
8585
query:
8686
'k8s:Event.v1:{"fields":{"involvedObject.namespace":"default","involvedObject.name":"bad-deployment-000000000-00000","involvedObject.apiVersion":"v1","involvedObject.kind":"Pod"}}',
8787
},
88-
{ url: `/k8s/ns/default/pods/foo`, query: `k8s:Pod.v1:{"namespace":"default","name":"foo"}` },
89-
{ url: `/k8s/ns/default/pods`, query: `k8s:Pod.v1:{"namespace":"default"}` },
88+
{
89+
url: `/k8s/ns/default/core~v1~Pod/foo`,
90+
query: `k8s:Pod.v1:{"namespace":"default","name":"foo"}`,
91+
},
92+
{ url: `/k8s/ns/default/core~v1~Pod`, query: `k8s:Pod.v1:{"namespace":"default"}` },
9093
{ url: `/k8s/cluster/projects/foo`, query: `k8s:Namespace.v1:{"name":"foo"}` },
9194
{
9295
url: `/k8s/ns/x/operators.coreos.com~v1alpha1~ClusterServiceVersion/y`,
@@ -107,44 +110,44 @@ describe('K8sNode.fromQuery', () => {
107110
// Note "fields" are ignored.
108111
{
109112
query: 'k8s:Pod.v1:{"namespace":"default","name":"bad-deployment-000000000-00000"}',
110-
url: 'k8s/ns/default/pods/bad-deployment-000000000-00000',
113+
url: 'k8s/ns/default/core~v1~Pod/bad-deployment-000000000-00000',
111114
},
112115
{
113116
query: `k8s:Pod:{"namespace":"x","name":"y","labels":{"a":"b","c":"d"},"fields": {"x":"y"}}`,
114-
url: `k8s/ns/x/pods/y?labels=${encodeURIComponent('a=b,c=d')}&fields=${encodeURIComponent(
115-
'x=y',
116-
)}`,
117+
url: `k8s/ns/x/core~v1~Pod/y?labels=${encodeURIComponent(
118+
'a=b,c=d',
119+
)}&fields=${encodeURIComponent('x=y')}`,
117120
},
118121
{
119122
query:
120123
'k8s:Event.v1:{"fields":{"involvedObject.namespace":"default","involvedObject.name":"bad-deployment-000000000-00000","involvedObject.apiVersion":"v1","involvedObject.kind":"Pod"}}',
121-
url: 'k8s/ns/default/pods/bad-deployment-000000000-00000/events',
124+
url: 'k8s/ns/default/core~v1~Pod/bad-deployment-000000000-00000/events',
122125
},
123126
{
124127
query: `k8s:Pod:{ "namespace":"x", "name":"y", "labels":{ "a":"b" } }`,
125-
url: `k8s/ns/x/pods/y?labels=${encodeURIComponent('a=b')}`,
128+
url: `k8s/ns/x/core~v1~Pod/y?labels=${encodeURIComponent('a=b')}`,
126129
},
127130
{
128131
query: `k8s:Pod:{ "namespace":"x", "labels":{ "a":"b" } }`,
129-
url: `k8s/ns/x/pods?labels=${encodeURIComponent('a=b')}`,
132+
url: `k8s/ns/x/core~v1~Pod?labels=${encodeURIComponent('a=b')}`,
130133
},
131-
{ query: `k8s:Pod.v1:{ "namespace":"x", "name":"y" }`, url: `k8s/ns/x/pods/y` },
132-
{ query: `k8s:Pod.v1:{ "namespace":"x" }`, url: `k8s/ns/x/pods` },
134+
{ query: `k8s:Pod.v1:{ "namespace":"x", "name":"y" }`, url: `k8s/ns/x/core~v1~Pod/y` },
135+
{ query: `k8s:Pod.v1:{ "namespace":"x" }`, url: `k8s/ns/x/core~v1~Pod` },
133136
{
134137
query: `k8s:Pod.v1:{ "labels":{ "a":"b" } }`,
135138
url: `search/all-namespaces?labels=${encodeURIComponent('a=b')}&kind=core~v1~Pod`,
136139
},
137140
{
138141
query: `k8s:Pod.v1:{"namespace":"x","labels":{"a":"b"}}`,
139-
url: `k8s/ns/x/pods?labels=${encodeURIComponent('a=b')}`,
142+
url: `k8s/ns/x/core~v1~Pod?labels=${encodeURIComponent('a=b')}`,
140143
},
141144

142145
// Variations on korrel8r class spec.
143146
{
144147
query: `k8s:Role.v1.rbac.authorization.k8s.io:{ "namespace":"x", "name":"y" }`,
145-
url: `k8s/ns/x/roles/y`,
148+
url: `k8s/ns/x/rbac.authorization.k8s.io~v1~Role/y`,
146149
},
147-
{ query: `k8s:Pod:{}`, url: 'k8s/all-namespaces/pods' },
150+
{ query: `k8s:Pod:{}`, url: 'k8s/all-namespaces/core~v1~Pod' },
148151
])('converts $query to $url', ({ url, query }) => {
149152
expect(k8s.queryToLink(Query.parse(query))).toEqual(new URIRef(url));
150153
});

web/src/components/Korrel8rPanel.tsx

Lines changed: 33 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,14 @@ import { AlertDomain } from '../korrel8r/alert';
2626
import { allDomains } from '../korrel8r/all-domains';
2727
import * as api from '../korrel8r/client';
2828
import * as korrel8r from '../korrel8r/types';
29-
import { defaultSearch, Search, SearchType, setPersistedSearch } from '../redux-actions';
29+
import {
30+
defaultSearch,
31+
Result,
32+
Search,
33+
SearchResult,
34+
SearchType,
35+
setPersistedSearch,
36+
} from '../redux-actions';
3037
import { State } from '../redux-reducers';
3138
import * as time from '../time';
3239
import { HelpPopover as FieldLevelHelp } from './HelpPopover';
@@ -36,18 +43,11 @@ import TimeRangeFormGroup from './TimeRangeFormGroup';
3643
import { Korrel8rTopology } from './topology/Korrel8rTopology';
3744
import { LoadingTopology } from './topology/LoadingTopology';
3845

39-
type Result = {
40-
graph?: korrel8r.Graph;
41-
message?: string;
42-
title?: string;
43-
isError?: boolean;
44-
};
45-
4646
export default function Korrel8rPanel() {
4747
const { t } = useTranslation('plugin__troubleshooting-panel-console-plugin');
48-
const persistedSearch = useSelector((state: State) => {
48+
const searchResult: SearchResult = useSelector((state: State) => {
4949
return state.plugins?.tp?.get('persistedSearch');
50-
}) as Search;
50+
});
5151
const dispatch = useDispatch();
5252

5353
// State
@@ -61,23 +61,19 @@ export default function Korrel8rPanel() {
6161
[alertIDs],
6262
);
6363
const locationQuery = useLocationQuery(domains);
64-
const [search, setSearch] = React.useState<Search>(
65-
persistedSearch?.queryStr
66-
? persistedSearch
67-
: ({
68-
...defaultSearch,
69-
queryStr: locationQuery?.toString(),
70-
constraint: persistedSearch?.constraint,
71-
} as Search),
72-
);
73-
const [result, setResult] = React.useState<Result | null>(null);
64+
const [search, setSearch] = React.useState<Search>({
65+
...defaultSearch, // Default search parameters.
66+
queryStr: locationQuery?.toString(), // Default query string.
67+
...searchResult?.search, // Use persisted search if available.
68+
});
69+
const [result, setResult] = React.useState<Result | null>(searchResult?.result ?? null);
7470
const [showQuery, setShowQuery] = React.useState(false);
7571

7672
const focusTip = t('Create a graph of correlated items from resources in the current view.');
7773
const cannotFocus = t('The current view does not support correlation.');
7874

7975
React.useEffect(() => {
80-
// Set result = null to trigger a reload, don't run the query till then.
76+
// Set result = null to trigger a new client request, don't run the query till then.
8177
if (result !== null) {
8278
return;
8379
}
@@ -86,7 +82,7 @@ export default function Korrel8rPanel() {
8682
return;
8783
}
8884
// eslint-disable-next-line no-console
89-
console.log('korrel8r search', search);
85+
console.debug('korrel8r search', search);
9086
const queryStr = search?.queryStr?.trim();
9187
const start: api.Start = {
9288
queries: queryStr ? [queryStr] : undefined,
@@ -99,17 +95,21 @@ export default function Korrel8rPanel() {
9995

10096
cancellableFetch
10197
.then((response: api.Graph) => {
102-
setResult({ graph: new korrel8r.Graph(response) });
103-
// Only set the persisted search upon a successful query. It would be a
104-
// poor feeling to create a query that fails, and then be forced to rerun it
105-
// when opening the panel later
106-
dispatch(setPersistedSearch(search));
98+
const result: Result = { graph: new korrel8r.Graph(response) };
99+
// eslint-disable-next-line no-console
100+
console.debug('korrel8r result', result);
101+
setResult(result);
102+
dispatch(setPersistedSearch({ search, result }));
107103
})
108104
.catch((e: api.ApiError) => {
109-
setResult({
105+
const result = {
110106
message: e.body?.error || e.message || 'Unknown Error',
111107
title: e?.body?.error ? t('Korrel8r Error') : t('Request Failed'),
112-
});
108+
};
109+
// eslint-disable-next-line no-console
110+
console.debug('korrel8r result', result);
111+
setResult(result);
112+
dispatch(setPersistedSearch({ search, result }));
113113
});
114114
return () => cancellableFetch.cancel();
115115
}, [result, t, dispatch, search, cannotFocus, locationQuery]);
@@ -159,8 +159,8 @@ export default function Korrel8rPanel() {
159159
runSearch({
160160
...defaultSearch,
161161
queryStr: locationQuery?.toString(),
162-
constraint: persistedSearch?.constraint,
163-
period: persistedSearch?.period,
162+
constraint: searchResult?.search?.constraint,
163+
period: searchResult?.search?.period,
164164
})
165165
}
166166
>
@@ -320,16 +320,6 @@ const TopologyInfoState: React.FC<TopologyInfoStateProps> = ({ titleText, text,
320320
);
321321
};
322322

323-
const applyBounds = (minValue: number, maxValue: number) => {
324-
return (val: number) => {
325-
if (!val || val < minValue) {
326-
return minValue;
327-
} else if (val > maxValue) {
328-
return maxValue;
329-
} else {
330-
return val;
331-
}
332-
};
323+
const applyBounds = (min: number, max: number) => {
324+
return (val: number) => Math.max(min, Math.min(val, max));
333325
};
334-
335-
// {/* FIXME Tooltips or popovers uniformly */}

web/src/components/topology/Korrel8rTopology.tsx

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,10 @@ const PADDING = 30;
9999
export const Korrel8rTopology: React.FC<{
100100
domains: korrel8r.Domains;
101101
graph: korrel8r.Graph;
102-
reFit?: boolean;
103102
loggingAvailable: boolean;
104103
netobserveAvailable: boolean;
105104
constraint: korrel8r.Constraint;
106-
}> = ({ domains, graph, reFit, loggingAvailable, netobserveAvailable, constraint }) => {
105+
}> = ({ domains, graph, loggingAvailable, netobserveAvailable, constraint }) => {
107106
const { t } = useTranslation('plugin__troubleshooting-panel-console-plugin');
108107
const navigate = useNavigate();
109108
const [selectedIds, setSelectedIds] = React.useState<string[]>([]);
@@ -153,7 +152,7 @@ export const Korrel8rTopology: React.FC<{
153152
if (!link) return;
154153
if (!link.startsWith('/')) link = '/' + link;
155154
// eslint-disable-next-line no-console
156-
console.log(
155+
console.debug(
157156
'korrel8r navigate',
158157
'\nquery',
159158
query,
@@ -254,8 +253,6 @@ export const Korrel8rTopology: React.FC<{
254253
return controller;
255254
}, [controller, selectionAction, componentFactory]);
256255

257-
if (reFit) controller2.getGraph().fit(PADDING);
258-
259256
return (
260257
<TopologyView
261258
controlBar={

web/src/components/topology/LoadingTopology.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import * as React from 'react';
21
import {
32
action,
43
BreadthFirstLayout,
@@ -18,6 +17,7 @@ import {
1817
VisualizationProvider,
1918
VisualizationSurface,
2019
} from '@patternfly/react-topology';
20+
import * as React from 'react';
2121

2222
const baselineComponentFactory: ComponentFactory = (kind: ModelKind, type: string) => {
2323
switch (type) {
@@ -75,6 +75,7 @@ export const LoadingTopology: React.FC = () => {
7575
resetViewCallback: action(() => {
7676
controller.getGraph().reset();
7777
controller.getGraph().layout();
78+
controller.getGraph().fit(30);
7879
}),
7980
legend: false,
8081
zoomInDisabled: true,

web/src/hooks/useTroubleshootingPanel.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { InfrastructureIcon } from '@patternfly/react-icons';
33
import * as React from 'react';
44
import { useTranslation } from 'react-i18next';
55
import { useDispatch } from 'react-redux';
6-
import { defaultSearch, openTP, setPersistedSearch } from '../redux-actions';
6+
import { openTP } from '../redux-actions';
77
import { useKorrel8r } from './useKorrel8r';
88

99
const useTroubleshootingPanel: ExtensionHook<Array<Action>> = () => {
@@ -12,7 +12,6 @@ const useTroubleshootingPanel: ExtensionHook<Array<Action>> = () => {
1212
const [perspective] = useActivePerspective();
1313
const dispatch = useDispatch();
1414
const open = React.useCallback(() => {
15-
dispatch(setPersistedSearch(defaultSearch));
1615
dispatch(openTP());
1716
}, [dispatch]);
1817

0 commit comments

Comments
 (0)