mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-05-10 09:50:08 +02:00
Migrate to Vite+ unified toolchain (#428)
This commit is contained in:
@@ -143,7 +143,7 @@ export const syncWorkspace = createFastMutation<
|
||||
}
|
||||
|
||||
return (
|
||||
// biome-ignore lint/suspicious/noArrayIndexKey: none
|
||||
// oxlint-disable-next-line react/no-array-index-key
|
||||
<TableRow key={i}>
|
||||
<TableCell className="text-text-subtle">{model}</TableCell>
|
||||
<TruncatedWideTableCell>{name}</TruncatedWideTableCell>
|
||||
|
||||
@@ -19,7 +19,7 @@ export const openWorkspaceFromSyncDir = createFastMutation<void, void, string>({
|
||||
|
||||
await applySync(workspace.id, dir, ops);
|
||||
|
||||
router.navigate({
|
||||
await router.navigate({
|
||||
to: '/workspaces/$workspaceId',
|
||||
params: { workspaceId: workspace.id },
|
||||
});
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { DnsOverride, Workspace } from '@yaakapp-internal/models';
|
||||
import { patchModel } from '@yaakapp-internal/models';
|
||||
import { useCallback, useId, useMemo } from 'react';
|
||||
import { fireAndForget } from '../lib/fireAndForget';
|
||||
import { Button } from './core/Button';
|
||||
import { Checkbox } from './core/Checkbox';
|
||||
import { IconButton } from './core/IconButton';
|
||||
@@ -29,7 +30,7 @@ export function DnsOverridesEditor({ workspace }: Props) {
|
||||
|
||||
const handleChange = useCallback(
|
||||
(overrides: DnsOverride[]) => {
|
||||
patchModel(workspace, { settingDnsOverrides: overrides });
|
||||
fireAndForget(patchModel(workspace, { settingDnsOverrides: overrides }));
|
||||
},
|
||||
[workspace],
|
||||
);
|
||||
|
||||
@@ -512,16 +512,14 @@ function HttpRequestArg({
|
||||
help={arg.description}
|
||||
value={value}
|
||||
disabled={arg.disabled}
|
||||
options={[
|
||||
...httpRequests.map((r) => {
|
||||
options={httpRequests.map((r) => {
|
||||
return {
|
||||
label:
|
||||
buildRequestBreadcrumbs(r, folders).join(' / ') +
|
||||
(r.id === activeHttpRequest?.id ? ' (current)' : ''),
|
||||
value: r.id,
|
||||
};
|
||||
}),
|
||||
]}
|
||||
})}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
useEnvironmentsBreakdown,
|
||||
} from '../hooks/useEnvironmentsBreakdown';
|
||||
import { deleteModelWithConfirm } from '../lib/deleteModelWithConfirm';
|
||||
import { fireAndForget } from '../lib/fireAndForget';
|
||||
import { jotaiStore } from '../lib/jotai';
|
||||
import { isBaseEnvironment, isSubEnvironment } from '../lib/model_util';
|
||||
import { resolvedModelName } from '../lib/resolvedModelName';
|
||||
@@ -112,7 +113,7 @@ function EnvironmentEditDialogSidebar({
|
||||
const treeRef = useRef<TreeHandle>(null);
|
||||
const { baseEnvironment, baseEnvironments } = useEnvironmentsBreakdown();
|
||||
|
||||
// biome-ignore lint/correctness/useExhaustiveDependencies: none
|
||||
// oxlint-disable-next-line react-hooks/exhaustive-deps
|
||||
useLayoutEffect(() => {
|
||||
if (selectedEnvironmentId == null) return;
|
||||
treeRef.current?.selectItem(selectedEnvironmentId);
|
||||
@@ -199,7 +200,7 @@ function EnvironmentEditDialogSidebar({
|
||||
// Not sure why this is needed, but without it the
|
||||
// edit input blurs immediately after opening.
|
||||
requestAnimationFrame(() => {
|
||||
actions['sidebar.selected.rename'].cb(items);
|
||||
fireAndForget(actions['sidebar.selected.rename'].cb(items));
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
@@ -55,7 +55,7 @@ function ExportDataDialogContent({
|
||||
|
||||
const handleToggleAll = () => {
|
||||
setSelectedWorkspaces(
|
||||
// biome-ignore lint/performance/noAccumulatingSpread: none
|
||||
// oxlint-disable-next-line no-accumulating-spread
|
||||
allSelected ? {} : workspaces.reduce((acc, w) => ({ ...acc, [w.id]: true }), {}),
|
||||
);
|
||||
};
|
||||
|
||||
@@ -8,6 +8,7 @@ import { allRequestsAtom } from '../hooks/useAllRequests';
|
||||
import { useFolderActions } from '../hooks/useFolderActions';
|
||||
import { useLatestHttpResponse } from '../hooks/useLatestHttpResponse';
|
||||
import { sendAnyHttpRequest } from '../hooks/useSendAnyHttpRequest';
|
||||
import { fireAndForget } from '../lib/fireAndForget';
|
||||
import { showDialog } from '../lib/dialog';
|
||||
import { resolvedModelName } from '../lib/resolvedModelName';
|
||||
import { router } from '../lib/router';
|
||||
@@ -45,7 +46,7 @@ export function FolderLayout({ folder, style }: Props) {
|
||||
}, [folder.id, folders, requests]);
|
||||
|
||||
const handleSendAll = useCallback(() => {
|
||||
sendAllAction?.call(folder);
|
||||
if (sendAllAction) fireAndForget(sendAllAction.call(folder));
|
||||
}, [sendAllAction, folder]);
|
||||
|
||||
return (
|
||||
|
||||
@@ -103,7 +103,7 @@ function GrpcProtoSelectionDialogWithRequest({ request }: Props & { request: Grp
|
||||
Found services{' '}
|
||||
{services?.slice(0, 5).map((s, i) => {
|
||||
return (
|
||||
<span key={s.name + s.methods.join(',')}>
|
||||
<span key={s.name + s.methods.map((m) => m.name).join(',')}>
|
||||
<InlineCode>{s.name}</InlineCode>
|
||||
{i === services.length - 1 ? '' : i === services.length - 2 ? ' and ' : ', '}
|
||||
</span>
|
||||
@@ -119,7 +119,7 @@ function GrpcProtoSelectionDialogWithRequest({ request }: Props & { request: Grp
|
||||
Server reflection found services
|
||||
{services?.map((s, i) => {
|
||||
return (
|
||||
<span key={s.name + s.methods.join(',')}>
|
||||
<span key={s.name + s.methods.map((m) => m.name).join(',')}>
|
||||
<InlineCode>{s.name}</InlineCode>
|
||||
{i === services.length - 1 ? '' : i === services.length - 2 ? ' and ' : ', '}
|
||||
</span>
|
||||
@@ -144,7 +144,7 @@ function GrpcProtoSelectionDialogWithRequest({ request }: Props & { request: Grp
|
||||
{protoFiles.map((f, i) => {
|
||||
const parts = f.split('/');
|
||||
return (
|
||||
// biome-ignore lint/suspicious/noArrayIndexKey: none
|
||||
// oxlint-disable-next-line react/no-array-index-key
|
||||
<tr key={f + i} className="group">
|
||||
<td>
|
||||
<Icon icon={f.endsWith('.proto') ? 'file_code' : 'folder_code'} />
|
||||
|
||||
@@ -50,7 +50,7 @@ export function GrpcResponsePane({ style, methodType, activeRequest }: Props) {
|
||||
);
|
||||
|
||||
// Set the active message to the first message received if unary
|
||||
// biome-ignore lint/correctness/useExhaustiveDependencies: none
|
||||
// oxlint-disable-next-line react-hooks/exhaustive-deps
|
||||
useEffect(() => {
|
||||
if (events.length === 0 || activeEvent != null || methodType !== 'unary') {
|
||||
return;
|
||||
|
||||
@@ -13,9 +13,9 @@ export function ImportCurlButton() {
|
||||
const importCurl = useImportCurl();
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
// biome-ignore lint/correctness/useExhaustiveDependencies: none
|
||||
// oxlint-disable-next-line react-hooks/exhaustive-deps
|
||||
useEffect(() => {
|
||||
readText().then(setClipboardText);
|
||||
readText().then(setClipboardText).catch(() => {});
|
||||
}, [focused]);
|
||||
|
||||
if (!clipboardText?.trim().startsWith('curl ')) {
|
||||
|
||||
@@ -2,6 +2,7 @@ import { linter } from '@codemirror/lint';
|
||||
import type { HttpRequest } from '@yaakapp-internal/models';
|
||||
import { patchModel } from '@yaakapp-internal/models';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { fireAndForget } from '../lib/fireAndForget';
|
||||
import { useKeyValue } from '../hooks/useKeyValue';
|
||||
import { textLikelyContainsJsonComments } from '../lib/jsonComments';
|
||||
import { Banner } from './core/Banner';
|
||||
@@ -58,12 +59,12 @@ export function JsonBodyEditor({ forceUpdateKey, heightMode, request }: Props) {
|
||||
} else {
|
||||
delete newBody.sendJsonComments;
|
||||
}
|
||||
patchModel(request, { body: newBody });
|
||||
fireAndForget(patchModel(request, { body: newBody }));
|
||||
}, [request, autoFix]);
|
||||
|
||||
const handleDropdownOpen = useCallback(() => {
|
||||
if (!bannerDismissed) {
|
||||
setBannerDismissed(true);
|
||||
fireAndForget(setBannerDismissed(true));
|
||||
}
|
||||
}, [bannerDismissed, setBannerDismissed]);
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@ const markdownComponents: Partial<Components> = {
|
||||
language={match[1]}
|
||||
style={prismTheme}
|
||||
>
|
||||
{String(children).replace(/\n$/, '')}
|
||||
{String(children as string).replace(/\n$/, '')}
|
||||
</SyntaxHighlighter>
|
||||
) : (
|
||||
<code {...extraProps} ref={ref} className={className}>
|
||||
|
||||
@@ -5,6 +5,7 @@ import { getRecentCookieJars } from '../hooks/useRecentCookieJars';
|
||||
import { getRecentEnvironments } from '../hooks/useRecentEnvironments';
|
||||
import { getRecentRequests } from '../hooks/useRecentRequests';
|
||||
import { useRecentWorkspaces } from '../hooks/useRecentWorkspaces';
|
||||
import { fireAndForget } from '../lib/fireAndForget';
|
||||
import { router } from '../lib/router';
|
||||
|
||||
export function RedirectToLatestWorkspace() {
|
||||
@@ -20,7 +21,7 @@ export function RedirectToLatestWorkspace() {
|
||||
return;
|
||||
}
|
||||
|
||||
(async () => {
|
||||
fireAndForget((async () => {
|
||||
const workspaceId = recentWorkspaces[0] ?? workspaces[0]?.id ?? 'n/a';
|
||||
const environmentId = (await getRecentEnvironments(workspaceId))[0] ?? null;
|
||||
const cookieJarId = (await getRecentCookieJars(workspaceId))[0] ?? null;
|
||||
@@ -34,7 +35,7 @@ export function RedirectToLatestWorkspace() {
|
||||
|
||||
console.log('Redirecting to workspace', params, search);
|
||||
await router.navigate({ to: '/workspaces/$workspaceId', params, search });
|
||||
})();
|
||||
})());
|
||||
}, [recentWorkspaces, workspaces, workspaces.length]);
|
||||
|
||||
return null;
|
||||
|
||||
@@ -130,7 +130,7 @@ export function ResponseCookies({ response }: Props) {
|
||||
) : (
|
||||
<KeyValueRows>
|
||||
{sentCookies.map((cookie, i) => (
|
||||
// biome-ignore lint/suspicious/noArrayIndexKey: none
|
||||
// oxlint-disable-next-line react/no-array-index-key
|
||||
<KeyValueRow labelColor="primary" key={i} label={cookie.name}>
|
||||
{cookie.value}
|
||||
</KeyValueRow>
|
||||
@@ -153,7 +153,7 @@ export function ResponseCookies({ response }: Props) {
|
||||
) : (
|
||||
<div className="flex flex-col gap-4">
|
||||
{receivedCookies.map((cookie, i) => (
|
||||
// biome-ignore lint/suspicious/noArrayIndexKey: none
|
||||
// oxlint-disable-next-line react/no-array-index-key
|
||||
<div key={i} className="flex flex-col gap-1">
|
||||
<div className="flex items-center gap-2 my-1">
|
||||
<span
|
||||
|
||||
@@ -62,7 +62,7 @@ export function ResponseHeaders({ response }: Props) {
|
||||
) : (
|
||||
<KeyValueRows>
|
||||
{requestHeaders.map((h, i) => (
|
||||
// biome-ignore lint/suspicious/noArrayIndexKey: none
|
||||
// oxlint-disable-next-line react/no-array-index-key
|
||||
<KeyValueRow labelColor="primary" key={i} label={h.name}>
|
||||
{h.value}
|
||||
</KeyValueRow>
|
||||
@@ -84,7 +84,7 @@ export function ResponseHeaders({ response }: Props) {
|
||||
) : (
|
||||
<KeyValueRows>
|
||||
{responseHeaders.map((h, i) => (
|
||||
// biome-ignore lint/suspicious/noArrayIndexKey: none
|
||||
// oxlint-disable-next-line react/no-array-index-key
|
||||
<KeyValueRow labelColor="info" key={i} label={h.name}>
|
||||
{h.value}
|
||||
</KeyValueRow>
|
||||
|
||||
@@ -7,7 +7,7 @@ import { VStack } from './core/Stacks';
|
||||
export default function RouteError({ error }: { error: unknown }) {
|
||||
console.log('Error', error);
|
||||
const stringified = JSON.stringify(error);
|
||||
// biome-ignore lint/suspicious/noExplicitAny: none
|
||||
// oxlint-disable-next-line no-explicit-any
|
||||
const message = (error as any).message ?? stringified;
|
||||
const stack =
|
||||
typeof error === 'object' && error != null && 'stack' in error ? String(error.stack) : null;
|
||||
|
||||
@@ -238,7 +238,7 @@ export function SettingsCertificates() {
|
||||
<VStack space={3}>
|
||||
{certificates.map((cert, index) => (
|
||||
<CertificateEditor
|
||||
// biome-ignore lint/suspicious/noArrayIndexKey: Index is fine here
|
||||
// oxlint-disable-next-line react/no-array-index-key
|
||||
key={index}
|
||||
certificate={cert}
|
||||
index={index}
|
||||
|
||||
@@ -43,6 +43,7 @@ import { useSidebarHidden } from '../hooks/useSidebarHidden';
|
||||
import { getWebsocketRequestActions } from '../hooks/useWebsocketRequestActions';
|
||||
import { deepEqualAtom } from '../lib/atoms';
|
||||
import { deleteModelWithConfirm } from '../lib/deleteModelWithConfirm';
|
||||
import { fireAndForget } from '../lib/fireAndForget';
|
||||
import { jotaiStore } from '../lib/jotai';
|
||||
import { resolvedModelName } from '../lib/resolvedModelName';
|
||||
import { isSidebarFocused } from '../lib/scopes';
|
||||
@@ -439,7 +440,7 @@ function Sidebar({ className }: { className?: string }) {
|
||||
leftSlot: <Icon icon="arrow_right_circle" />,
|
||||
hidden: workspaces.length <= 1 || requestItems.length === 0 || requestItems.length !== items.length,
|
||||
onSelect: () => {
|
||||
actions['sidebar.selected.move'].cb(items);
|
||||
fireAndForget(actions['sidebar.selected.move'].cb(items));
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -141,7 +141,7 @@ function InitializedTemplateFunctionDialog({
|
||||
});
|
||||
|
||||
const tooLarge = rendered.data ? rendered.data.length > 10000 : false;
|
||||
// biome-ignore lint/correctness/useExhaustiveDependencies: Only update this on rendered data change to keep secrets hidden on input change
|
||||
// oxlint-disable-next-line react-hooks/exhaustive-deps -- Only update this on rendered data change to keep secrets hidden on input change
|
||||
const dataContainsSecrets = useMemo(() => {
|
||||
for (const [name, value] of Object.entries(argValues)) {
|
||||
const arg = templateFunction.data?.args.find((a) => 'name' in a && a.name === name);
|
||||
|
||||
@@ -127,7 +127,7 @@ export function WorkspaceEncryptionSetting({ size, expanded, onDone, onEnabledEn
|
||||
await enableEncryption(workspaceMeta.workspaceId);
|
||||
setJustEnabledEncryption(true);
|
||||
} catch (err) {
|
||||
setError(`Failed to enable encryption: ${err}`);
|
||||
setError(`Failed to enable encryption: ${err instanceof Error ? err.message : String(err)}`);
|
||||
}
|
||||
}}
|
||||
>
|
||||
@@ -285,7 +285,7 @@ function HighlightedKey({ keyText, show }: { keyText: string; show: boolean }) {
|
||||
keyText.split('').map((c, i) => {
|
||||
return (
|
||||
<span
|
||||
// biome-ignore lint/suspicious/noArrayIndexKey: it's fine
|
||||
// oxlint-disable-next-line react/no-array-index-key
|
||||
key={i}
|
||||
className={classNames(
|
||||
c.match(/[0-9]/) && 'text-info',
|
||||
|
||||
@@ -54,7 +54,7 @@ export function AutoScroller<T>({
|
||||
useLayoutEffect(() => {
|
||||
if (!autoScroll) return;
|
||||
|
||||
data.length; // Make linter happy. We want to refresh when length changes
|
||||
void data.length; // Trigger refresh when length changes
|
||||
|
||||
const el = containerRef.current;
|
||||
if (el == null) return;
|
||||
|
||||
@@ -22,7 +22,7 @@ export function DetailsBanner({
|
||||
storageKey,
|
||||
...extraProps
|
||||
}: Props) {
|
||||
// biome-ignore lint/correctness/useExhaustiveDependencies: We only want to recompute the atom when storageKey changes
|
||||
// oxlint-disable-next-line react-hooks/exhaustive-deps -- We only want to recompute the atom when storageKey changes
|
||||
const openAtom = useMemo(
|
||||
() =>
|
||||
storageKey
|
||||
|
||||
@@ -25,6 +25,7 @@ import {
|
||||
} from 'react';
|
||||
import { useKey, useWindowSize } from 'react-use';
|
||||
import { useClickOutside } from '../../hooks/useClickOutside';
|
||||
import { fireAndForget } from '../../lib/fireAndForget';
|
||||
import type { HotkeyAction } from '../../hooks/useHotKey';
|
||||
import { useHotKey } from '../../hooks/useHotKey';
|
||||
import { useStateWithDeps } from '../../hooks/useStateWithDeps';
|
||||
@@ -614,7 +615,7 @@ const Menu = forwardRef<Omit<DropdownRef, 'open' | 'isOpen' | 'toggle' | 'items'
|
||||
setActiveSubmenu({ item, parent, viaKeyboard: true });
|
||||
}
|
||||
} else if (item.onSelect) {
|
||||
handleSelect(item);
|
||||
fireAndForget(handleSelect(item));
|
||||
}
|
||||
},
|
||||
{},
|
||||
@@ -752,7 +753,7 @@ const Menu = forwardRef<Omit<DropdownRef, 'open' | 'isOpen' | 'toggle' | 'items'
|
||||
if (item.type === 'separator') {
|
||||
return (
|
||||
<Separator
|
||||
// biome-ignore lint/suspicious/noArrayIndexKey: Nothing else available
|
||||
// oxlint-disable-next-line react/no-array-index-key -- Nothing else available
|
||||
key={i}
|
||||
className={classNames('my-1.5', item.label ? 'ml-2' : null)}
|
||||
>
|
||||
@@ -762,8 +763,8 @@ const Menu = forwardRef<Omit<DropdownRef, 'open' | 'isOpen' | 'toggle' | 'items'
|
||||
}
|
||||
if (item.type === 'content') {
|
||||
return (
|
||||
// biome-ignore lint/a11y/noStaticElementInteractions: Needs to be clickable but want to support nested buttons
|
||||
// biome-ignore lint/suspicious/noArrayIndexKey: index is fine
|
||||
// oxlint-disable-next-line jsx-a11y/no-static-element-interactions
|
||||
// oxlint-disable-next-line react/no-array-index-key
|
||||
<div key={i} className={classNames('my-1 mx-2 max-w-xs')} onClick={onClose}>
|
||||
{item.label}
|
||||
</div>
|
||||
@@ -777,7 +778,7 @@ const Menu = forwardRef<Omit<DropdownRef, 'open' | 'isOpen' | 'toggle' | 'items'
|
||||
onFocus={handleFocus}
|
||||
onSelect={handleSelect}
|
||||
onHover={handleItemHover}
|
||||
// biome-ignore lint/suspicious/noArrayIndexKey: It's fine
|
||||
// oxlint-disable-next-line react/no-array-index-key
|
||||
key={i}
|
||||
item={item}
|
||||
/>
|
||||
@@ -785,7 +786,7 @@ const Menu = forwardRef<Omit<DropdownRef, 'open' | 'isOpen' | 'toggle' | 'items'
|
||||
})}
|
||||
</VStack>
|
||||
{activeSubmenu && (
|
||||
// biome-ignore lint/a11y/noStaticElementInteractions: Container div that cancels hover timeout
|
||||
// oxlint-disable-next-line jsx-a11y/no-static-element-interactions -- Container div that cancels hover timeout
|
||||
<div
|
||||
ref={submenuRef}
|
||||
onMouseEnter={() => {
|
||||
|
||||
@@ -327,7 +327,7 @@ function EditorInner({
|
||||
);
|
||||
|
||||
// Update the language extension when the language changes
|
||||
// biome-ignore lint/correctness/useExhaustiveDependencies: intentionally limited deps
|
||||
// oxlint-disable-next-line react-hooks/exhaustive-deps -- intentionally limited deps
|
||||
useEffect(() => {
|
||||
if (cm.current === null) return;
|
||||
const { view, languageCompartment } = cm.current;
|
||||
@@ -361,7 +361,7 @@ function EditorInner({
|
||||
]);
|
||||
|
||||
// Initialize the editor when ref mounts
|
||||
// biome-ignore lint/correctness/useExhaustiveDependencies: only reinitialize when necessary
|
||||
// oxlint-disable-next-line react-hooks/exhaustive-deps -- only reinitialize when necessary
|
||||
const initEditorRef = useCallback(
|
||||
function initEditorRef(container: HTMLDivElement | null) {
|
||||
if (container === null) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// biome-ignore-all lint: Disable for generated file
|
||||
/* oxlint-disable */
|
||||
// This file was generated by lezer-generator. You probably shouldn't edit it.
|
||||
import { LRParser } from '@lezer/lr';
|
||||
import { highlight } from './highlight';
|
||||
|
||||
@@ -14,7 +14,7 @@ const tooltip = hoverTooltip(
|
||||
let match: RegExpExecArray | null;
|
||||
let found: { start: number; end: number } | null = null;
|
||||
|
||||
// biome-ignore lint/suspicious/noAssignInExpressions: none
|
||||
// oxlint-disable-next-line no-cond-assign
|
||||
while ((match = REGEX.exec(text))) {
|
||||
const start = from + match.index;
|
||||
const end = start + match[0].length;
|
||||
|
||||
@@ -20,7 +20,7 @@ export function jsonParseLinter(options?: JsonLintOptions) {
|
||||
mode: (options?.allowComments ?? true) ? 'cjson' : 'json',
|
||||
ignoreTrailingCommas: options?.allowTrailingCommas ?? false,
|
||||
});
|
||||
// biome-ignore lint/suspicious/noExplicitAny: none
|
||||
// oxlint-disable-next-line no-explicit-any
|
||||
} catch (err: any) {
|
||||
if (!('location' in err)) {
|
||||
return [];
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// biome-ignore-all lint/suspicious/noTemplateCurlyInString: We're testing this, specifically
|
||||
/* oxlint-disable no-template-curly-in-string */
|
||||
|
||||
import { describe, expect, test } from 'vitest';
|
||||
import { describe, expect, test } from 'vite-plus/test';
|
||||
import { parser } from './twig';
|
||||
|
||||
function getNodeNames(input: string): string[] {
|
||||
|
||||
@@ -35,7 +35,7 @@ export function HotkeyRaw({ labelParts, className, variant }: HotkeyRawProps) {
|
||||
)}
|
||||
>
|
||||
{labelParts.map((char, index) => (
|
||||
// biome-ignore lint/suspicious/noArrayIndexKey: none
|
||||
// oxlint-disable-next-line react/no-array-index-key
|
||||
<div key={index} className="min-w-[1em] text-center">
|
||||
{char}
|
||||
</div>
|
||||
|
||||
@@ -144,7 +144,7 @@ function BaseInput({
|
||||
isFocused: () => editorRef.current?.hasFocus ?? false,
|
||||
value: () => editorRef.current?.state.doc.toString() ?? '',
|
||||
dispatch: (...args) => {
|
||||
// biome-ignore lint/suspicious/noExplicitAny: none
|
||||
// oxlint-disable-next-line no-explicit-any
|
||||
editorRef.current?.dispatch(...(args as any));
|
||||
},
|
||||
selectAll() {
|
||||
@@ -329,7 +329,7 @@ function BaseInput({
|
||||
</HStack>
|
||||
{type === 'password' && !disableObscureToggle && (
|
||||
<IconButton
|
||||
title={obscured ? `Show ${label}` : `Obscure ${label}`}
|
||||
title={obscured ? `Show ${typeof label === 'string' ? label : 'field'}` : `Obscure ${typeof label === 'string' ? label : 'field'}`}
|
||||
size="xs"
|
||||
className={classNames('mr-0.5 !h-auto my-0.5', disabled && 'opacity-disabled')}
|
||||
color={tint}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Icon } from './Icon';
|
||||
|
||||
interface Props {
|
||||
depth?: number;
|
||||
// biome-ignore lint/suspicious/noExplicitAny: none
|
||||
// oxlint-disable-next-line no-explicit-any
|
||||
attrValue: any;
|
||||
attrKey?: string | number;
|
||||
attrKeyJsonPath?: string;
|
||||
@@ -54,10 +54,10 @@ export const JsonAttributeTree = ({
|
||||
if (jsonType === '[object Array]') {
|
||||
return {
|
||||
children: isExpanded
|
||||
? // biome-ignore lint/suspicious/noExplicitAny: none
|
||||
? // oxlint-disable-next-line no-explicit-any
|
||||
attrValue.flatMap((v: any, i: number) => (
|
||||
<JsonAttributeTree
|
||||
// biome-ignore lint/suspicious/noArrayIndexKey: none
|
||||
// oxlint-disable-next-line react/no-array-index-key
|
||||
key={i}
|
||||
depth={depth + 1}
|
||||
attrValue={v}
|
||||
|
||||
@@ -13,7 +13,7 @@ export function KeyValueRows({ children }: Props) {
|
||||
<table className="text-editor font-mono min-w-0 w-full mb-auto">
|
||||
<tbody className="divide-y divide-surface-highlight">
|
||||
{childArray.map((child, i) => (
|
||||
// biome-ignore lint/suspicious/noArrayIndexKey: none
|
||||
// oxlint-disable-next-line react/no-array-index-key
|
||||
<tr key={i}>{child}</tr>
|
||||
))}
|
||||
</tbody>
|
||||
|
||||
@@ -37,7 +37,7 @@ export function Label({
|
||||
{required === true && <span className="text-text-subtlest">*</span>}
|
||||
</span>
|
||||
{tags.map((tag, i) => (
|
||||
// biome-ignore lint/suspicious/noArrayIndexKey: none
|
||||
// oxlint-disable-next-line react/no-array-index-key
|
||||
<span key={i} className="text-xs text-text-subtlest">
|
||||
({tag})
|
||||
</span>
|
||||
|
||||
@@ -145,7 +145,7 @@ export function PairEditor({
|
||||
[handle, pairs, setRef],
|
||||
);
|
||||
|
||||
// biome-ignore lint/correctness/useExhaustiveDependencies: Only care about forceUpdateKey
|
||||
// oxlint-disable-next-line react-hooks/exhaustive-deps -- Only care about forceUpdateKey
|
||||
useEffect(() => {
|
||||
// Remove empty headers on initial render and ensure they all have valid ids (pairs didn't use to have IDs)
|
||||
const newPairs: PairWithId[] = [];
|
||||
|
||||
@@ -195,7 +195,7 @@ export const PlainInput = forwardRef<{ focus: () => void }, PlainInputProps>(fun
|
||||
key={forceUpdateKey}
|
||||
type={type === 'password' && !obscured ? 'text' : type}
|
||||
name={name}
|
||||
// biome-ignore lint/a11y/noAutofocus: Who cares
|
||||
// oxlint-disable-next-line jsx-a11y/no-autofocus
|
||||
autoFocus={autoFocus}
|
||||
defaultValue={defaultValue ?? undefined}
|
||||
autoComplete="off"
|
||||
@@ -213,7 +213,7 @@ export const PlainInput = forwardRef<{ focus: () => void }, PlainInputProps>(fun
|
||||
</HStack>
|
||||
{type === 'password' && !hideObscureToggle && (
|
||||
<IconButton
|
||||
title={obscured ? `Show ${label}` : `Obscure ${label}`}
|
||||
title={obscured ? `Show ${typeof label === 'string' ? label : 'field'}` : `Obscure ${typeof label === 'string' ? label : 'field'}`}
|
||||
size="xs"
|
||||
className="mr-0.5 group/obscure !h-auto my-0.5"
|
||||
iconClassName="group-hover/obscure:text"
|
||||
|
||||
@@ -62,13 +62,13 @@ export function SegmentedControl<T extends string>({
|
||||
if (e.key === 'ArrowRight') {
|
||||
e.preventDefault();
|
||||
const newIndex = Math.abs((selectedIndex + 1) % options.length);
|
||||
options[newIndex] && setSelectedValue(options[newIndex].value);
|
||||
if (options[newIndex]) setSelectedValue(options[newIndex].value);
|
||||
const child = containerRef.current?.children[newIndex] as HTMLButtonElement;
|
||||
child.focus();
|
||||
} else if (e.key === 'ArrowLeft') {
|
||||
e.preventDefault();
|
||||
const newIndex = Math.abs((selectedIndex - 1) % options.length);
|
||||
options[newIndex] && setSelectedValue(options[newIndex].value);
|
||||
if (options[newIndex]) setSelectedValue(options[newIndex].value);
|
||||
const child = containerRef.current?.children[newIndex] as HTMLButtonElement;
|
||||
child.focus();
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ interface HStackProps extends BaseStackProps {
|
||||
|
||||
export const HStack = forwardRef(function HStack(
|
||||
{ className, space, children, alignItems = 'center', ...props }: HStackProps,
|
||||
// biome-ignore lint/suspicious/noExplicitAny: none
|
||||
// oxlint-disable-next-line no-explicit-any
|
||||
ref: ForwardedRef<any>,
|
||||
) {
|
||||
return (
|
||||
@@ -41,7 +41,7 @@ export type VStackProps = BaseStackProps & {
|
||||
|
||||
export const VStack = forwardRef(function VStack(
|
||||
{ className, space, children, ...props }: VStackProps,
|
||||
// biome-ignore lint/suspicious/noExplicitAny: none
|
||||
// oxlint-disable-next-line no-explicit-any
|
||||
ref: ForwardedRef<any>,
|
||||
) {
|
||||
return (
|
||||
@@ -65,7 +65,7 @@ type BaseStackProps = HTMLAttributes<HTMLElement> & {
|
||||
|
||||
const BaseStack = forwardRef(function BaseStack(
|
||||
{ className, alignItems, justifyContent, wrap, children, as, ...props }: BaseStackProps,
|
||||
// biome-ignore lint/suspicious/noExplicitAny: none
|
||||
// oxlint-disable-next-line no-explicit-any
|
||||
ref: ForwardedRef<any>,
|
||||
) {
|
||||
const Component = as ?? 'div';
|
||||
|
||||
@@ -22,6 +22,7 @@ import {
|
||||
useState,
|
||||
} from 'react';
|
||||
import { useKeyValue } from '../../../hooks/useKeyValue';
|
||||
import { fireAndForget } from '../../../lib/fireAndForget';
|
||||
import { computeSideForDragMove } from '../../../lib/dnd';
|
||||
import { DropMarker } from '../../DropMarker';
|
||||
import { ErrorBoundary } from '../../ErrorBoundary';
|
||||
@@ -143,7 +144,7 @@ export const Tabs = forwardRef<TabsRef, Props>(function Tabs(
|
||||
forwardedRef,
|
||||
() => ({
|
||||
setActiveTab: (value: string) => {
|
||||
onChangeValue(value);
|
||||
fireAndForget(onChangeValue(value));
|
||||
},
|
||||
}),
|
||||
[onChangeValue],
|
||||
|
||||
@@ -110,7 +110,7 @@ export function Tooltip({ children, className, content, tabIndex, size = 'md' }:
|
||||
/>
|
||||
</div>
|
||||
</Portal>
|
||||
{/** biome-ignore lint/a11y/useSemanticElements: Needs to be usable in other buttons */}
|
||||
{/* oxlint-disable-next-line jsx-a11y/prefer-tag-over-role -- Needs to be usable in other buttons */}
|
||||
<span
|
||||
ref={triggerRef}
|
||||
role="button"
|
||||
|
||||
@@ -111,7 +111,7 @@ function TreeInner<T extends { id: string }>(
|
||||
}, []);
|
||||
|
||||
// Select the first item on first render
|
||||
// biome-ignore lint/correctness/useExhaustiveDependencies: Only used for initial render
|
||||
// oxlint-disable-next-line react-hooks/exhaustive-deps -- Only used for initial render
|
||||
useEffect(() => {
|
||||
const ids = jotaiStore.get(selectedIdsFamily(treeId));
|
||||
const fallback = selectableItems[0];
|
||||
@@ -736,7 +736,7 @@ function DropRegionAfterList({
|
||||
onContextMenu?: (e: MouseEvent<HTMLDivElement>) => void;
|
||||
}) {
|
||||
const { setNodeRef } = useDroppable({ id });
|
||||
// biome-ignore lint/a11y/noStaticElementInteractions: Meh
|
||||
// oxlint-disable-next-line jsx-a11y/no-static-element-interactions
|
||||
return <div ref={setNodeRef} onContextMenu={onContextMenu} />;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ export const TreeIndentGuide = memo(function TreeIndentGuide({
|
||||
<div className="flex">
|
||||
{Array.from({ length: depth }).map((_, i) => (
|
||||
<div
|
||||
// biome-ignore lint/suspicious/noArrayIndexKey: none
|
||||
// oxlint-disable-next-line react/no-array-index-key
|
||||
key={i}
|
||||
className={classNames(
|
||||
'w-[calc(1rem+0.5px)] border-r border-r-text-subtlest',
|
||||
|
||||
@@ -41,7 +41,7 @@ export function equalSubtree<T extends { id: string }>(
|
||||
}
|
||||
|
||||
for (let i = 0; i < ak.length; i++) {
|
||||
// biome-ignore lint/style/noNonNullAssertion: none
|
||||
// oxlint-disable-next-line no-non-null-assertion
|
||||
if (!equalSubtree(ak[i]!, bk[i]!, getItemKey)) return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import { useRandomKey } from '../../hooks/useRandomKey';
|
||||
import { sync } from '../../init/sync';
|
||||
import { showConfirm, showConfirmDelete } from '../../lib/confirm';
|
||||
import { showDialog } from '../../lib/dialog';
|
||||
import { fireAndForget } from '../../lib/fireAndForget';
|
||||
import { showPrompt } from '../../lib/prompt';
|
||||
import { showErrorToast, showToast } from '../../lib/toast';
|
||||
import { Banner } from '../core/Banner';
|
||||
@@ -246,7 +247,7 @@ function SyncDropdownWithSyncDir({ syncDir }: { syncDir: string }) {
|
||||
message: 'Changes have been reset',
|
||||
color: 'success',
|
||||
});
|
||||
sync({ force: true });
|
||||
fireAndForget(sync({ force: true }));
|
||||
},
|
||||
onError(err) {
|
||||
showErrorToast({
|
||||
@@ -293,7 +294,7 @@ function SyncDropdownWithSyncDir({ syncDir }: { syncDir: string }) {
|
||||
</>
|
||||
),
|
||||
});
|
||||
sync({ force: true });
|
||||
fireAndForget(sync({ force: true }));
|
||||
},
|
||||
onError(err) {
|
||||
showErrorToast({
|
||||
|
||||
@@ -27,7 +27,7 @@ export function HistoryDialog({ log }: Props) {
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{log.map((l) => (
|
||||
<TableRow key={l.author + (l.message ?? 'n/a') + l.when}>
|
||||
<TableRow key={(l.author.name ?? '') + (l.author.email ?? '') + (l.message ?? 'n/a') + l.when}>
|
||||
<TruncatedWideTableCell>
|
||||
{l.message || <em className="text-text-subtle">No message</em>}
|
||||
</TruncatedWideTableCell>
|
||||
|
||||
@@ -45,7 +45,7 @@ interface Props {
|
||||
|
||||
type ExplorerItem =
|
||||
| { kind: 'type'; type: GraphQLType; from: ExplorerItem }
|
||||
// biome-ignore lint/suspicious/noExplicitAny: none
|
||||
// oxlint-disable-next-line no-explicit-any
|
||||
| { kind: 'field'; type: GraphQLField<any, any>; from: ExplorerItem }
|
||||
| { kind: 'input_field'; type: GraphQLInputField; from: ExplorerItem }
|
||||
| null;
|
||||
@@ -146,7 +146,7 @@ export const GraphQLDocsExplorer = memo(function GraphQLDocsExplorer({
|
||||
</div>
|
||||
) : (
|
||||
<div
|
||||
key={activeItem.type.toString()} // Reset scroll position to top
|
||||
key={'name' in activeItem.type ? activeItem.type.name : String(activeItem.type)} // Reset scroll position to top
|
||||
className="overflow-y-auto h-full w-full p-3 grid grid-cols-[minmax(0,1fr)]"
|
||||
>
|
||||
<GqlTypeInfo item={activeItem} setItem={setActiveItem} schema={schema} />
|
||||
@@ -182,14 +182,14 @@ function GraphQLExplorerHeader({
|
||||
<Icon icon="book_open_text" />
|
||||
{crumbs.map((crumb, i) => {
|
||||
return (
|
||||
// biome-ignore lint/suspicious/noArrayIndexKey: none
|
||||
// oxlint-disable-next-line react/no-array-index-key
|
||||
<Fragment key={i}>
|
||||
{i > 0 && <Icon icon="chevron_right" className="text-text-subtlest" />}
|
||||
{crumb === item || item == null ? (
|
||||
<GqlTypeLabel noTruncate item={item} />
|
||||
) : crumb === item ? null : (
|
||||
<GqlTypeLink
|
||||
// biome-ignore lint/suspicious/noArrayIndexKey: none
|
||||
// oxlint-disable-next-line react/no-array-index-key
|
||||
key={i}
|
||||
noTruncate
|
||||
item={crumb}
|
||||
@@ -202,7 +202,7 @@ function GraphQLExplorerHeader({
|
||||
})}
|
||||
</div>
|
||||
<GqlSchemaSearch
|
||||
key={item?.type.toString()} // Force reset when changing items
|
||||
key={item != null && 'name' in item.type ? item.type.name : 'search'} // Force reset when changing items
|
||||
maxHeight={containerHeight}
|
||||
currentItem={item}
|
||||
schema={schema}
|
||||
@@ -270,7 +270,7 @@ function GqlTypeInfo({
|
||||
{Object.entries(fields).map(([fieldName, field]) => {
|
||||
const fieldItem: ExplorerItem = toExplorerItem(field, item);
|
||||
return (
|
||||
<div key={`${field.type}::${field.name}`} className="my-4">
|
||||
<div key={`${String(field.type)}::${field.name}`} className="my-4">
|
||||
<GqlTypeRow
|
||||
item={fieldItem}
|
||||
setItem={setItem}
|
||||
@@ -363,7 +363,7 @@ function GqlTypeInfo({
|
||||
<Subheading>Arguments</Subheading>
|
||||
{item.type.args.map((a) => {
|
||||
return (
|
||||
<div key={`${a.type}::${a.name}`} className="my-4">
|
||||
<div key={`${String(a.type)}::${a.name}`} className="my-4">
|
||||
<GqlTypeRow
|
||||
name={{ value: a.name, color: 'info' }}
|
||||
item={{ kind: 'type', type: a.type, from: item }}
|
||||
@@ -393,7 +393,7 @@ function GqlTypeInfo({
|
||||
from: item,
|
||||
};
|
||||
return (
|
||||
<div key={`${field.type}::${field.name}`} className="my-4">
|
||||
<div key={`${String(field.type)}::${field.name}`} className="my-4">
|
||||
<GqlTypeRow
|
||||
item={fieldItem}
|
||||
setItem={setItem}
|
||||
@@ -431,7 +431,7 @@ function GqlTypeInfo({
|
||||
if (field == null) return null;
|
||||
const fieldItem: ExplorerItem = { kind: 'field', type: field, from: item };
|
||||
return (
|
||||
<div key={`${field.type}::${field.name}`} className="my-4">
|
||||
<div key={`${String(field.type)}::${field.name}`} className="my-4">
|
||||
<GqlTypeRow
|
||||
item={fieldItem}
|
||||
setItem={setItem}
|
||||
@@ -512,7 +512,7 @@ function GqlTypeRow({
|
||||
<span className="text-text-subtle">(</span>
|
||||
{item.type.args.map((arg) => (
|
||||
<div
|
||||
key={`${arg.type}::${arg.name}`}
|
||||
key={`${String(arg.type)}::${arg.name}`}
|
||||
className={classNames(item.type.args.length === 1 && 'inline-flex')}
|
||||
>
|
||||
{item.type.args.length > 1 && <> </>}
|
||||
@@ -674,7 +674,7 @@ function Subheading({ children, count }: { children: ReactNode; count?: number }
|
||||
|
||||
interface SearchResult {
|
||||
name: string;
|
||||
// biome-ignore lint/suspicious/noExplicitAny: none
|
||||
// oxlint-disable-next-line no-explicit-any
|
||||
type: GraphQLNamedType | GraphQLField<any, any> | GraphQLInputField;
|
||||
score: number;
|
||||
from: GraphQLNamedType | null;
|
||||
@@ -798,7 +798,7 @@ function GqlSchemaSearch({
|
||||
label="search"
|
||||
hideLabel
|
||||
defaultValue={value}
|
||||
placeholder={focused ? `Search ${currentItem?.type.toString() ?? 'Schema'}` : 'Search'}
|
||||
placeholder={focused ? `Search ${currentItem != null && 'name' in currentItem.type ? currentItem.type.name : 'Schema'}` : 'Search'}
|
||||
leftSlot={
|
||||
<div className="w-10 flex justify-center items-center">
|
||||
<Icon size="sm" icon="search" color="secondary" />
|
||||
@@ -897,10 +897,10 @@ function DocMarkdown({ children, className }: { children: string | null; classNa
|
||||
|
||||
function walkTypeGraph(
|
||||
schema: GraphQLSchema,
|
||||
// biome-ignore lint/suspicious/noExplicitAny: none
|
||||
// oxlint-disable-next-line no-explicit-any
|
||||
start: GraphQLType | GraphQLField<any, any> | GraphQLInputField | null,
|
||||
cb: (
|
||||
// biome-ignore lint/suspicious/noExplicitAny: none
|
||||
// oxlint-disable-next-line no-explicit-any
|
||||
type: GraphQLNamedType | GraphQLField<any, any> | GraphQLInputField,
|
||||
from: GraphQLNamedType | null,
|
||||
path: string[],
|
||||
@@ -908,7 +908,7 @@ function walkTypeGraph(
|
||||
) {
|
||||
const visited = new Set<string>();
|
||||
const queue: Array<{
|
||||
// biome-ignore lint/suspicious/noExplicitAny: none
|
||||
// oxlint-disable-next-line no-explicit-any
|
||||
current: GraphQLType | GraphQLField<any, any> | GraphQLInputField;
|
||||
from: GraphQLNamedType | null;
|
||||
path: string[];
|
||||
@@ -928,7 +928,7 @@ function walkTypeGraph(
|
||||
}
|
||||
|
||||
while (queue.length > 0) {
|
||||
// biome-ignore lint/style/noNonNullAssertion: none
|
||||
// oxlint-disable-next-line no-non-null-assertion
|
||||
const { current, from, path } = queue.shift()!;
|
||||
if (!isNamedType(current)) continue;
|
||||
|
||||
@@ -981,7 +981,7 @@ function walkTypeGraph(
|
||||
}
|
||||
}
|
||||
|
||||
// biome-ignore lint/suspicious/noExplicitAny: none
|
||||
// oxlint-disable-next-line no-explicit-any
|
||||
function toExplorerItem(t: any, from: ExplorerItem | null): ExplorerItem | null {
|
||||
if (t == null) return null;
|
||||
|
||||
|
||||
@@ -22,6 +22,6 @@ export function AudioViewer({ bodyPath, data }: Props) {
|
||||
}
|
||||
}, [bodyPath, data]);
|
||||
|
||||
// biome-ignore lint/a11y/useMediaCaption: none
|
||||
// oxlint-disable-next-line jsx-a11y/media-has-caption
|
||||
return <audio className="w-full" controls src={src} />;
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ export function CsvViewerInner({ text, className }: { text: string | null; class
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{parsed.data.map((row, i) => (
|
||||
// biome-ignore lint/suspicious/noArrayIndexKey: none
|
||||
// oxlint-disable-next-line react/no-array-index-key
|
||||
<TableRow key={i}>
|
||||
{parsed.meta.fields?.map((key) => (
|
||||
<TableCell key={key}>{row[key] ?? ''}</TableCell>
|
||||
|
||||
@@ -75,7 +75,7 @@ export function MultipartViewer({ data, boundary, idPrefix = 'multipart' }: Prop
|
||||
>
|
||||
{parts.map((part, i) => (
|
||||
<TabContent
|
||||
// biome-ignore lint/suspicious/noArrayIndexKey: Nothing else to key on
|
||||
// oxlint-disable-next-line react/no-array-index-key -- Nothing else to key on
|
||||
key={idPrefix + part.name + i}
|
||||
value={tabValue(part, i)}
|
||||
className="pl-3 !pt-0"
|
||||
|
||||
@@ -6,13 +6,14 @@ import type { PDFDocumentProxy } from 'pdfjs-dist';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { Document, Page } from 'react-pdf';
|
||||
import { useContainerSize } from '../../hooks/useContainerQuery';
|
||||
import { fireAndForget } from '../../lib/fireAndForget';
|
||||
|
||||
import('react-pdf').then(({ pdfjs }) => {
|
||||
fireAndForget(import('react-pdf').then(({ pdfjs }) => {
|
||||
pdfjs.GlobalWorkerOptions.workerSrc = new URL(
|
||||
'pdfjs-dist/build/pdf.worker.min.mjs',
|
||||
import.meta.url,
|
||||
).toString();
|
||||
});
|
||||
}));
|
||||
|
||||
interface Props {
|
||||
bodyPath?: string;
|
||||
@@ -56,7 +57,7 @@ export function PdfViewer({ bodyPath, data }: Props) {
|
||||
externalLinkTarget="_blank"
|
||||
externalLinkRel="noopener noreferrer"
|
||||
>
|
||||
{Array.from(new Array(numPages), (_, index) => (
|
||||
{Array.from({ length: numPages ?? 0 }, (_, index) => (
|
||||
<Page
|
||||
className="mb-6 select-all"
|
||||
renderTextLayer
|
||||
|
||||
@@ -22,6 +22,6 @@ export function VideoViewer({ bodyPath, data }: Props) {
|
||||
}
|
||||
}, [bodyPath, data]);
|
||||
|
||||
// biome-ignore lint/a11y/useMediaCaption: none
|
||||
// oxlint-disable-next-line jsx-a11y/media-has-caption
|
||||
return <video className="w-full" controls src={src} />;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Listen for settings changes, the re-compute theme
|
||||
import { listen } from '@tauri-apps/api/event';
|
||||
import type { ModelPayload } from '@yaakapp-internal/models';
|
||||
import { fireAndForget } from './lib/fireAndForget';
|
||||
import { getSettings } from './lib/settings';
|
||||
|
||||
function setFontSizeOnDocument(fontSize: number) {
|
||||
@@ -13,4 +14,4 @@ listen<ModelPayload>('model_write', async (event) => {
|
||||
setFontSizeOnDocument(event.payload.model.interfaceFontSize);
|
||||
}).catch(console.error);
|
||||
|
||||
getSettings().then((settings) => setFontSizeOnDocument(settings.interfaceFontSize));
|
||||
fireAndForget(getSettings().then((settings) => setFontSizeOnDocument(settings.interfaceFontSize)));
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Listen for settings changes, the re-compute theme
|
||||
import { listen } from '@tauri-apps/api/event';
|
||||
import type { ModelPayload, Settings } from '@yaakapp-internal/models';
|
||||
import { fireAndForget } from './lib/fireAndForget';
|
||||
import { getSettings } from './lib/settings';
|
||||
|
||||
function setFonts(settings: Settings) {
|
||||
@@ -17,4 +18,4 @@ listen<ModelPayload>('model_write', async (event) => {
|
||||
setFonts(event.payload.model);
|
||||
}).catch(console.error);
|
||||
|
||||
getSettings().then((settings) => setFonts(settings));
|
||||
fireAndForget(getSettings().then((settings) => setFonts(settings)));
|
||||
|
||||
@@ -37,7 +37,7 @@ export function useEnsureActiveCookieJar() {
|
||||
// things change when switching workspaces, and we don't currently have a good way to ensure that all
|
||||
// stores have updated.
|
||||
// TODO: Create a global data store that can handle this case
|
||||
// biome-ignore lint/correctness/useExhaustiveDependencies: none
|
||||
// oxlint-disable-next-line react-hooks/exhaustive-deps
|
||||
useEffect(() => {
|
||||
if (cookieJars == null) return; // Hasn't loaded yet
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ interface TypeMap {
|
||||
}
|
||||
|
||||
export function useActiveRequest<T extends keyof TypeMap>(
|
||||
model?: T | undefined,
|
||||
model?: T,
|
||||
): TypeMap[T] | null {
|
||||
const activeRequest = useAtomValue(activeRequestAtom);
|
||||
if (model == null) return activeRequest as TypeMap[T];
|
||||
|
||||
@@ -18,7 +18,7 @@ export function useCreateDropdownItems({
|
||||
}: {
|
||||
hideFolder?: boolean;
|
||||
hideIcons?: boolean;
|
||||
folderId?: string | null | 'active-folder';
|
||||
folderId?: string | null;
|
||||
} = {}): DropdownItem[] {
|
||||
const workspaceId = useAtomValue(activeWorkspaceIdAtom);
|
||||
const activeRequest = useAtomValue(activeRequestAtom);
|
||||
@@ -40,7 +40,7 @@ export function getCreateDropdownItems({
|
||||
}: {
|
||||
hideFolder?: boolean;
|
||||
hideIcons?: boolean;
|
||||
folderId?: string | null | 'active-folder';
|
||||
folderId?: string | null;
|
||||
workspaceId: string | null;
|
||||
activeRequest: HttpRequest | GrpcRequest | WebsocketRequest | null;
|
||||
onCreate?: (
|
||||
|
||||
@@ -42,7 +42,7 @@ export function createFastMutation<TData = unknown, TError = unknown, TVariables
|
||||
if (!disableToastError) {
|
||||
showToast({
|
||||
id: stringKey,
|
||||
message: `${err}`,
|
||||
message: err instanceof Error ? err.message : String(err),
|
||||
color: 'danger',
|
||||
timeout: 5000,
|
||||
});
|
||||
@@ -71,6 +71,6 @@ export function useFastMutation<TData = unknown, TError = unknown, TVariables =
|
||||
) {
|
||||
return useMemo(() => {
|
||||
return createFastMutation(defaultArgs);
|
||||
// biome-ignore lint/correctness/useExhaustiveDependencies: Force it!
|
||||
// oxlint-disable-next-line react-hooks/exhaustive-deps -- Force it!
|
||||
}, defaultArgs.mutationKey);
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ export function useFolderActions() {
|
||||
queryFn: () => getFolderActions(),
|
||||
});
|
||||
|
||||
// biome-ignore lint/correctness/useExhaustiveDependencies: none
|
||||
// oxlint-disable-next-line react-hooks/exhaustive-deps
|
||||
const actions = useMemo(() => {
|
||||
return actionsResult.data ?? [];
|
||||
}, [JSON.stringify(actionsResult.data)]);
|
||||
|
||||
@@ -24,7 +24,7 @@ export function useGrpcRequestActions() {
|
||||
},
|
||||
});
|
||||
|
||||
// biome-ignore lint/correctness/useExhaustiveDependencies: none
|
||||
// oxlint-disable-next-line react-hooks/exhaustive-deps
|
||||
const actions = useMemo(() => {
|
||||
return actionsResult.data ?? [];
|
||||
}, [JSON.stringify(actionsResult.data)]);
|
||||
|
||||
@@ -21,7 +21,7 @@ export function useHttpRequestActions() {
|
||||
queryFn: () => getHttpRequestActions(),
|
||||
});
|
||||
|
||||
// biome-ignore lint/correctness/useExhaustiveDependencies: none
|
||||
// oxlint-disable-next-line react-hooks/exhaustive-deps
|
||||
const actions = useMemo(() => {
|
||||
return actionsResult.data ?? [];
|
||||
}, [JSON.stringify(actionsResult.data)]);
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
} from '@yaakapp-internal/models';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import { useEffect } from 'react';
|
||||
import { fireAndForget } from '../lib/fireAndForget';
|
||||
|
||||
export function useHttpResponseEvents(response: HttpResponse | null) {
|
||||
const allEvents = useAtomValue(httpResponseEventsAtom);
|
||||
@@ -18,10 +19,10 @@ export function useHttpResponseEvents(response: HttpResponse | null) {
|
||||
}
|
||||
|
||||
// Fetch events from database, filtering out events from other responses and merging atomically
|
||||
invoke<HttpResponseEvent[]>('cmd_get_http_response_events', { responseId: response.id }).then(
|
||||
fireAndForget(invoke<HttpResponseEvent[]>('cmd_get_http_response_events', { responseId: response.id }).then(
|
||||
(events) =>
|
||||
mergeModelsInStore('http_response_event', events, (e) => e.responseId === response.id),
|
||||
);
|
||||
));
|
||||
}, [response?.id]);
|
||||
|
||||
const events = allEvents.filter((e) => e.responseId === response?.id);
|
||||
|
||||
@@ -86,7 +86,7 @@ export function useIntrospectGraphQL(
|
||||
}
|
||||
}, [activeEnvironment?.id, baseRequest, upsertIntrospection]);
|
||||
|
||||
// biome-ignore lint/correctness/useExhaustiveDependencies: none
|
||||
// oxlint-disable-next-line react-hooks/exhaustive-deps
|
||||
useEffect(() => {
|
||||
// Skip introspection if automatic is disabled and we already have one
|
||||
if (options.disabled) {
|
||||
@@ -144,14 +144,14 @@ function tryParseIntrospectionToSchema(
|
||||
let parsedResponse: IntrospectionQuery;
|
||||
try {
|
||||
parsedResponse = JSON.parse(content).data;
|
||||
// biome-ignore lint/suspicious/noExplicitAny: none
|
||||
// oxlint-disable-next-line no-explicit-any
|
||||
} catch (e: any) {
|
||||
return { error: String('message' in e ? e.message : e) };
|
||||
}
|
||||
|
||||
try {
|
||||
return { schema: buildClientSchema(parsedResponse, {}) };
|
||||
// biome-ignore lint/suspicious/noExplicitAny: none
|
||||
// oxlint-disable-next-line no-explicit-any
|
||||
} catch (e: any) {
|
||||
return { error: String('message' in e ? e.message : e) };
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ export function useKeyValue<T extends object | boolean | number | string | null>
|
||||
fallback: T;
|
||||
}) {
|
||||
const { value, isLoading } = useAtomValue(
|
||||
// biome-ignore lint/correctness/useExhaustiveDependencies: Only create a new atom when the key changes. Fallback might not be a stable reference, so we don't want to refresh on that.
|
||||
// oxlint-disable-next-line react-hooks/exhaustive-deps -- Only create a new atom when the key changes. Fallback might not be a stable reference, so we don't want to refresh on that.
|
||||
useMemo(
|
||||
() =>
|
||||
selectAtom(
|
||||
@@ -42,7 +42,7 @@ export function useKeyValue<T extends object | boolean | number | string | null>
|
||||
mutationFn: (value) => setKeyValue<T>({ namespace, key, value }),
|
||||
});
|
||||
|
||||
// biome-ignore lint/correctness/useExhaustiveDependencies: none
|
||||
// oxlint-disable-next-line react-hooks/exhaustive-deps
|
||||
const set = useCallback(
|
||||
async (valueOrUpdate: ((v: T) => T) | T) => {
|
||||
if (typeof valueOrUpdate === 'function') {
|
||||
|
||||
@@ -5,7 +5,7 @@ export function useKeyboardEvent(
|
||||
key: KeyboardEvent['key'],
|
||||
cb: () => void,
|
||||
) {
|
||||
// biome-ignore lint/correctness/useExhaustiveDependencies: Don't have `cb` as a dep for caller convenience
|
||||
// oxlint-disable-next-line react-hooks/exhaustive-deps -- Don't have `cb` as a dep for caller convenience
|
||||
useEffect(() => {
|
||||
const fn = (e: KeyboardEvent) => {
|
||||
if (e.key === key) cb();
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
} from '@yaakapp-internal/models';
|
||||
import { atom, useAtomValue } from 'jotai';
|
||||
import { useEffect, useMemo } from 'react';
|
||||
import { fireAndForget } from '../lib/fireAndForget';
|
||||
import { atomWithKVStorage } from '../lib/atoms/atomWithKVStorage';
|
||||
import { activeRequestIdAtom } from './useActiveRequestId';
|
||||
|
||||
@@ -69,9 +70,9 @@ export function useGrpcEvents(connectionId: string | null) {
|
||||
}
|
||||
|
||||
// Fetch events from database, filtering out events from other connections and merging atomically
|
||||
invoke<GrpcEvent[]>('models_grpc_events', { connectionId }).then((events) =>
|
||||
fireAndForget(invoke<GrpcEvent[]>('models_grpc_events', { connectionId }).then((events) =>
|
||||
mergeModelsInStore('grpc_event', events, (e) => e.connectionId === connectionId),
|
||||
);
|
||||
));
|
||||
}, [connectionId]);
|
||||
|
||||
return useMemo(
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
} from '@yaakapp-internal/models';
|
||||
import { atom, useAtomValue } from 'jotai';
|
||||
import { useEffect, useMemo } from 'react';
|
||||
import { fireAndForget } from '../lib/fireAndForget';
|
||||
import { atomWithKVStorage } from '../lib/atoms/atomWithKVStorage';
|
||||
import { jotaiStore } from '../lib/jotai';
|
||||
import { activeRequestIdAtom } from './useActiveRequestId';
|
||||
@@ -56,9 +57,9 @@ export function useWebsocketEvents(connectionId: string | null) {
|
||||
}
|
||||
|
||||
// Fetch events from database, filtering out events from other connections and merging atomically
|
||||
invoke<WebsocketEvent[]>('models_websocket_events', { connectionId }).then((events) =>
|
||||
fireAndForget(invoke<WebsocketEvent[]>('models_websocket_events', { connectionId }).then((events) =>
|
||||
mergeModelsInStore('websocket_event', events, (e) => e.connectionId === connectionId),
|
||||
);
|
||||
));
|
||||
}, [connectionId]);
|
||||
|
||||
return useMemo(
|
||||
|
||||
@@ -17,7 +17,7 @@ export function useRequestEditorEvent<
|
||||
return () => {
|
||||
emitter.off(event, fn);
|
||||
};
|
||||
// biome-ignore lint/correctness/useExhaustiveDependencies: We're handing deps manually
|
||||
// oxlint-disable-next-line react-hooks/exhaustive-deps -- We're handing deps manually
|
||||
}, deps);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import { useEffect, useState } from 'react';
|
||||
*/
|
||||
export function useStateWithDeps<T>(defaultValue: T | (() => T), deps: DependencyList) {
|
||||
const [value, setValue] = useState(defaultValue);
|
||||
// biome-ignore lint/correctness/useExhaustiveDependencies: none
|
||||
// oxlint-disable-next-line react-hooks/exhaustive-deps
|
||||
useEffect(() => {
|
||||
setValue(defaultValue);
|
||||
}, [...deps]);
|
||||
|
||||
@@ -21,7 +21,7 @@ export function useWebsocketRequestActions() {
|
||||
queryFn: () => getWebsocketRequestActions(),
|
||||
});
|
||||
|
||||
// biome-ignore lint/correctness/useExhaustiveDependencies: none
|
||||
// oxlint-disable-next-line react-hooks/exhaustive-deps
|
||||
const actions = useMemo(() => {
|
||||
return actionsResult.data ?? [];
|
||||
}, [JSON.stringify(actionsResult.data)]);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { fireAndForget } from '../lib/fireAndForget';
|
||||
|
||||
export function useWindowFocus() {
|
||||
const [visible, setVisible] = useState(true);
|
||||
@@ -10,7 +11,7 @@ export function useWindowFocus() {
|
||||
});
|
||||
|
||||
return () => {
|
||||
unlisten.then((fn) => fn());
|
||||
fireAndForget(unlisten.then((fn) => fn()));
|
||||
};
|
||||
}, []);
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ export function useWorkspaceActions() {
|
||||
queryFn: () => getWorkspaceActions(),
|
||||
});
|
||||
|
||||
// biome-ignore lint/correctness/useExhaustiveDependencies: none
|
||||
// oxlint-disable-next-line react-hooks/exhaustive-deps
|
||||
const actions = useMemo(() => {
|
||||
return actionsResult.data ?? [];
|
||||
}, [JSON.stringify(actionsResult.data)]);
|
||||
|
||||
16
src-web/lib/fireAndForget.ts
Normal file
16
src-web/lib/fireAndForget.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { showErrorToast } from './toast';
|
||||
|
||||
/**
|
||||
* Handles a fire-and-forget promise by catching and reporting errors
|
||||
* via console.error and a toast notification.
|
||||
*/
|
||||
export function fireAndForget(promise: Promise<unknown>) {
|
||||
promise.catch((err: unknown) => {
|
||||
console.error('Unhandled async error:', err);
|
||||
showErrorToast({
|
||||
id: 'async-error',
|
||||
title: 'Unexpected Error',
|
||||
message: err instanceof Error ? err.message : String(err),
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import type { ReactNode } from 'react';
|
||||
* https://stackoverflow.com/questions/50428910/get-text-content-from-node-in-react
|
||||
*/
|
||||
export function getNodeText(node: ReactNode): string {
|
||||
if (['string', 'number'].includes(typeof node)) {
|
||||
if (typeof node === 'string' || typeof node === 'number') {
|
||||
return String(node);
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ export function getNodeText(node: ReactNode): string {
|
||||
}
|
||||
|
||||
if (typeof node === 'object' && node) {
|
||||
// biome-ignore lint/suspicious/noExplicitAny: none
|
||||
// oxlint-disable-next-line no-explicit-any
|
||||
return getNodeText((node as any).props.children);
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import { HStack, VStack } from '../components/core/Stacks';
|
||||
|
||||
// Listen for toasts
|
||||
import { listenToTauriEvent } from '../hooks/useListenToTauriEvent';
|
||||
import { fireAndForget } from './fireAndForget';
|
||||
import { updateAvailableAtom } from './atoms';
|
||||
import { stringToColor } from './color';
|
||||
import { generateId } from './generateId';
|
||||
@@ -81,7 +82,7 @@ export function initGlobalListeners() {
|
||||
done,
|
||||
},
|
||||
};
|
||||
emit(event.id, result);
|
||||
fireAndForget(emit(event.id, result));
|
||||
};
|
||||
|
||||
const values = await showPromptForm({
|
||||
@@ -110,7 +111,7 @@ export function initGlobalListeners() {
|
||||
// Listen for update events
|
||||
listenToTauriEvent<UpdateInfo>('update_available', async ({ payload }) => {
|
||||
console.log('Got update available', payload);
|
||||
showUpdateAvailableToast(payload);
|
||||
fireAndForget(showUpdateAvailableToast(payload));
|
||||
});
|
||||
|
||||
listenToTauriEvent<YaakNotification>('notification', ({ payload }) => {
|
||||
@@ -125,7 +126,7 @@ export function initGlobalListeners() {
|
||||
});
|
||||
|
||||
// Check for plugin initialization errors
|
||||
invokeCmd<[string, string][]>('cmd_plugin_init_errors').then((errors) => {
|
||||
fireAndForget(invokeCmd<[string, string][]>('cmd_plugin_init_errors').then((errors) => {
|
||||
for (const [dir, message] of errors) {
|
||||
const dirBasename = dir.split('/').pop() ?? dir;
|
||||
showToast({
|
||||
@@ -155,7 +156,7 @@ export function initGlobalListeners() {
|
||||
),
|
||||
});
|
||||
}
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
function showUpdateInstalledToast(version: string) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { HttpResponseEvent } from '@yaakapp-internal/models';
|
||||
import { describe, expect, test } from 'vitest';
|
||||
import { describe, expect, test } from 'vite-plus/test';
|
||||
import { getCookieCounts } from './model_util';
|
||||
|
||||
function makeEvent(
|
||||
|
||||
@@ -15,10 +15,10 @@ export function setWorkspaceSearchParams(
|
||||
folder_id: string | null;
|
||||
}>,
|
||||
) {
|
||||
// biome-ignore lint/suspicious/noExplicitAny: none
|
||||
// oxlint-disable-next-line no-explicit-any
|
||||
(router as any)
|
||||
.navigate({
|
||||
// biome-ignore lint/suspicious/noExplicitAny: none
|
||||
// oxlint-disable-next-line no-explicit-any
|
||||
search: (prev: any) => {
|
||||
// console.log('Navigating to', { prev, search });
|
||||
const o = { ...prev, ...search };
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow';
|
||||
import { fireAndForget } from '../fireAndForget';
|
||||
|
||||
export type Appearance = 'light' | 'dark';
|
||||
|
||||
@@ -22,13 +23,13 @@ export function subscribeToWindowAppearanceChange(
|
||||
unsubscribe: () => {},
|
||||
};
|
||||
|
||||
getCurrentWebviewWindow()
|
||||
fireAndForget(getCurrentWebviewWindow()
|
||||
.onThemeChanged((t) => {
|
||||
cb(t.payload);
|
||||
})
|
||||
.then((l) => {
|
||||
container.unsubscribe = l;
|
||||
});
|
||||
}));
|
||||
|
||||
return () => container.unsubscribe();
|
||||
}
|
||||
@@ -43,6 +44,6 @@ export function resolveAppearance(
|
||||
|
||||
export function subscribeToPreferredAppearance(cb: (a: Appearance) => void) {
|
||||
cb(getCSSAppearance());
|
||||
getWindowAppearance().then(cb);
|
||||
fireAndForget(getWindowAppearance().then(cb));
|
||||
subscribeToWindowAppearanceChange(cb);
|
||||
}
|
||||
|
||||
@@ -279,7 +279,7 @@ export function getThemeCSS(theme: Theme): string {
|
||||
theme.components.toast = theme.components.toast ?? theme.components.menu ?? {};
|
||||
const { components, id, label } = theme;
|
||||
const colors = Object.keys(theme.base).reduce((prev, key) => {
|
||||
// biome-ignore lint/performance/noAccumulatingSpread: none
|
||||
// oxlint-disable-next-line no-accumulating-spread
|
||||
return { ...prev, [key]: theme.base[key as YaakColorKey] };
|
||||
}, {}) as ThemeComponentColors;
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite dev --force",
|
||||
"build": "vite build",
|
||||
"dev": "vp dev --force",
|
||||
"build": "vp build",
|
||||
"lint": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -77,9 +77,11 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@lezer/generator": "^1.8.0",
|
||||
"@rolldown/plugin-babel": "^0.2.1",
|
||||
"@tailwindcss/container-queries": "^0.1.1",
|
||||
"@tailwindcss/nesting": "^0.0.0-insiders.565cd3e",
|
||||
"@tanstack/router-plugin": "^1.127.5",
|
||||
"@types/babel__core": "^7.20.5",
|
||||
"@types/node": "^24.0.13",
|
||||
"@types/papaparse": "^5.3.16",
|
||||
"@types/parse-color": "^1.0.3",
|
||||
@@ -88,18 +90,17 @@
|
||||
"@types/react-syntax-highlighter": "^15.5.13",
|
||||
"@types/uuid": "^10.0.0",
|
||||
"@types/whatwg-mimetype": "^3.0.2",
|
||||
"babel-plugin-react-compiler": "^1.0.0",
|
||||
"@vitejs/plugin-react": "^6.0.0",
|
||||
"autoprefixer": "^10.4.21",
|
||||
"babel-plugin-react-compiler": "^1.0.0",
|
||||
"decompress": "^4.2.1",
|
||||
"internal-ip": "^8.0.0",
|
||||
"postcss": "^8.5.6",
|
||||
"postcss-nesting": "^13.0.2",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"vite": "^8.0.0",
|
||||
"vite": "npm:@voidzero-dev/vite-plus-core@latest",
|
||||
"vite-plugin-static-copy": "^3.3.0",
|
||||
"vite-plugin-svgr": "^4.5.0",
|
||||
"vite-plugin-top-level-await": "^1.6.0",
|
||||
"vite-plugin-wasm": "^3.5.0"
|
||||
"vite-plus": "latest"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ type WorkspaceSearchSchema = {
|
||||
| {
|
||||
folder_id: string;
|
||||
}
|
||||
// biome-ignore lint/complexity/noBannedTypes: Needed to support empty
|
||||
// oxlint-disable-next-line no-restricted-types -- Needed to support empty
|
||||
| {}
|
||||
);
|
||||
|
||||
|
||||
@@ -138,6 +138,7 @@ module.exports = {
|
||||
},
|
||||
plugins: [
|
||||
require('@tailwindcss/container-queries'),
|
||||
// oxlint-disable-next-line unbound-method
|
||||
plugin(function ({ addVariant }) {
|
||||
addVariant('hocus', ['&:hover', '&:focus-visible', '&.focus:focus']);
|
||||
addVariant('focus-visible-or-class', ['&:focus-visible', '&.focus:focus']);
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node",
|
||||
"moduleResolution": "bundler",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node",
|
||||
"moduleResolution": "bundler",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"noUncheckedIndexedAccess": true
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
||||
|
||||
2
src-web/vite-env.d.ts
vendored
2
src-web/vite-env.d.ts
vendored
@@ -1 +1 @@
|
||||
/// <reference types="vite/client" />
|
||||
/// <reference types="vite-plus/client" />
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
// @ts-ignore
|
||||
import { tanstackRouter } from '@tanstack/router-plugin/vite';
|
||||
import react from '@vitejs/plugin-react';
|
||||
import babel from '@rolldown/plugin-babel';
|
||||
import react, { reactCompilerPreset } from '@vitejs/plugin-react';
|
||||
import { createRequire } from 'node:module';
|
||||
import path from 'node:path';
|
||||
import { defineConfig, normalizePath } from 'vite';
|
||||
import { defineConfig, normalizePath } from 'vite-plus';
|
||||
import { viteStaticCopy } from 'vite-plugin-static-copy';
|
||||
import svgr from 'vite-plugin-svgr';
|
||||
import topLevelAwait from 'vite-plugin-top-level-await';
|
||||
import wasm from 'vite-plugin-wasm';
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const cMapsDir = normalizePath(
|
||||
@@ -18,10 +17,9 @@ const standardFontsDir = normalizePath(
|
||||
);
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig(async () => {
|
||||
return {
|
||||
export default defineConfig(
|
||||
{
|
||||
plugins: [
|
||||
wasm(),
|
||||
tanstackRouter({
|
||||
target: 'react',
|
||||
routesDirectory: './routes',
|
||||
@@ -29,12 +27,10 @@ export default defineConfig(async () => {
|
||||
autoCodeSplitting: true,
|
||||
}),
|
||||
svgr(),
|
||||
react({
|
||||
babel: {
|
||||
plugins: ['babel-plugin-react-compiler'],
|
||||
},
|
||||
react(),
|
||||
babel({
|
||||
presets: [reactCompilerPreset()],
|
||||
}),
|
||||
topLevelAwait(),
|
||||
viteStaticCopy({
|
||||
targets: [
|
||||
{ src: cMapsDir, dest: '' },
|
||||
@@ -61,5 +57,4 @@ export default defineConfig(async () => {
|
||||
strictPort: true,
|
||||
},
|
||||
envPrefix: ['VITE_', 'TAURI_'],
|
||||
};
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user