mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-03-26 03:11:12 +01:00
Show hotkeys on empty views
This commit is contained in:
@@ -35,7 +35,7 @@ export const EnvironmentActionsDropdown = memo(function EnvironmentActionsDropdo
|
||||
});
|
||||
}, [dialog, activeEnvironment]);
|
||||
|
||||
useHotkey('environmentEditor.toggle', showEnvironmentDialog);
|
||||
useHotkey('environmentEditor.toggle', showEnvironmentDialog, { enable: environments.length > 0 });
|
||||
|
||||
const items: DropdownItem[] = useMemo(
|
||||
() => [
|
||||
|
||||
@@ -3,8 +3,12 @@ import classNames from 'classnames';
|
||||
import type { CSSProperties, MouseEvent as ReactMouseEvent } from 'react';
|
||||
import React, { memo, useCallback, useMemo, useRef, useState } from 'react';
|
||||
import { useLocalStorage } from 'react-use';
|
||||
import { useActiveRequest } from '../hooks/useActiveRequest';
|
||||
import { useActiveWorkspaceId } from '../hooks/useActiveWorkspaceId';
|
||||
import { useCreateRequest } from '../hooks/useCreateRequest';
|
||||
import { useRequests } from '../hooks/useRequests';
|
||||
import { clamp } from '../lib/clamp';
|
||||
import { HotKeyList } from './core/HotKeyList';
|
||||
import { RequestPane } from './RequestPane';
|
||||
import { ResizeHandle } from './ResizeHandle';
|
||||
import { ResponsePane } from './ResponsePane';
|
||||
@@ -24,6 +28,9 @@ const STACK_VERTICAL_WIDTH = 600;
|
||||
|
||||
export const RequestResponse = memo(function RequestResponse({ style }: Props) {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const activeRequest = useActiveRequest();
|
||||
const createRequest = useCreateRequest();
|
||||
const requests = useRequests();
|
||||
const [vertical, setVertical] = useState<boolean>(false);
|
||||
const [widthRaw, setWidth] = useLocalStorage<number>(`body_width::${useActiveWorkspaceId()}`);
|
||||
const [heightRaw, setHeight] = useLocalStorage<number>(`body_height::${useActiveWorkspaceId()}`);
|
||||
@@ -114,6 +121,24 @@ export const RequestResponse = memo(function RequestResponse({ style }: Props) {
|
||||
[width, height, vertical, setHeight, setWidth],
|
||||
);
|
||||
|
||||
if (activeRequest === null && requests.length > 0) {
|
||||
return (
|
||||
<div className="h-full flex items-center justify-center opacity-disabled">
|
||||
<p>No Selected Request</p>
|
||||
</div>
|
||||
);
|
||||
} else if (requests.length === 0) {
|
||||
return (
|
||||
<HotKeyList
|
||||
hotkeys={[
|
||||
{ action: 'request.create', label: 'New Request' },
|
||||
{ action: 'sidebar.toggle', label: 'Toggle Sidebar' },
|
||||
{ action: 'urlBar.focus', label: 'Focus URL' },
|
||||
]}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div ref={containerRef} className="grid gap-1.5 w-full h-full p-3" style={styles}>
|
||||
<RequestPane style={rqst} fullHeight={!vertical} />
|
||||
|
||||
@@ -2,7 +2,7 @@ import classNames from 'classnames';
|
||||
import type { CSSProperties } from 'react';
|
||||
import { memo, useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { createGlobalState } from 'react-use';
|
||||
import { useActiveRequestId } from '../hooks/useActiveRequestId';
|
||||
import { useActiveRequest } from '../hooks/useActiveRequest';
|
||||
import { useLatestResponse } from '../hooks/useLatestResponse';
|
||||
import { useResponseContentType } from '../hooks/useResponseContentType';
|
||||
import { useResponses } from '../hooks/useResponses';
|
||||
@@ -12,6 +12,7 @@ import { isResponseLoading } from '../lib/models';
|
||||
import { Banner } from './core/Banner';
|
||||
import { CountBadge } from './core/CountBadge';
|
||||
import { DurationTag } from './core/DurationTag';
|
||||
import { HotKeyList } from './core/HotKeyList';
|
||||
import { SizeTag } from './core/SizeTag';
|
||||
import { HStack } from './core/Stacks';
|
||||
import { StatusTag } from './core/StatusTag';
|
||||
@@ -34,9 +35,9 @@ const useActiveTab = createGlobalState<string>('body');
|
||||
|
||||
export const ResponsePane = memo(function ResponsePane({ style, className }: Props) {
|
||||
const [pinnedResponseId, setPinnedResponseId] = useState<string | null>(null);
|
||||
const activeRequestId = useActiveRequestId();
|
||||
const latestResponse = useLatestResponse(activeRequestId);
|
||||
const responses = useResponses(activeRequestId);
|
||||
const activeRequest = useActiveRequest();
|
||||
const latestResponse = useLatestResponse(activeRequest?.id ?? null);
|
||||
const responses = useResponses(activeRequest?.id ?? null);
|
||||
const activeResponse: HttpResponse | null = pinnedResponseId
|
||||
? responses.find((r) => r.id === pinnedResponseId) ?? null
|
||||
: latestResponse ?? null;
|
||||
@@ -84,6 +85,10 @@ export const ResponsePane = memo(function ResponsePane({ style, className }: Pro
|
||||
[activeResponse?.headers, contentType, setViewMode, viewMode],
|
||||
);
|
||||
|
||||
if (activeRequest === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
style={style}
|
||||
@@ -95,6 +100,19 @@ export const ResponsePane = memo(function ResponsePane({ style, className }: Pro
|
||||
)}
|
||||
>
|
||||
{activeResponse?.error && <Banner className="m-2">{activeResponse.error}</Banner>}
|
||||
{!activeResponse && (
|
||||
<>
|
||||
<span />
|
||||
<HotKeyList
|
||||
hotkeys={[
|
||||
{ action: 'request.send', label: 'Send Request' },
|
||||
{ action: 'request.create', label: 'New Request' },
|
||||
{ action: 'sidebar.toggle', label: 'Toggle Sidebar' },
|
||||
{ action: 'urlBar.focus', label: 'Focus URL' },
|
||||
]}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{activeResponse && !activeResponse.error && !isResponseLoading(activeResponse) && (
|
||||
<>
|
||||
<HStack
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { invoke } from '@tauri-apps/api';
|
||||
import { invoke, shell } from '@tauri-apps/api';
|
||||
import { useRef } from 'react';
|
||||
import { useAppVersion } from '../hooks/useAppVersion';
|
||||
import { useExportData } from '../hooks/useExportData';
|
||||
@@ -79,6 +79,12 @@ export function SettingsDropdown() {
|
||||
onSelect: () => invoke('check_for_updates'),
|
||||
leftSlot: <Icon icon="update" />,
|
||||
},
|
||||
{
|
||||
key: 'feedback',
|
||||
label: 'Feedback',
|
||||
onSelect: () => shell.open('https://yaak.canny.io'),
|
||||
leftSlot: <Icon icon="chat" />,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<IconButton size="sm" title="Request Options" icon="gear" className="pointer-events-auto" />
|
||||
|
||||
@@ -5,9 +5,11 @@ import { useOsInfo } from '../../hooks/useOsInfo';
|
||||
|
||||
interface Props {
|
||||
action: HotkeyAction | null;
|
||||
className?: string;
|
||||
variant?: 'text' | 'with-bg';
|
||||
}
|
||||
|
||||
export function HotKey({ action }: Props) {
|
||||
export function HotKey({ action, className, variant }: Props) {
|
||||
const osInfo = useOsInfo();
|
||||
const label = useFormattedHotkey(action);
|
||||
if (label === null || osInfo == null) {
|
||||
@@ -15,6 +17,14 @@ export function HotKey({ action }: Props) {
|
||||
}
|
||||
|
||||
return (
|
||||
<span className={classNames('text-sm text-gray-1000 text-opacity-disabled')}>{label}</span>
|
||||
<span
|
||||
className={classNames(
|
||||
className,
|
||||
variant === 'with-bg' && 'rounded border',
|
||||
'text-sm text-gray-1000 text-opacity-disabled',
|
||||
)}
|
||||
>
|
||||
{label}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
24
src-web/components/core/HotKeyList.tsx
Normal file
24
src-web/components/core/HotKeyList.tsx
Normal file
@@ -0,0 +1,24 @@
|
||||
import React from 'react';
|
||||
import type { HotkeyAction } from '../../hooks/useHotkey';
|
||||
import { HotKey } from './HotKey';
|
||||
|
||||
interface Props {
|
||||
hotkeys: { action: HotkeyAction; label: string }[];
|
||||
}
|
||||
|
||||
export const HotKeyList = ({ hotkeys }: Props) => {
|
||||
return (
|
||||
<div className="mx-auto h-full flex items-center text-gray-800 text-sm">
|
||||
<div className="flex flex-col gap-1">
|
||||
{hotkeys.map((hotkey) => (
|
||||
<div key={hotkey.action} className="grid grid-cols-2">
|
||||
<p>{hotkey.label}</p>
|
||||
<div className="ml-auto">
|
||||
<HotKey action={hotkey.action} />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -8,6 +8,7 @@ import { ReactComponent as LeftPanelVisibleIcon } from '../../assets/icons/LeftP
|
||||
const icons = {
|
||||
archive: ReactIcons.ArchiveIcon,
|
||||
camera: ReactIcons.CameraIcon,
|
||||
chat: ReactIcons.ChatBubbleIcon,
|
||||
check: ReactIcons.CheckIcon,
|
||||
checkbox: ReactIcons.CheckboxIcon,
|
||||
clock: ReactIcons.ClockIcon,
|
||||
|
||||
Reference in New Issue
Block a user