Added filtering and sorting in the model alerts view (#3509)
This commit is contained in:
@@ -29,17 +29,22 @@ export function calculateModelAlerts(
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const [i, repoResult] of repoResults.entries()) {
|
for (const [i, repoResult] of repoResults.entries()) {
|
||||||
|
const results = repoResult.interpretedResults || [];
|
||||||
|
const repository = {
|
||||||
|
id: repoResult.repositoryId,
|
||||||
|
fullName: repoMap.get(repoResult.repositoryId) || "",
|
||||||
|
};
|
||||||
|
|
||||||
|
const alerts = results.map(() => {
|
||||||
|
return {
|
||||||
|
alert: createMockAlert(),
|
||||||
|
repository,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
modelAlerts.push({
|
modelAlerts.push({
|
||||||
model: createModeledMethod(i.toString()),
|
model: createModeledMethod(i.toString()),
|
||||||
alerts: [
|
alerts,
|
||||||
{
|
|
||||||
alert: createMockAlert(),
|
|
||||||
repository: {
|
|
||||||
id: repoResult.repositoryId,
|
|
||||||
fullName: repoMap.get(repoResult.repositoryId) || "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
import type { ModelAlerts } from "../model-alerts/model-alerts";
|
||||||
|
|
||||||
|
export enum SortKey {
|
||||||
|
Alphabetically = "alphabetically",
|
||||||
|
NumberOfResults = "numberOfResults",
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ModelAlertsFilterSortState = {
|
||||||
|
modelSearchValue: string;
|
||||||
|
repositorySearchValue: string;
|
||||||
|
sortKey: SortKey;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const defaultFilterSortState: ModelAlertsFilterSortState = {
|
||||||
|
modelSearchValue: "",
|
||||||
|
repositorySearchValue: "",
|
||||||
|
sortKey: SortKey.NumberOfResults,
|
||||||
|
};
|
||||||
|
|
||||||
|
export function filterAndSort(
|
||||||
|
modelAlerts: ModelAlerts[],
|
||||||
|
filterSortState: ModelAlertsFilterSortState,
|
||||||
|
): ModelAlerts[] {
|
||||||
|
if (!modelAlerts || modelAlerts.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return modelAlerts
|
||||||
|
.filter((item) => matchesFilter(item, filterSortState))
|
||||||
|
.sort((a, b) => {
|
||||||
|
switch (filterSortState.sortKey) {
|
||||||
|
case SortKey.Alphabetically:
|
||||||
|
return a.model.signature.localeCompare(b.model.signature);
|
||||||
|
case SortKey.NumberOfResults:
|
||||||
|
return (b.alerts.length || 0) - (a.alerts.length || 0);
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function matchesFilter(
|
||||||
|
item: ModelAlerts,
|
||||||
|
filterSortState: ModelAlertsFilterSortState | undefined,
|
||||||
|
): boolean {
|
||||||
|
if (!filterSortState) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
matchesRepository(item, filterSortState.repositorySearchValue) &&
|
||||||
|
matchesModel(item, filterSortState.modelSearchValue)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function matchesRepository(
|
||||||
|
item: ModelAlerts,
|
||||||
|
repositorySearchValue: string,
|
||||||
|
): boolean {
|
||||||
|
// We may want to only return alerts that have a repository match
|
||||||
|
// but for now just return true if the model has any alerts
|
||||||
|
// with a matching repo.
|
||||||
|
|
||||||
|
return item.alerts.some((alert) =>
|
||||||
|
alert.repository.fullName
|
||||||
|
.toLowerCase()
|
||||||
|
.includes(repositorySearchValue.toLowerCase()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function matchesModel(item: ModelAlerts, modelSearchValue: string): boolean {
|
||||||
|
return item.model.signature
|
||||||
|
.toLowerCase()
|
||||||
|
.includes(modelSearchValue.toLowerCase());
|
||||||
|
}
|
||||||
@@ -2,7 +2,9 @@ import type { Meta, StoryFn } from "@storybook/react";
|
|||||||
|
|
||||||
import { ModelAlerts as ModelAlertsComponent } from "../../view/model-alerts/ModelAlerts";
|
import { ModelAlerts as ModelAlertsComponent } from "../../view/model-alerts/ModelAlerts";
|
||||||
import { createMockVariantAnalysis } from "../../../test/factories/variant-analysis/shared/variant-analysis";
|
import { createMockVariantAnalysis } from "../../../test/factories/variant-analysis/shared/variant-analysis";
|
||||||
|
import { VariantAnalysisRepoStatus } from "../../variant-analysis/shared/variant-analysis";
|
||||||
import type { VariantAnalysisScannedRepositoryResult } from "../../variant-analysis/shared/variant-analysis";
|
import type { VariantAnalysisScannedRepositoryResult } from "../../variant-analysis/shared/variant-analysis";
|
||||||
|
import { createMockAnalysisAlert } from "../../../test/factories/variant-analysis/shared/analysis-alert";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
title: "Model Alerts/Model Alerts",
|
title: "Model Alerts/Model Alerts",
|
||||||
@@ -24,15 +26,79 @@ const variantAnalysis = createMockVariantAnalysis({
|
|||||||
path: "/path/to/model-pack-2",
|
path: "/path/to/model-pack-2",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
scannedRepos: [
|
||||||
|
{
|
||||||
|
repository: {
|
||||||
|
id: 1,
|
||||||
|
fullName: "org/repo1",
|
||||||
|
private: false,
|
||||||
|
stargazersCount: 100,
|
||||||
|
updatedAt: new Date().toISOString(),
|
||||||
|
},
|
||||||
|
analysisStatus: VariantAnalysisRepoStatus.InProgress,
|
||||||
|
resultCount: 0,
|
||||||
|
artifactSizeInBytes: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
repository: {
|
||||||
|
id: 2,
|
||||||
|
fullName: "org/repo2",
|
||||||
|
private: false,
|
||||||
|
stargazersCount: 100,
|
||||||
|
updatedAt: new Date().toISOString(),
|
||||||
|
},
|
||||||
|
analysisStatus: VariantAnalysisRepoStatus.Succeeded,
|
||||||
|
resultCount: 0,
|
||||||
|
artifactSizeInBytes: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
repository: {
|
||||||
|
id: 3,
|
||||||
|
fullName: "org/repo3",
|
||||||
|
private: false,
|
||||||
|
stargazersCount: 100,
|
||||||
|
updatedAt: new Date().toISOString(),
|
||||||
|
},
|
||||||
|
analysisStatus: VariantAnalysisRepoStatus.Succeeded,
|
||||||
|
resultCount: 1,
|
||||||
|
artifactSizeInBytes: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
repository: {
|
||||||
|
id: 4,
|
||||||
|
fullName: "org/repo4",
|
||||||
|
private: false,
|
||||||
|
stargazersCount: 100,
|
||||||
|
updatedAt: new Date().toISOString(),
|
||||||
|
},
|
||||||
|
analysisStatus: VariantAnalysisRepoStatus.Succeeded,
|
||||||
|
resultCount: 3,
|
||||||
|
artifactSizeInBytes: 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
const repoResults: VariantAnalysisScannedRepositoryResult[] = (
|
const repoResults: VariantAnalysisScannedRepositoryResult[] = [
|
||||||
variantAnalysis.scannedRepos || []
|
{
|
||||||
).map((repo) => ({
|
variantAnalysisId: variantAnalysis.id,
|
||||||
variantAnalysisId: variantAnalysis.id,
|
repositoryId: 2,
|
||||||
repositoryId: repo.repository.id,
|
interpretedResults: [createMockAnalysisAlert(), createMockAnalysisAlert()],
|
||||||
interpretedResults: [],
|
},
|
||||||
}));
|
{
|
||||||
|
variantAnalysisId: variantAnalysis.id,
|
||||||
|
repositoryId: 3,
|
||||||
|
interpretedResults: [
|
||||||
|
createMockAnalysisAlert(),
|
||||||
|
createMockAnalysisAlert(),
|
||||||
|
createMockAnalysisAlert(),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
variantAnalysisId: variantAnalysis.id,
|
||||||
|
repositoryId: 4,
|
||||||
|
interpretedResults: [createMockAnalysisAlert()],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
export const ModelAlerts = Template.bind({});
|
export const ModelAlerts = Template.bind({});
|
||||||
ModelAlerts.args = {
|
ModelAlerts.args = {
|
||||||
|
|||||||
@@ -11,6 +11,12 @@ import { vscode } from "../vscode-api";
|
|||||||
import { ModelAlertsResults } from "./ModelAlertsResults";
|
import { ModelAlertsResults } from "./ModelAlertsResults";
|
||||||
import type { ModelAlerts } from "../../model-editor/model-alerts/model-alerts";
|
import type { ModelAlerts } from "../../model-editor/model-alerts/model-alerts";
|
||||||
import { calculateModelAlerts } from "../../model-editor/model-alerts/alert-processor";
|
import { calculateModelAlerts } from "../../model-editor/model-alerts/alert-processor";
|
||||||
|
import { ModelAlertsSearchSortRow } from "./ModelAlertsSearchSortRow";
|
||||||
|
import {
|
||||||
|
defaultFilterSortState,
|
||||||
|
filterAndSort,
|
||||||
|
} from "../../model-editor/shared/model-alerts-filter-sort";
|
||||||
|
import type { ModelAlertsFilterSortState } from "../../model-editor/shared/model-alerts-filter-sort";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
initialViewState?: ModelAlertsViewState;
|
initialViewState?: ModelAlertsViewState;
|
||||||
@@ -53,6 +59,9 @@ export function ModelAlerts({
|
|||||||
const [repoResults, setRepoResults] =
|
const [repoResults, setRepoResults] =
|
||||||
useState<VariantAnalysisScannedRepositoryResult[]>(initialRepoResults);
|
useState<VariantAnalysisScannedRepositoryResult[]>(initialRepoResults);
|
||||||
|
|
||||||
|
const [filterSortValue, setFilterSortValue] =
|
||||||
|
useState<ModelAlertsFilterSortState>(defaultFilterSortState);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const listener = (evt: MessageEvent) => {
|
const listener = (evt: MessageEvent) => {
|
||||||
if (evt.origin === window.origin) {
|
if (evt.origin === window.origin) {
|
||||||
@@ -97,8 +106,10 @@ export function ModelAlerts({
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
return calculateModelAlerts(variantAnalysis, repoResults);
|
const modelAlerts = calculateModelAlerts(variantAnalysis, repoResults);
|
||||||
}, [variantAnalysis, repoResults]);
|
|
||||||
|
return filterAndSort(modelAlerts, filterSortValue);
|
||||||
|
}, [filterSortValue, variantAnalysis, repoResults]);
|
||||||
|
|
||||||
if (viewState === undefined || variantAnalysis === undefined) {
|
if (viewState === undefined || variantAnalysis === undefined) {
|
||||||
return <></>;
|
return <></>;
|
||||||
@@ -125,6 +136,10 @@ export function ModelAlerts({
|
|||||||
></ModelAlertsHeader>
|
></ModelAlertsHeader>
|
||||||
<div>
|
<div>
|
||||||
<SectionTitle>Model alerts</SectionTitle>
|
<SectionTitle>Model alerts</SectionTitle>
|
||||||
|
<ModelAlertsSearchSortRow
|
||||||
|
filterSortValue={filterSortValue}
|
||||||
|
onFilterSortChange={setFilterSortValue}
|
||||||
|
/>
|
||||||
<div>
|
<div>
|
||||||
{modelAlerts.map((alerts, i) => (
|
{modelAlerts.map((alerts, i) => (
|
||||||
// We're using the index as the key here which is not recommended.
|
// We're using the index as the key here which is not recommended.
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
import { useCallback } from "react";
|
||||||
|
import type { Dispatch, SetStateAction } from "react";
|
||||||
|
import { styled } from "styled-components";
|
||||||
|
import type {
|
||||||
|
ModelAlertsFilterSortState,
|
||||||
|
SortKey,
|
||||||
|
} from "../../model-editor/shared/model-alerts-filter-sort";
|
||||||
|
import { SearchBox } from "../common/SearchBox";
|
||||||
|
import { ModelAlertsSort } from "./ModelAlertsSort";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
filterSortValue: ModelAlertsFilterSortState;
|
||||||
|
onFilterSortChange: Dispatch<SetStateAction<ModelAlertsFilterSortState>>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Container = styled.div`
|
||||||
|
display: flex;
|
||||||
|
gap: 1em;
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const ModelsSearchColumn = styled(SearchBox)`
|
||||||
|
flex: 2;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const RepositoriesSearchColumn = styled(SearchBox)`
|
||||||
|
flex: 2;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const SortColumn = styled(ModelAlertsSort)`
|
||||||
|
flex: 1;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const ModelAlertsSearchSortRow = ({
|
||||||
|
filterSortValue,
|
||||||
|
onFilterSortChange,
|
||||||
|
}: Props) => {
|
||||||
|
const handleModelSearchValueChange = useCallback(
|
||||||
|
(searchValue: string) => {
|
||||||
|
onFilterSortChange((oldValue) => ({
|
||||||
|
...oldValue,
|
||||||
|
modelSearchValue: searchValue,
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
[onFilterSortChange],
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleRepositorySearchValueChange = useCallback(
|
||||||
|
(searchValue: string) => {
|
||||||
|
onFilterSortChange((oldValue) => ({
|
||||||
|
...oldValue,
|
||||||
|
repositorySearchValue: searchValue,
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
[onFilterSortChange],
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleSortKeyChange = useCallback(
|
||||||
|
(sortKey: SortKey) => {
|
||||||
|
onFilterSortChange((oldValue) => ({
|
||||||
|
...oldValue,
|
||||||
|
sortKey,
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
[onFilterSortChange],
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container>
|
||||||
|
<ModelsSearchColumn
|
||||||
|
placeholder="Filter by model"
|
||||||
|
value={filterSortValue.modelSearchValue}
|
||||||
|
onChange={handleModelSearchValueChange}
|
||||||
|
/>
|
||||||
|
<RepositoriesSearchColumn
|
||||||
|
placeholder="Filter by repository owner/name"
|
||||||
|
value={filterSortValue.repositorySearchValue}
|
||||||
|
onChange={handleRepositorySearchValueChange}
|
||||||
|
/>
|
||||||
|
<SortColumn
|
||||||
|
value={filterSortValue.sortKey}
|
||||||
|
onChange={handleSortKeyChange}
|
||||||
|
/>
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import { useCallback } from "react";
|
||||||
|
import { styled } from "styled-components";
|
||||||
|
import { VSCodeDropdown, VSCodeOption } from "@vscode/webview-ui-toolkit/react";
|
||||||
|
import { SortKey } from "../../model-editor/shared/model-alerts-filter-sort";
|
||||||
|
import { Codicon } from "../common";
|
||||||
|
|
||||||
|
const Dropdown = styled(VSCodeDropdown)`
|
||||||
|
width: 100%;
|
||||||
|
`;
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
value: SortKey;
|
||||||
|
onChange: (value: SortKey) => void;
|
||||||
|
|
||||||
|
className?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ModelAlertsSort = ({ value, onChange, className }: Props) => {
|
||||||
|
const handleInput = useCallback(
|
||||||
|
(e: InputEvent) => {
|
||||||
|
const target = e.target as HTMLSelectElement;
|
||||||
|
|
||||||
|
onChange(target.value as SortKey);
|
||||||
|
},
|
||||||
|
[onChange],
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dropdown value={value} onInput={handleInput} className={className}>
|
||||||
|
<Codicon name="sort-precedence" label="Sort..." slot="indicator" />
|
||||||
|
<VSCodeOption value={SortKey.Alphabetically}>Alphabetically</VSCodeOption>
|
||||||
|
<VSCodeOption value={SortKey.NumberOfResults}>
|
||||||
|
Number of results
|
||||||
|
</VSCodeOption>
|
||||||
|
</Dropdown>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,158 @@
|
|||||||
|
import type { ModelAlerts } from "../../../../src/model-editor/model-alerts/model-alerts";
|
||||||
|
import type { ModelAlertsFilterSortState } from "../../../../src/model-editor/shared/model-alerts-filter-sort";
|
||||||
|
import {
|
||||||
|
SortKey,
|
||||||
|
filterAndSort,
|
||||||
|
} from "../../../../src/model-editor/shared/model-alerts-filter-sort";
|
||||||
|
import { createSinkModeledMethod } from "../../../factories/model-editor/modeled-method-factories";
|
||||||
|
import { createMockAnalysisAlert } from "../../../factories/variant-analysis/shared/analysis-alert";
|
||||||
|
import { shuffle } from "../../../vscode-tests/utils/list-helpers";
|
||||||
|
|
||||||
|
describe("model alerts filter sort", () => {
|
||||||
|
const modelAlerts: ModelAlerts[] = [
|
||||||
|
{
|
||||||
|
model: createSinkModeledMethod({
|
||||||
|
signature: "foo.m1",
|
||||||
|
}),
|
||||||
|
alerts: [
|
||||||
|
{
|
||||||
|
alert: createMockAnalysisAlert(),
|
||||||
|
repository: {
|
||||||
|
id: 1,
|
||||||
|
fullName: "r1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
alert: createMockAnalysisAlert(),
|
||||||
|
repository: {
|
||||||
|
id: 2,
|
||||||
|
fullName: "r2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
alert: createMockAnalysisAlert(),
|
||||||
|
repository: {
|
||||||
|
id: 3,
|
||||||
|
fullName: "r3",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
alert: createMockAnalysisAlert(),
|
||||||
|
repository: {
|
||||||
|
id: 4,
|
||||||
|
fullName: "r4",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: createSinkModeledMethod({
|
||||||
|
signature: "foo.m2",
|
||||||
|
}),
|
||||||
|
alerts: [
|
||||||
|
{
|
||||||
|
alert: createMockAnalysisAlert(),
|
||||||
|
repository: {
|
||||||
|
id: 1,
|
||||||
|
fullName: "r1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
alert: createMockAnalysisAlert(),
|
||||||
|
repository: {
|
||||||
|
id: 2,
|
||||||
|
fullName: "r2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: createSinkModeledMethod({
|
||||||
|
signature: "bar.m1",
|
||||||
|
}),
|
||||||
|
alerts: [
|
||||||
|
{
|
||||||
|
alert: createMockAnalysisAlert(),
|
||||||
|
repository: {
|
||||||
|
id: 1,
|
||||||
|
fullName: "r1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
it("should return an empty array if no model alerts", () => {
|
||||||
|
const filterSortState: ModelAlertsFilterSortState = {
|
||||||
|
modelSearchValue: "",
|
||||||
|
repositorySearchValue: "",
|
||||||
|
sortKey: SortKey.Alphabetically,
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = filterAndSort([], filterSortState);
|
||||||
|
|
||||||
|
expect(result).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should filter model alerts based on the model search value", () => {
|
||||||
|
const filterSortState: ModelAlertsFilterSortState = {
|
||||||
|
modelSearchValue: "m1",
|
||||||
|
repositorySearchValue: "",
|
||||||
|
sortKey: SortKey.Alphabetically,
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = filterAndSort(modelAlerts, filterSortState);
|
||||||
|
|
||||||
|
expect(result.includes(modelAlerts[0])).toBeTruthy();
|
||||||
|
expect(result.includes(modelAlerts[2])).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should filter model alerts based on the repository search value", () => {
|
||||||
|
const filterSortState: ModelAlertsFilterSortState = {
|
||||||
|
modelSearchValue: "",
|
||||||
|
repositorySearchValue: "r2",
|
||||||
|
sortKey: SortKey.Alphabetically,
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = filterAndSort(modelAlerts, filterSortState);
|
||||||
|
|
||||||
|
expect(result.includes(modelAlerts[0])).toBeTruthy();
|
||||||
|
expect(result.includes(modelAlerts[1])).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should sort model alerts alphabetically", () => {
|
||||||
|
const filterSortState: ModelAlertsFilterSortState = {
|
||||||
|
modelSearchValue: "",
|
||||||
|
repositorySearchValue: "",
|
||||||
|
sortKey: SortKey.Alphabetically,
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = filterAndSort(shuffle([...modelAlerts]), filterSortState);
|
||||||
|
|
||||||
|
expect(result).toEqual([modelAlerts[2], modelAlerts[0], modelAlerts[1]]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should sort model alerts by number of results", () => {
|
||||||
|
const filterSortState: ModelAlertsFilterSortState = {
|
||||||
|
modelSearchValue: "",
|
||||||
|
repositorySearchValue: "",
|
||||||
|
sortKey: SortKey.NumberOfResults,
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = filterAndSort(shuffle([...modelAlerts]), filterSortState);
|
||||||
|
|
||||||
|
expect(result).toEqual([modelAlerts[0], modelAlerts[1], modelAlerts[2]]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should filter and sort model alerts", () => {
|
||||||
|
const filterSortState: ModelAlertsFilterSortState = {
|
||||||
|
modelSearchValue: "m1",
|
||||||
|
repositorySearchValue: "r1",
|
||||||
|
sortKey: SortKey.NumberOfResults,
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = filterAndSort(shuffle([...modelAlerts]), filterSortState);
|
||||||
|
|
||||||
|
expect(result).toEqual([modelAlerts[0], modelAlerts[2]]);
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user