Skip to content

Commit

Permalink
fix(topology): nodes can be filtered by label/annotation (#1312)
Browse files Browse the repository at this point in the history
Signed-off-by: Andrew Azores <me@andrewazor.es>
Co-authored-by: Thuan Vo <thuan.votann@gmail.com>
  • Loading branch information
andrewazores and tthvo authored Jul 30, 2024
1 parent 953645f commit 9526cb5
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 12 deletions.
10 changes: 9 additions & 1 deletion src/app/Shared/Services/api.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { RecordingReplace } from '@app/CreateRecording/types';
import { AlertVariant } from '@patternfly/react-core';
import _ from 'lodash';
import { Observable } from 'rxjs';

export type ApiVersion = 'v1' | 'v2' | 'v2.1' | 'v2.2' | 'v2.3' | 'v2.4' | 'v3' | 'beta';
Expand All @@ -28,6 +28,14 @@ export interface KeyValue {
value: string;
}

export const isKeyValue = (o: any): o is KeyValue => {
return typeof o === 'object' && _.isEqual(new Set(['key', 'value']), new Set(Object.getOwnPropertyNames(o)));
};

export const keyValueToString = (kv: KeyValue): string => {
return `${kv.key}=${kv.value}`;
};

export interface Metadata {
labels: KeyValue[];
}
Expand Down
3 changes: 2 additions & 1 deletion src/app/Topology/Entity/EntityAnnotations.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { keyValueToString } from '@app/Shared/Services/api.types';
import { Label, LabelGroup } from '@patternfly/react-core';
import * as React from 'react';
import { EmptyText } from '../../Shared/Components/EmptyText';
Expand All @@ -27,7 +28,7 @@ export const EntityAnnotations: React.FC<{ annotations?: Annotations; maxDisplay
return annotations
? Object.keys(annotations).map((groupK) => ({
groupLabel: groupK,
annotations: annotations[groupK].map((kv) => `${kv.key}=${kv.value}`),
annotations: annotations[groupK].map((kv) => keyValueToString(kv)),
}))
: [];
}, [annotations]);
Expand Down
14 changes: 6 additions & 8 deletions src/app/Topology/Shared/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import { JmxAuthDescription } from '@app/Shared/Components/JmxAuthDescription';
import { JmxSslDescription } from '@app/Shared/Components/JmxSslDescription';
import { TopologyFilters } from '@app/Shared/Redux/Filters/TopologyFilterSlice';
import { NodeType, EnvironmentNode, TargetNode } from '@app/Shared/Services/api.types';
import { NodeType, EnvironmentNode, TargetNode, keyValueToString } from '@app/Shared/Services/api.types';
import { DEFAULT_EMPTY_UNIVERSE, isTargetNode } from '@app/Shared/Services/api.utils';
import {
Button,
Expand Down Expand Up @@ -110,8 +110,7 @@ export const isGroupNodeFiltered = (
matched = matched && filter.Name.includes(groupNode.name);
}
if (filter.Label && filter.Label.length) {
matched =
matched && Object.entries(groupNode.labels).filter(([k, v]) => filter.Label.includes(`${k}=${v}`)).length > 0;
matched = matched && groupNode.labels.some((kv) => filter.Label.includes(keyValueToString(kv)));
}
return matched;
};
Expand All @@ -131,16 +130,15 @@ export const isTargetNodeFiltered = ({ target }: TargetNode, filters?: TopologyF
matched = matched && target.jvmId !== undefined && filters.JvmId.includes(target.jvmId);
}
if (filters.Label && filters.Label.length) {
matched =
matched && Object.entries(target.labels || {}).filter(([k, v]) => filters.Label.includes(`${k}=${v}`)).length > 0;
matched = matched && target.labels.some((kv) => filters.Label.includes(keyValueToString(kv)));
}
if (filters.Annotation && filters.Annotation.length) {
const annotations = target.annotations;
matched =
matched &&
[...Object.entries(annotations?.cryostat || {}), ...Object.entries(annotations?.platform || {})].filter(
([k, v]) => filters.Annotation.includes(`${k}=${v}`),
).length > 0;
[...annotations?.cryostat, ...annotations?.platform].some((kv) =>
filters.Annotation.includes(keyValueToString(kv)),
);
}
return matched;
};
20 changes: 18 additions & 2 deletions src/app/Topology/Toolbar/TopologyFilters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {
topologyUpdateCategoryIntent,
topologyUpdateCategoryTypeIntent,
} from '@app/Shared/Redux/ReduxStore';
import { EnvironmentNode, TargetNode } from '@app/Shared/Services/api.types';
import { EnvironmentNode, TargetNode, isKeyValue, keyValueToString } from '@app/Shared/Services/api.types';
import { flattenTree, getUniqueNodeTypes, isTargetNode } from '@app/Shared/Services/api.utils';
import { getDisplayFieldName } from '@app/utils/utils';
import {
Expand Down Expand Up @@ -272,7 +272,10 @@ export const TopologyFilter: React.FC<{ isDisabled?: boolean }> = ({ isDisabled,
value={{
toString: () => opt,
compareTo: (other) => {
const regex = new RegExp(typeof other === 'string' ? other : other.value, 'i');
const regex = new RegExp(
typeof other === 'string' ? other : isKeyValue(other) ? keyValueToString(other) : `${other}`,
'i',
);
return regex.test(opt);
},
...{
Expand Down Expand Up @@ -349,6 +352,19 @@ export const fieldValueToStrings = (value: unknown): string[] => {
}
if (typeof value === 'object') {
if (Array.isArray(value)) {
if (value.length > 0 && typeof value[0] === 'object') {
if (isKeyValue(value[0])) {
return value.map(keyValueToString);
} else {
return value.map((o) => {
let str = '';
for (const p in Object.getOwnPropertyNames(o)) {
str += `${p}=${o[p]}`;
}
return str;
});
}
}
return value.map((v) => `${v}`);
} else {
return Object.entries(value as object).map(([k, v]) => `${k}=${v}`);
Expand Down

0 comments on commit 9526cb5

Please sign in to comment.