mirror of
https://github.com/Kong/insomnia
synced 2024-11-08 14:49:53 +00:00
chore(tailwind): Move grpc-method-dropdown to tailwind (#7074)
* grpc-method-dropdown tailwind * fix disabled prop
This commit is contained in:
parent
c0707c884f
commit
45edba1269
@ -26,7 +26,7 @@ test('can send gRPC requests with reflection', async ({ app, page }) => {
|
|||||||
await page.getByTestId('button-server-reflection').click();
|
await page.getByTestId('button-server-reflection').click();
|
||||||
|
|
||||||
await page.getByRole('button', { name: 'Select Method' }).click();
|
await page.getByRole('button', { name: 'Select Method' }).click();
|
||||||
await page.getByRole('menuitem', { name: 'RouteGuide/GetFeature' }).click();
|
await page.getByRole('option', { name: 'RouteGuide/GetFeature' }).click();
|
||||||
|
|
||||||
await page.getByRole('tab', { name: 'Unary' }).click();
|
await page.getByRole('tab', { name: 'Unary' }).click();
|
||||||
await page.getByRole('button', { name: 'Send' }).click();
|
await page.getByRole('button', { name: 'Send' }).click();
|
||||||
|
@ -1,16 +1,8 @@
|
|||||||
import React, { FunctionComponent } from 'react';
|
import React, { Fragment, FunctionComponent } from 'react';
|
||||||
import styled from 'styled-components';
|
import { Button, Header, ListBox, ListBoxItem, Popover, Section, Select, SelectValue } from 'react-aria-components';
|
||||||
|
|
||||||
import type { GrpcMethodInfo } from '../../../../main/ipc/grpc';
|
import type { GrpcMethodInfo, GrpcMethodType } from '../../../../main/ipc/grpc';
|
||||||
import { Dropdown, DropdownButton, DropdownItem, DropdownSection, ItemContent } from '../../base/dropdown';
|
import { Icon } from '../../icon';
|
||||||
import { GrpcMethodTag } from '../../tags/grpc-method-tag';
|
|
||||||
import { Tooltip } from '../../tooltip';
|
|
||||||
|
|
||||||
const DropdownMethodButtonLabel = styled.div({
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
gap: 'var(--padding-xs)',
|
|
||||||
});
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
@ -22,6 +14,13 @@ const PROTO_PATH_REGEX = /^\/(?:(?<package>[\w.]+)\.)?(?<service>\w+)\/(?<method
|
|||||||
|
|
||||||
export const NO_PACKAGE_KEY = 'no-package';
|
export const NO_PACKAGE_KEY = 'no-package';
|
||||||
|
|
||||||
|
const GrpcMethodTypeAcronym = {
|
||||||
|
unary: 'U',
|
||||||
|
server: 'SS',
|
||||||
|
client: 'CS',
|
||||||
|
bidi: 'BD',
|
||||||
|
} as const;
|
||||||
|
|
||||||
function groupBy(list: {}[], keyGetter: (item: any) => string): Record<string, any[]> {
|
function groupBy(list: {}[], keyGetter: (item: any) => string): Record<string, any[]> {
|
||||||
const map = new Map();
|
const map = new Map();
|
||||||
list.forEach(item => {
|
list.forEach(item => {
|
||||||
@ -48,9 +47,6 @@ export const getShortGrpcPath = (fullPath: string): string => {
|
|||||||
const methodName = result?.groups?.method;
|
const methodName = result?.groups?.method;
|
||||||
return packageName && serviceName && methodName ? `/${serviceName}/${methodName}` : fullPath;
|
return packageName && serviceName && methodName ? `/${serviceName}/${methodName}` : fullPath;
|
||||||
};
|
};
|
||||||
const NormalCase = styled.span`
|
|
||||||
text-transform: initial;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const GrpcMethodDropdown: FunctionComponent<Props> = ({
|
export const GrpcMethodDropdown: FunctionComponent<Props> = ({
|
||||||
disabled,
|
disabled,
|
||||||
@ -59,61 +55,97 @@ export const GrpcMethodDropdown: FunctionComponent<Props> = ({
|
|||||||
handleChange,
|
handleChange,
|
||||||
}) => {
|
}) => {
|
||||||
const groupedByPkg = groupGrpcMethodsByPackage(methods);
|
const groupedByPkg = groupGrpcMethodsByPackage(methods);
|
||||||
|
const sections = Object.entries(groupedByPkg).map(([name, pkg]) => ({
|
||||||
|
id: name,
|
||||||
|
name: name !== NO_PACKAGE_KEY ? `pkg: ${name}` : 'No package',
|
||||||
|
display_name: name !== NO_PACKAGE_KEY ? `pkg: ${name}` : 'No package',
|
||||||
|
items: pkg.map(({ type, fullPath, example }) => ({
|
||||||
|
id: fullPath,
|
||||||
|
fullPath,
|
||||||
|
display_name: getShortGrpcPath(fullPath),
|
||||||
|
type,
|
||||||
|
example,
|
||||||
|
isDisabled: disabled,
|
||||||
|
})),
|
||||||
|
}));
|
||||||
const selectedPath = selectedMethod?.fullPath;
|
const selectedPath = selectedMethod?.fullPath;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dropdown
|
<Select
|
||||||
aria-label='Select gRPC method dropdown'
|
aria-label="Select gRPC method"
|
||||||
className="tall wide"
|
name="method"
|
||||||
|
onSelectionChange={key => {
|
||||||
|
handleChange(key.toString());
|
||||||
|
}}
|
||||||
|
className="h-full"
|
||||||
|
selectedKey={selectedPath}
|
||||||
isDisabled={methods.length === 0}
|
isDisabled={methods.length === 0}
|
||||||
triggerButton={
|
|
||||||
<DropdownButton
|
|
||||||
size='medium'
|
|
||||||
className='tall wide'
|
|
||||||
removeBorderRadius
|
|
||||||
removePaddings={false}
|
|
||||||
disableHoverBehavior={false}
|
|
||||||
isDisabled={methods.length === 0}
|
|
||||||
style={{ maxWidth: '250px' }}
|
|
||||||
>
|
|
||||||
<Tooltip
|
|
||||||
message={selectedPath || 'Add proto file or use server reflection'}
|
|
||||||
position="bottom"
|
|
||||||
delay={500}
|
|
||||||
style={{ maxWidth: '240px', display: 'flex', alignItems: 'center' }}
|
|
||||||
>
|
|
||||||
<span style={{ maxWidth: '240px', overflow: 'hidden', textOverflow: 'ellipsis' }}>
|
|
||||||
{!selectedPath ? 'Select Method' : getShortGrpcPath(selectedPath)}
|
|
||||||
</span>
|
|
||||||
<i className="fa fa-caret-down pad-left-sm" />
|
|
||||||
</Tooltip>
|
|
||||||
</DropdownButton>
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
{Object.entries(groupedByPkg).map(([name, pkg]) => (
|
<Button className="px-4 py-1 disabled:bg-[--hl-xs] h-full disabled:cursor-not-allowed font-semibold flex items-center justify-center gap-2 aria-pressed:bg-[--hl-sm] rounded-sm text-[--color-font] hover:bg-[--hl-xs] data-[pressed]:bg-[--hl-xs] focus:ring-inset ring-1 ring-transparent focus:ring-[--hl-md] transition-all text-sm">
|
||||||
<DropdownSection
|
<SelectValue<{
|
||||||
key={name}
|
id: string;
|
||||||
aria-label='Select gRPC method section'
|
fullPath: string;
|
||||||
title={name !== NO_PACKAGE_KEY && <NormalCase>pkg: {name}</NormalCase>}
|
display_name: string;
|
||||||
|
type: GrpcMethodType;
|
||||||
|
example: Record<string, any> | undefined;
|
||||||
|
}>
|
||||||
|
className="flex truncate items-center justify-center gap-2"
|
||||||
>
|
>
|
||||||
{pkg.map(({ type, fullPath }) => (
|
{({ selectedItem }) => {
|
||||||
<DropdownItem
|
if (!selectedItem) {
|
||||||
key={fullPath}
|
return (
|
||||||
aria-label={fullPath}
|
<Fragment>
|
||||||
>
|
<span>
|
||||||
<ItemContent
|
{selectedPath ? getShortGrpcPath(selectedPath) : 'Select Method'}
|
||||||
isDisabled={disabled}
|
</span>
|
||||||
isSelected={fullPath === selectedPath}
|
</Fragment>
|
||||||
onClick={() => handleChange(fullPath)}
|
);
|
||||||
>
|
}
|
||||||
<Tooltip message={fullPath} position="right" delay={500}>
|
|
||||||
<DropdownMethodButtonLabel><GrpcMethodTag methodType={type} /> {getShortGrpcPath(fullPath)}</DropdownMethodButtonLabel>
|
return (
|
||||||
</Tooltip>
|
<Fragment>
|
||||||
</ItemContent>
|
{selectedItem.display_name}
|
||||||
</DropdownItem>
|
</Fragment>
|
||||||
))}
|
);
|
||||||
</DropdownSection>
|
}}
|
||||||
))}
|
</SelectValue>
|
||||||
</Dropdown>
|
<Icon icon="caret-down" />
|
||||||
|
</Button>
|
||||||
|
<Popover className="min-w-max max-w-xs">
|
||||||
|
<ListBox
|
||||||
|
items={sections}
|
||||||
|
className="border select-none text-sm min-w-max border-solid border-[--hl-sm] shadow-lg bg-[--color-bg] py-2 rounded-md overflow-y-auto max-h-[85vh] focus:outline-none"
|
||||||
|
>
|
||||||
|
{item => (
|
||||||
|
<Section key={item.id}>
|
||||||
|
<Header className='flex px-[--padding-md] items-center gap-2 text-[--hl-md]'><span>{item.display_name}</span><span className='bg-[--hl-md] h-[1px] flex-1' /></Header>
|
||||||
|
{item.items.map(grpcMethod => (
|
||||||
|
<ListBoxItem
|
||||||
|
id={grpcMethod.id}
|
||||||
|
key={grpcMethod.id}
|
||||||
|
className="flex gap-2 px-[--padding-md] aria-selected:font-bold items-center text-[--color-font] h-[--line-height-xs] w-full text-md whitespace-nowrap bg-transparent hover:bg-[--hl-sm] disabled:cursor-not-allowed focus:bg-[--hl-xs] focus:outline-none transition-colors"
|
||||||
|
aria-label={grpcMethod.display_name}
|
||||||
|
textValue={grpcMethod.display_name}
|
||||||
|
value={grpcMethod}
|
||||||
|
>
|
||||||
|
{({ isSelected }) => (
|
||||||
|
<Fragment>
|
||||||
|
<em>{GrpcMethodTypeAcronym[grpcMethod.type]}</em>
|
||||||
|
{grpcMethod.display_name}
|
||||||
|
{isSelected && (
|
||||||
|
<Icon
|
||||||
|
icon="check"
|
||||||
|
className="text-[--color-success] justify-self-end"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Fragment>
|
||||||
|
)}
|
||||||
|
</ListBoxItem>
|
||||||
|
))}
|
||||||
|
</Section>
|
||||||
|
)}
|
||||||
|
</ListBox>
|
||||||
|
</Popover>
|
||||||
|
</Select >
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
import React, { FunctionComponent } from 'react';
|
|
||||||
import styled from 'styled-components';
|
|
||||||
|
|
||||||
import type { GrpcMethodType } from '../../../main/ipc/grpc';
|
|
||||||
import { GrpcMethodTypeName } from '../panes/grpc-request-pane';
|
|
||||||
import { Tooltip } from '../tooltip';
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
methodType: GrpcMethodType;
|
|
||||||
}
|
|
||||||
|
|
||||||
const StyledTag = styled.div`
|
|
||||||
width: 1.5em;
|
|
||||||
text-align: right;
|
|
||||||
`;
|
|
||||||
const GrpcMethodTypeAcronym = {
|
|
||||||
unary: 'U',
|
|
||||||
server: 'SS',
|
|
||||||
client: 'CS',
|
|
||||||
bidi: 'BD',
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
export const GrpcMethodTag: FunctionComponent<Props> = ({ methodType }) => (
|
|
||||||
<Tooltip message={GrpcMethodTypeName[methodType]} position="left" delay={500}>
|
|
||||||
<StyledTag>
|
|
||||||
<em>{GrpcMethodTypeAcronym[methodType]}</em>
|
|
||||||
</StyledTag>
|
|
||||||
</Tooltip>
|
|
||||||
);
|
|
Loading…
Reference in New Issue
Block a user