Convert dropdown to a full component

This commit is contained in:
Robert
2023-07-06 11:20:48 +01:00
parent d5c4f33d6e
commit 903e8c6688
3 changed files with 96 additions and 63 deletions

View File

@@ -1,16 +1,8 @@
import * as React from "react";
import { ChangeEvent } from "react";
import styled from "styled-components";
/**
* Styled to look like a `VSCodeDropdown`.
*
* The reason for doing this is that `VSCodeDropdown` doesn't handle fitting into
* available space and truncating content, and this leads to breaking the
* `VSCodeDataGrid` layout. This version using `select` directly will truncate the
* content as necessary and fit into whatever space is available.
* See https://github.com/github/vscode-codeql/pull/2582#issuecomment-1622164429
* for more info on the problem and other potential solutions.
*/
export const Dropdown = styled.select`
const StyledDropdown = styled.select`
width: 100%;
height: calc(var(--input-height) * 1px);
background: var(--dropdown-background);
@@ -19,3 +11,40 @@ export const Dropdown = styled.select`
border: none;
padding: 2px 6px 2px 8px;
`;
type Props = {
value: string | undefined;
options: Array<{ value: string; label: string }>;
disabled?: boolean;
onChange: (event: ChangeEvent<HTMLSelectElement>) => void;
};
/**
* A dropdown implementation styled to look like `VSCodeDropdown`.
*
* The reason for doing this is that `VSCodeDropdown` doesn't handle fitting into
* available space and truncating content, and this leads to breaking the
* `VSCodeDataGrid` layout. This version using `select` directly will truncate the
* content as necessary and fit into whatever space is available.
* See https://github.com/github/vscode-codeql/pull/2582#issuecomment-1622164429
* for more info on the problem and other potential solutions.
*/
export function Dropdown({ value, options, disabled, onChange }: Props) {
return (
<StyledDropdown
value={disabled ? undefined : value}
disabled={disabled}
onChange={onChange}
>
{!disabled && (
<>
{options.map((option) => (
<option key={option.value} value={option.value}>
{option.label}
</option>
))}
</>
)}
</StyledDropdown>
);
}

View File

@@ -1,5 +1,5 @@
import * as React from "react";
import { ChangeEvent, useCallback, useEffect } from "react";
import { ChangeEvent, useCallback, useEffect, useMemo } from "react";
import type { ModeledMethod } from "../../data-extensions-editor/modeled-method";
import { Dropdown } from "../common/Dropdown";
@@ -13,6 +13,11 @@ type Props = {
};
export const KindInput = ({ kinds, value, disabled, onChange }: Props) => {
const options = useMemo(
() => kinds.map((kind) => ({ value: kind, label: kind })),
[kinds],
);
const handleInput = useCallback(
(e: ChangeEvent<HTMLSelectElement>) => {
const target = e.target as HTMLSelectElement;
@@ -33,16 +38,11 @@ export const KindInput = ({ kinds, value, disabled, onChange }: Props) => {
}, [value, kinds, onChange]);
return (
<Dropdown value={value} disabled={disabled} onChange={handleInput}>
{!disabled && (
<>
{kinds.map((kind) => (
<option key={kind} value={kind}>
{kind}
</option>
))}
</>
)}
</Dropdown>
<Dropdown
value={value}
options={options}
disabled={disabled}
onChange={handleInput}
/>
);
};

View File

@@ -141,10 +141,44 @@ export const MethodRow = ({
const showModelTypeCell =
!externalApiUsage.supported ||
(modeledMethod && modeledMethod?.type !== "none");
const modelTypeOptions = useMemo(
() => [
{ value: "none", label: "Unmodeled" },
{ value: "source", label: "Source" },
{ value: "sink", label: "Sink" },
{ value: "summary", label: "Flow summary" },
{ value: "neutral", label: "Neutral" },
],
[],
);
const showInputCell =
modeledMethod?.type && ["sink", "summary"].includes(modeledMethod?.type);
const inputOptions = useMemo(
() => [
{ value: "Argument[this]", label: "Argument[this]" },
...argumentsList.map((argument, index) => ({
value: `Argument[${index}]`,
label: `Argument[${index}]: ${argument}`,
})),
],
[argumentsList],
);
const showOutputCell =
modeledMethod?.type && ["source", "summary"].includes(modeledMethod?.type);
const outputOptions = useMemo(
() => [
{ value: "ReturnValue", label: "ReturnValue" },
{ value: "Argument[this]", label: "Argument[this]" },
...argumentsList.map((argument, index) => ({
value: `Argument[${index}]`,
label: `Argument[${index}]: ${argument}`,
})),
],
[argumentsList],
);
const showKindCell = predicate?.supportedKinds;
return (
@@ -165,62 +199,32 @@ export const MethodRow = ({
</ApiOrMethodCell>
<VSCodeDataGridCell gridColumn={2}>
<Dropdown
value={showModelTypeCell ? modeledMethod?.type ?? "none" : undefined}
value={modeledMethod?.type ?? "none"}
options={modelTypeOptions}
disabled={!showModelTypeCell}
onChange={handleTypeInput}
>
{showModelTypeCell && (
<>
<option value="none">Unmodeled</option>
<option value="source">Source</option>
<option value="sink">Sink</option>
<option value="summary">Flow summary</option>
<option value="neutral">Neutral</option>
</>
)}
</Dropdown>
/>
</VSCodeDataGridCell>
<VSCodeDataGridCell gridColumn={3}>
<Dropdown
value={showInputCell ? modeledMethod?.input : undefined}
value={modeledMethod?.input}
options={inputOptions}
disabled={!showInputCell}
onChange={handleInputInput}
>
{showInputCell && (
<>
<option value="Argument[this]">Argument[this]</option>
{argumentsList.map((argument, index) => (
<option key={argument} value={`Argument[${index}]`}>
Argument[{index}]: {argument}
</option>
))}
</>
)}
</Dropdown>
/>
</VSCodeDataGridCell>
<VSCodeDataGridCell gridColumn={4}>
<Dropdown
value={showOutputCell ? modeledMethod?.output : undefined}
value={modeledMethod?.output}
options={outputOptions}
disabled={!showOutputCell}
onChange={handleOutputInput}
>
{showOutputCell && (
<>
<option value="ReturnValue">ReturnValue</option>
<option value="Argument[this]">Argument[this]</option>
{argumentsList.map((argument, index) => (
<option key={argument} value={`Argument[${index}]`}>
Argument[{index}]: {argument}
</option>
))}
</>
)}
</Dropdown>
/>
</VSCodeDataGridCell>
<VSCodeDataGridCell gridColumn={5}>
<KindInput
kinds={predicate?.supportedKinds || []}
value={showKindCell && modeledMethod?.kind}
value={modeledMethod?.kind}
disabled={!showKindCell}
onChange={handleKindChange}
/>