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
@@ -0,0 +1,7 @@
import type { AnalysisAlert } from "../../variant-analysis/shared/analysis-result";
import type { ModeledMethod } from "../modeled-method";

export interface ModelAlerts {
model: ModeledMethod;
alerts: AnalysisAlert[];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import type { Meta, StoryFn } from "@storybook/react";

import { ModelAlertsResults as ModelAlertsResultsComponent } from "../../view/model-alerts/ModelAlertsResults";
import { createSinkModeledMethod } from "../../../test/factories/model-editor/modeled-method-factories";
import { createMockAnalysisAlert } from "../../../test/factories/variant-analysis/shared/analysis-alert";

export default {
title: "Model Alerts/Model Alerts Results",
component: ModelAlertsResultsComponent,
} as Meta<typeof ModelAlertsResultsComponent>;

const Template: StoryFn<typeof ModelAlertsResultsComponent> = (args) => (
<ModelAlertsResultsComponent {...args} />
);

export const ModelAlertsResults = Template.bind({});
ModelAlertsResults.args = {
modelAlerts: {
model: createSinkModeledMethod(),
alerts: [createMockAnalysisAlert()],
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { styled } from "styled-components";
import type { ModelAlerts } from "../../model-editor/model-alerts/model-alerts";
import { Codicon } from "../common";
import { useState } from "react";
import { VSCodeBadge } from "@vscode/webview-ui-toolkit/react";
import { formatDecimal } from "../../common/number";
import AnalysisAlertResult from "../variant-analysis/AnalysisAlertResult";
import { MethodName } from "../model-editor/MethodName";
import { ModelDetails } from "./ModelDetails";

// This will ensure that these icons have a className which we can use in the TitleContainer
const ExpandCollapseCodicon = styled(Codicon)``;

const TitleContainer = styled.button`
display: flex;
gap: 0.5em;
align-items: center;
width: 100%;

color: var(--vscode-editor-foreground);
background-color: transparent;
border: none;
cursor: pointer;

&:disabled {
cursor: default;

${ExpandCollapseCodicon} {
color: var(--vscode-disabledForeground);
}
}
`;

const ModelTypeText = styled.span`
font-size: 0.85em;
color: var(--vscode-descriptionForeground);
`;

const ModelDetailsContainer = styled.div`
padding-top: 10px;
`;

const AlertsContainer = styled.ul`
list-style-type: none;
margin: 1em 0 0;
padding: 0.5em 0 0 0;
`;

const Alert = styled.li`
margin-bottom: 1em;
background-color: var(--vscode-notifications-background);
`;

interface Props {
modelAlerts: ModelAlerts;
}

export const ModelAlertsResults = ({
modelAlerts,
}: Props): React.JSX.Element => {
const [isExpanded, setExpanded] = useState(true);
return (
<div>
<TitleContainer onClick={() => setExpanded(!isExpanded)}>
{isExpanded && (
<ExpandCollapseCodicon name="chevron-down" label="Collapse" />
)}
{!isExpanded && (
<ExpandCollapseCodicon name="chevron-right" label="Expand" />
)}
<VSCodeBadge>{formatDecimal(modelAlerts.alerts.length)}</VSCodeBadge>
<MethodName {...modelAlerts.model}></MethodName>
<ModelTypeText>{modelAlerts.model.type}</ModelTypeText>
</TitleContainer>
{isExpanded && (
<>
<ModelDetailsContainer>
<ModelDetails model={modelAlerts.model} />
</ModelDetailsContainer>
<AlertsContainer>
{modelAlerts.alerts.map((r, i) => (
<Alert key={i}>
<AnalysisAlertResult alert={r} />
</Alert>
))}
</AlertsContainer>
</>
)}
</div>
);
};
52 changes: 52 additions & 0 deletions extensions/ql-vscode/src/view/model-alerts/ModelDetails.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { styled } from "styled-components";
import {
modeledMethodSupportsInput,
modeledMethodSupportsKind,
modeledMethodSupportsOutput,
} from "../../model-editor/modeled-method";
import type { ModeledMethod } from "../../model-editor/modeled-method";

const DetailsContainer = styled.div`
display: flex;
`;

const Detail = styled.span`
display: flex;
margin-right: 30px;
`;

const Label = styled.span`
color: var(--vscode-descriptionForeground);
margin-right: 10px;
`;

const Value = styled.span``;

export const ModelDetails = ({ model }: { model: ModeledMethod }) => {
return (
<DetailsContainer>
<Detail>
<Label>Model type:</Label>
<Value>{model.type}</Value>
</Detail>
{modeledMethodSupportsInput(model) && (
<Detail>
<Label>Input:</Label>
<Value>{model.input}</Value>
</Detail>
)}
{modeledMethodSupportsOutput(model) && (
<Detail>
<Label>Output:</Label>
<Value>{model.output}</Value>
</Detail>
)}
{modeledMethodSupportsKind(model) && (
<Detail>
<Label>Kind:</Label>
<Value>{model.kind}</Value>
</Detail>
)}
</DetailsContainer>
);
};