Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,22 @@ export function calculateModelAlerts(
}

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({
model: createModeledMethod(i.toString()),
alerts: [
{
alert: createMockAlert(),
repository: {
id: repoResult.repositoryId,
fullName: repoMap.get(repoResult.repositoryId) || "",
},
},
],
alerts,
});
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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());
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import type { Meta, StoryFn } from "@storybook/react";

import { ModelAlerts as ModelAlertsComponent } from "../../view/model-alerts/ModelAlerts";
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 { createMockAnalysisAlert } from "../../../test/factories/variant-analysis/shared/analysis-alert";

export default {
title: "Model Alerts/Model Alerts",
Expand All @@ -24,15 +26,79 @@ const variantAnalysis = createMockVariantAnalysis({
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[] = (
variantAnalysis.scannedRepos || []
).map((repo) => ({
variantAnalysisId: variantAnalysis.id,
repositoryId: repo.repository.id,
interpretedResults: [],
}));
const repoResults: VariantAnalysisScannedRepositoryResult[] = [
{
variantAnalysisId: variantAnalysis.id,
repositoryId: 2,
interpretedResults: [createMockAnalysisAlert(), createMockAnalysisAlert()],
},
{
variantAnalysisId: variantAnalysis.id,
repositoryId: 3,
interpretedResults: [
createMockAnalysisAlert(),
createMockAnalysisAlert(),
createMockAnalysisAlert(),
],
},
{
variantAnalysisId: variantAnalysis.id,
repositoryId: 4,
interpretedResults: [createMockAnalysisAlert()],
},
];

export const ModelAlerts = Template.bind({});
ModelAlerts.args = {
Expand Down
19 changes: 17 additions & 2 deletions extensions/ql-vscode/src/view/model-alerts/ModelAlerts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ import { vscode } from "../vscode-api";
import { ModelAlertsResults } from "./ModelAlertsResults";
import type { ModelAlerts } from "../../model-editor/model-alerts/model-alerts";
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 = {
initialViewState?: ModelAlertsViewState;
Expand Down Expand Up @@ -53,6 +59,9 @@ export function ModelAlerts({
const [repoResults, setRepoResults] =
useState<VariantAnalysisScannedRepositoryResult[]>(initialRepoResults);

const [filterSortValue, setFilterSortValue] =
useState<ModelAlertsFilterSortState>(defaultFilterSortState);

useEffect(() => {
const listener = (evt: MessageEvent) => {
if (evt.origin === window.origin) {
Expand Down Expand Up @@ -97,8 +106,10 @@ export function ModelAlerts({
return [];
}

return calculateModelAlerts(variantAnalysis, repoResults);
}, [variantAnalysis, repoResults]);
const modelAlerts = calculateModelAlerts(variantAnalysis, repoResults);

return filterAndSort(modelAlerts, filterSortValue);
}, [filterSortValue, variantAnalysis, repoResults]);

if (viewState === undefined || variantAnalysis === undefined) {
return <></>;
Expand All @@ -125,6 +136,10 @@ export function ModelAlerts({
></ModelAlertsHeader>
<div>
<SectionTitle>Model alerts</SectionTitle>
<ModelAlertsSearchSortRow
filterSortValue={filterSortValue}
onFilterSortChange={setFilterSortValue}
/>
<div>
{modelAlerts.map((alerts, i) => (
// We're using the index as the key here which is not recommended.
Expand Down
Original file line number Diff line number Diff line change
@@ -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>
);
};
37 changes: 37 additions & 0 deletions extensions/ql-vscode/src/view/model-alerts/ModelAlertsSort.tsx
Original file line number Diff line number Diff line change
@@ -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>
);
};
Loading