mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-02-22 18:47:57 +01:00
Compare commits
10 Commits
v2025.2.0-
...
v2025.2.0-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9fa0650647 | ||
|
|
b8c42677ca | ||
|
|
2eb3c2241c | ||
|
|
8fb7bbfe2e | ||
|
|
52eba74151 | ||
|
|
e651760713 | ||
|
|
82451a26f6 | ||
|
|
cc15f60fb6 | ||
|
|
2f8b2a81c7 | ||
|
|
6d4fdc91fe |
@@ -158,15 +158,14 @@ impl EncryptionManager {
|
||||
}
|
||||
|
||||
fn get_master_key(&self) -> Result<MasterKey> {
|
||||
{
|
||||
let master_secret = self.cached_master_key.lock().unwrap();
|
||||
if let Some(k) = master_secret.as_ref() {
|
||||
return Ok(k.to_owned());
|
||||
}
|
||||
// NOTE: This locks the key for the entire function which seems wrong, but this prevents
|
||||
// concurrent access from prompting the user for a keychain password multiple times.
|
||||
let mut master_secret = self.cached_master_key.lock().unwrap();
|
||||
if let Some(k) = master_secret.as_ref() {
|
||||
return Ok(k.to_owned());
|
||||
}
|
||||
|
||||
let mkey = MasterKey::get_or_create(&self.app_id, KEY_USER)?;
|
||||
let mut master_secret = self.cached_master_key.lock().unwrap();
|
||||
*master_secret = Some(mkey.clone());
|
||||
Ok(mkey)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createStore } from 'jotai/index';
|
||||
import { createStore } from 'jotai';
|
||||
import { AnyModel } from '../bindings/gen_models';
|
||||
|
||||
export type ExtractModel<T, M> = T extends { model: M } ? T : never;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { workspacesAtom } from '@yaakapp-internal/models';
|
||||
import classNames from 'classnames';
|
||||
import { fuzzyFilter } from 'fuzzbunny';
|
||||
import { useAtomValue } from 'jotai/index';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import type { KeyboardEvent, ReactNode } from 'react';
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { createFolder } from '../commands/commands';
|
||||
@@ -350,10 +350,10 @@ export function CommandPaletteDialog({ onClose }: { onClose: () => void }) {
|
||||
|
||||
const filteredGroups = groups
|
||||
.map((g) => {
|
||||
g.items = result
|
||||
const items = result
|
||||
.filter((i) => g.items.find((i2) => i2.key === i.key))
|
||||
.slice(0, MAX_PER_GROUP);
|
||||
return g;
|
||||
return { ...g, items };
|
||||
})
|
||||
.filter((g) => g.items.length > 0);
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import type {
|
||||
JsonPrimitive,
|
||||
} from '@yaakapp-internal/plugins';
|
||||
import classNames from 'classnames';
|
||||
import { useAtomValue } from 'jotai/index';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import { useCallback } from 'react';
|
||||
import { useActiveRequest } from '../hooks/useActiveRequest';
|
||||
import { capitalize } from '../lib/capitalize';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { foldersAtom, patchModel } from '@yaakapp-internal/models';
|
||||
import { useAtomValue } from 'jotai/index';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import { Input } from './core/Input';
|
||||
import { VStack } from './core/Stacks';
|
||||
import { MarkdownEditor } from './MarkdownEditor';
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import type { GrpcEvent, GrpcRequest } from '@yaakapp-internal/models';
|
||||
import classNames from 'classnames';
|
||||
import { format } from 'date-fns';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import { useSetAtom } from 'jotai/index';
|
||||
import { useAtomValue , useSetAtom } from 'jotai';
|
||||
import type { CSSProperties } from 'react';
|
||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useCopy } from '../hooks/useCopy';
|
||||
|
||||
@@ -34,8 +34,8 @@ export function HeaderSize({
|
||||
// Add padding for macOS stoplights, but keep it the same width (account for the interface scale)
|
||||
paddingLeft:
|
||||
stoplightsVisible && !ignoreControlsSpacing ? 72 / settings.interfaceScale : undefined,
|
||||
...(size === 'md' ? { height: HEADER_SIZE_MD } : {}),
|
||||
...(size === 'lg' ? { height: HEADER_SIZE_LG } : {}),
|
||||
...(size === 'md' ? { minHeight: HEADER_SIZE_MD } : {}),
|
||||
...(size === 'lg' ? { minHeight: HEADER_SIZE_LG } : {}),
|
||||
...(osInfo.osType === 'macos' || ignoreControlsSpacing
|
||||
? { paddingRight: '2px' }
|
||||
: { paddingLeft: '2px', paddingRight: WINDOW_CONTROLS_WIDTH }),
|
||||
|
||||
@@ -5,6 +5,7 @@ import React, { useCallback, useMemo } from 'react';
|
||||
import { useLocalStorage } from 'react-use';
|
||||
import { usePinnedHttpResponse } from '../hooks/usePinnedHttpResponse';
|
||||
import { useResponseViewMode } from '../hooks/useResponseViewMode';
|
||||
import { getMimeTypeFromContentType } from '../lib/contentType';
|
||||
import { getContentTypeFromHeaders } from '../lib/model_util';
|
||||
import { ConfirmLargeResponse } from './ConfirmLargeResponse';
|
||||
import { Banner } from './core/Banner';
|
||||
@@ -48,6 +49,7 @@ export function HttpResponsePane({ style, className, activeRequestId }: Props) {
|
||||
{},
|
||||
);
|
||||
const contentType = getContentTypeFromHeaders(activeResponse?.headers ?? null);
|
||||
const mimeType = contentType == null ? null : getMimeTypeFromContentType(contentType).essence;
|
||||
|
||||
const tabs = useMemo<TabItem[]>(
|
||||
() => [
|
||||
@@ -59,7 +61,7 @@ export function HttpResponsePane({ style, className, activeRequestId }: Props) {
|
||||
onChange: setViewMode,
|
||||
items: [
|
||||
{ label: 'Pretty', value: 'pretty' },
|
||||
...(contentType?.startsWith('image') ? [] : [{ label: 'Raw', value: 'raw' }]),
|
||||
...(mimeType?.startsWith('image') ? [] : [{ label: 'Raw', value: 'raw' }]),
|
||||
],
|
||||
},
|
||||
},
|
||||
@@ -77,7 +79,7 @@ export function HttpResponsePane({ style, className, activeRequestId }: Props) {
|
||||
label: 'Info',
|
||||
},
|
||||
],
|
||||
[activeResponse?.headers, contentType, setViewMode, viewMode],
|
||||
[activeResponse?.headers, mimeType, setViewMode, viewMode],
|
||||
);
|
||||
const activeTab = activeTabs?.[activeRequestId];
|
||||
const setActiveTab = useCallback(
|
||||
@@ -123,9 +125,7 @@ export function HttpResponsePane({ style, className, activeRequestId }: Props) {
|
||||
{activeResponse.state !== 'closed' && <LoadingIcon size="sm" />}
|
||||
<HttpStatusTag showReason response={activeResponse} />
|
||||
<span>•</span>
|
||||
<HttpResponseDurationTag
|
||||
response={activeResponse}
|
||||
/>
|
||||
<HttpResponseDurationTag response={activeResponse} />
|
||||
<span>•</span>
|
||||
<SizeTag contentLength={activeResponse.contentLength ?? 0} />
|
||||
|
||||
@@ -162,23 +162,21 @@ export function HttpResponsePane({ style, className, activeRequestId }: Props) {
|
||||
</EmptyStateText>
|
||||
) : activeResponse.state === 'closed' && activeResponse.contentLength === 0 ? (
|
||||
<EmptyStateText>Empty </EmptyStateText>
|
||||
) : contentType?.match(/^text\/event-stream$/i) && viewMode === 'pretty' ? (
|
||||
) : mimeType?.match(/^text\/event-stream/i) && viewMode === 'pretty' ? (
|
||||
<EventStreamViewer response={activeResponse} />
|
||||
) : contentType?.match(/^image\/svg/) ? (
|
||||
) : mimeType?.match(/^image\/svg/) ? (
|
||||
<SvgViewer response={activeResponse} />
|
||||
) : contentType?.match(/^image/i) ? (
|
||||
) : mimeType?.match(/^image/i) ? (
|
||||
<EnsureCompleteResponse response={activeResponse} render={ImageViewer} />
|
||||
) : contentType?.match(/^audio/i) ? (
|
||||
) : mimeType?.match(/^audio/i) ? (
|
||||
<EnsureCompleteResponse response={activeResponse} render={AudioViewer} />
|
||||
) : contentType?.match(/^video/i) ? (
|
||||
) : mimeType?.match(/^video/i) ? (
|
||||
<EnsureCompleteResponse response={activeResponse} render={VideoViewer} />
|
||||
) : contentType?.match(/pdf/i) ? (
|
||||
) : mimeType?.match(/pdf/i) ? (
|
||||
<EnsureCompleteResponse response={activeResponse} render={PdfViewer} />
|
||||
) : contentType?.match(/csv|tab-separated/i) ? (
|
||||
) : mimeType?.match(/csv|tab-separated/i) ? (
|
||||
<CsvViewer className="pb-2" response={activeResponse} />
|
||||
) : (
|
||||
// ) : viewMode === 'pretty' && contentType?.includes('json') ? (
|
||||
// <JsonAttributeTree attrValue={activeResponse} />
|
||||
<HTMLOrTextViewer
|
||||
textViewerClassName="-mr-2 bg-surface" // Pull to the right
|
||||
response={activeResponse}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { revealItemInDir } from '@tauri-apps/plugin-opener';
|
||||
import { patchModel, settingsAtom } from '@yaakapp-internal/models';
|
||||
import { useAtomValue } from 'jotai/index';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import React from 'react';
|
||||
import { activeWorkspaceAtom } from '../../hooks/useActiveWorkspace';
|
||||
import { useAppInfo } from '../../hooks/useAppInfo';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { enableEncryption, revealWorkspaceKey, setWorkspaceKey } from '@yaakapp-internal/crypto';
|
||||
import type { WorkspaceMeta } from '@yaakapp-internal/models';
|
||||
import classNames from 'classnames';
|
||||
import { useAtomValue } from 'jotai/index';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { activeWorkspaceAtom, activeWorkspaceMetaAtom } from '../hooks/useActiveWorkspace';
|
||||
import { createFastMutation } from '../hooks/useFastMutation';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import classNames from 'classnames';
|
||||
import { useAtomValue } from 'jotai/index';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import React, { memo } from 'react';
|
||||
import { activeWorkspaceAtom, activeWorkspaceMetaAtom } from '../hooks/useActiveWorkspace';
|
||||
import { useToggleCommandPalette } from '../hooks/useToggleCommandPalette';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { patchModel, workspaceMetasAtom, workspacesAtom } from '@yaakapp-internal/models';
|
||||
import { useAtomValue } from 'jotai/index';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import { deleteModelWithConfirm } from '../lib/deleteModelWithConfirm';
|
||||
import { router } from '../lib/router';
|
||||
import { Banner } from './core/Banner';
|
||||
|
||||
@@ -6,23 +6,25 @@ interface Props {
|
||||
}
|
||||
|
||||
export function HttpResponseDurationTag({ response }: Props) {
|
||||
const [fallbackDuration, setFallbackDuration] = useState<number>(0);
|
||||
const [fallbackElapsed, setFallbackElapsed] = useState<number>(0);
|
||||
const timeout = useRef<NodeJS.Timeout>();
|
||||
|
||||
// Calculate the duration of the response for use when the response hasn't finished yet
|
||||
useEffect(() => {
|
||||
clearInterval(timeout.current);
|
||||
timeout.current = setInterval(() => {
|
||||
setFallbackDuration(Date.now() - new Date(response.createdAt + 'Z').getTime());
|
||||
setFallbackElapsed(Date.now() - new Date(response.createdAt + 'Z').getTime());
|
||||
}, 100);
|
||||
return () => clearInterval(timeout.current);
|
||||
}, [response.createdAt, response.elapsed, response.state]);
|
||||
|
||||
const title = `HEADER: ${formatMillis(response.elapsedHeaders)}\nTOTAL: ${formatMillis(response.elapsed)}`;
|
||||
|
||||
const elapsed = response.state === 'closed' ? response.elapsed : fallbackElapsed;
|
||||
|
||||
return (
|
||||
<span className="font-mono" title={title}>
|
||||
{formatMillis(response.elapsed || fallbackDuration)}
|
||||
{formatMillis(elapsed)}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ export function BinaryViewer({ response }: Props) {
|
||||
const contentType = getContentTypeFromHeaders(response.headers) ?? 'unknown';
|
||||
|
||||
// Wait until the response has been fully-downloaded
|
||||
if (response.state === 'closed') {
|
||||
if (response.state !== 'closed') {
|
||||
return (
|
||||
<EmptyStateText>
|
||||
<LoadingIcon size="sm" />
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { HttpResponse } from '@yaakapp-internal/models';
|
||||
import { useResponseBodyText } from '../../hooks/useResponseBodyText';
|
||||
import { languageFromContentType } from '../../lib/contentType';
|
||||
import { getContentTypeFromHeaders } from '../../lib/model_util';
|
||||
import { BinaryViewer } from './BinaryViewer';
|
||||
import { EmptyStateText } from '../EmptyStateText';
|
||||
import { TextViewer } from './TextViewer';
|
||||
import { WebPageViewer } from './WebPageViewer';
|
||||
|
||||
@@ -21,13 +21,10 @@ export function HTMLOrTextViewer({ response, pretty, textViewerClassName }: Prop
|
||||
return null;
|
||||
}
|
||||
|
||||
// Wasn't able to decode as text, so it must be binary
|
||||
if (rawTextBody.data == null) {
|
||||
return <BinaryViewer response={response} />;
|
||||
}
|
||||
|
||||
if (language === 'html' && pretty) {
|
||||
return <WebPageViewer response={response} />;
|
||||
} else if (rawTextBody.data == null) {
|
||||
return <EmptyStateText>Empty response</EmptyStateText>
|
||||
} else {
|
||||
return (
|
||||
<TextViewer
|
||||
|
||||
@@ -320,7 +320,7 @@ export function Sidebar({ className }: Props) {
|
||||
'h-full grid grid-rows-[minmax(0,1fr)_auto]',
|
||||
)}
|
||||
>
|
||||
<div className="pb-3 overflow-x-visible overflow-y-scroll hide-scrollbars pt-2">
|
||||
<div className="pb-3 overflow-x-visible overflow-y-scroll pt-2">
|
||||
<ContextMenu
|
||||
triggerPosition={showMainContextMenu}
|
||||
items={mainContextMenuItems}
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
websocketConnectionsAtom,
|
||||
} from '@yaakapp-internal/models';
|
||||
import classNames from 'classnames';
|
||||
import { useAtomValue } from 'jotai/index';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import React, { Fragment, memo } from 'react';
|
||||
import { VStack } from '../core/Stacks';
|
||||
import { DropMarker } from '../DropMarker';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useSearch } from '@tanstack/react-router';
|
||||
import type { CookieJar } from '@yaakapp-internal/models';
|
||||
import { cookieJarsAtom } from '@yaakapp-internal/models';
|
||||
import { atom, useAtomValue } from 'jotai/index';
|
||||
import { atom, useAtomValue } from 'jotai';
|
||||
import { useEffect } from 'react';
|
||||
import { jotaiStore } from '../lib/jotai';
|
||||
import { setWorkspaceSearchParams } from '../lib/setWorkspaceSearchParams';
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { useSearch } from '@tanstack/react-router';
|
||||
import type { Environment } from '@yaakapp-internal/models';
|
||||
import { environmentsAtom } from '@yaakapp-internal/models';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import { atom } from 'jotai/index';
|
||||
import { useAtomValue , atom } from 'jotai';
|
||||
import { useEffect } from 'react';
|
||||
import { jotaiStore } from '../lib/jotai';
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useParams } from '@tanstack/react-router';
|
||||
import { workspaceMetasAtom, workspacesAtom } from '@yaakapp-internal/models';
|
||||
import { atom } from 'jotai/index';
|
||||
import { atom } from 'jotai';
|
||||
import { useEffect } from 'react';
|
||||
import { jotaiStore } from '../lib/jotai';
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import {
|
||||
httpRequestsAtom,
|
||||
websocketRequestsAtom,
|
||||
} from '@yaakapp-internal/models';
|
||||
import { atom, useAtomValue } from 'jotai/index';
|
||||
import { atom, useAtomValue } from 'jotai';
|
||||
|
||||
export const allRequestsAtom = atom(function (get) {
|
||||
return [...get(httpRequestsAtom), ...get(grpcRequestsAtom), ...get(websocketRequestsAtom)];
|
||||
|
||||
@@ -3,7 +3,7 @@ import {
|
||||
httpResponsesAtom,
|
||||
websocketConnectionsAtom,
|
||||
} from '@yaakapp-internal/models';
|
||||
import { useAtomValue } from 'jotai/index';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import { showAlert } from '../lib/alert';
|
||||
import { showConfirmDelete } from '../lib/confirm';
|
||||
import { jotaiStore } from '../lib/jotai';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { environmentsAtom } from '@yaakapp-internal/models';
|
||||
import { useAtomValue } from 'jotai/index';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export function useEnvironmentsBreakdown() {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import type { GetHttpAuthenticationSummaryResponse } from '@yaakapp-internal/plugins';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import { atom } from 'jotai/index';
|
||||
import { useAtomValue , atom } from 'jotai';
|
||||
import { useState } from 'react';
|
||||
import { jotaiStore } from '../lib/jotai';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { GrpcConnection} from '@yaakapp-internal/models';
|
||||
import { grpcConnectionsAtom } from '@yaakapp-internal/models';
|
||||
import { useAtomValue } from 'jotai/index';
|
||||
import { useAtomValue } from 'jotai';
|
||||
|
||||
export function useLatestGrpcConnection(requestId: string | null): GrpcConnection | null {
|
||||
return useAtomValue(grpcConnectionsAtom).find((c) => c.requestId === requestId) ?? null;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { HttpResponse} from '@yaakapp-internal/models';
|
||||
import { httpResponsesAtom } from '@yaakapp-internal/models';
|
||||
import { useAtomValue } from 'jotai/index';
|
||||
import { useAtomValue } from 'jotai';
|
||||
|
||||
export function useLatestHttpResponse(requestId: string | null): HttpResponse | null {
|
||||
return useAtomValue(httpResponsesAtom).find((r) => r.requestId === requestId) ?? null;
|
||||
|
||||
@@ -5,8 +5,7 @@ import {
|
||||
grpcEventsAtom,
|
||||
replaceModelsInStore,
|
||||
} from '@yaakapp-internal/models';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import { atom } from 'jotai/index';
|
||||
import { useAtomValue , atom } from 'jotai';
|
||||
import { useEffect } from 'react';
|
||||
import { atomWithKVStorage } from '../lib/atoms/atomWithKVStorage';
|
||||
import { activeRequestIdAtom } from './useActiveRequestId';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { HttpResponse} from '@yaakapp-internal/models';
|
||||
import { httpResponsesAtom } from '@yaakapp-internal/models';
|
||||
import { useAtomValue } from 'jotai/index';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import { useKeyValue } from './useKeyValue';
|
||||
import { useLatestHttpResponse } from './useLatestHttpResponse';
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
websocketConnectionsAtom,
|
||||
websocketEventsAtom,
|
||||
} from '@yaakapp-internal/models';
|
||||
import { atom, useAtomValue } from 'jotai/index';
|
||||
import { atom, useAtomValue } from 'jotai';
|
||||
import { useEffect } from 'react';
|
||||
import { atomWithKVStorage } from '../lib/atoms/atomWithKVStorage';
|
||||
import { jotaiStore } from '../lib/jotai';
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import EventEmitter from 'eventemitter3';
|
||||
import { atom } from 'jotai';
|
||||
import { useAtom } from 'jotai/index';
|
||||
import { atom , useAtom } from 'jotai';
|
||||
import type { DependencyList } from 'react';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { HttpResponse } from '@yaakapp-internal/models';
|
||||
import { getResponseBodyText } from '../lib/responseBody';
|
||||
|
||||
export function useResponseBodyText(response: HttpResponse) {
|
||||
return useQuery<string | null>({
|
||||
return useQuery({
|
||||
placeholderData: (prev) => prev, // Keep previous data on refetch
|
||||
queryKey: ['response-body-text', response.id, response.updatedAt, response.contentLength],
|
||||
queryFn: () => getResponseBodyText(response),
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import type { GetTemplateFunctionsResponse, TemplateFunction } from '@yaakapp-internal/plugins';
|
||||
import { atom, useAtomValue } from 'jotai';
|
||||
import { useSetAtom } from 'jotai/index';
|
||||
import { atom, useAtomValue , useSetAtom } from 'jotai';
|
||||
import { useMemo, useState } from 'react';
|
||||
import type { TwigCompletionOption } from '../components/core/Editor/twig/completion';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { atom } from 'jotai/index';
|
||||
import { atom } from 'jotai';
|
||||
import { getKeyValue, setKeyValue } from '../keyValueStore';
|
||||
|
||||
export function atomWithKVStorage<T extends object | boolean | number | string | null>(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { atom } from 'jotai/index';
|
||||
import { atom } from 'jotai';
|
||||
import type { DialogInstance } from '../components/Dialogs';
|
||||
import { jotaiStore } from './jotai';
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
import { createStore } from 'jotai/index';
|
||||
import { createStore } from 'jotai';
|
||||
|
||||
export const jotaiStore = createStore();
|
||||
|
||||
@@ -5,18 +5,14 @@ import { getCharsetFromContentType } from './model_util';
|
||||
import { invokeCmd } from './tauri';
|
||||
|
||||
export async function getResponseBodyText(response: HttpResponse): Promise<string | null> {
|
||||
if (!response.bodyPath) return null;
|
||||
if (!response.bodyPath) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const bytes = await readFile(response.bodyPath);
|
||||
const charset = getCharsetFromContentType(response.headers);
|
||||
|
||||
try {
|
||||
return new TextDecoder(charset ?? 'utf-8', { fatal: true }).decode(bytes);
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
} catch (err) {
|
||||
// Failed to decode as text, so return null
|
||||
return null;
|
||||
}
|
||||
return new TextDecoder(charset ?? 'utf-8', { fatal: false }).decode(bytes);
|
||||
}
|
||||
|
||||
export async function getResponseBodyBlob(response: HttpResponse): Promise<Uint8Array | null> {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { atom } from 'jotai/index';
|
||||
import { atom } from 'jotai';
|
||||
import type { ToastInstance } from '../components/Toasts';
|
||||
import { generateId } from './generateId';
|
||||
import { jotaiStore } from './jotai';
|
||||
|
||||
Reference in New Issue
Block a user