mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-04-30 18:19:12 -05:00
Revert to preserving editor state with fromJson due to state callbacks not being preserved
This commit is contained in:
@@ -4,7 +4,7 @@ import { useCallback, useMemo, useState } from 'react';
|
|||||||
import slugify from 'slugify';
|
import slugify from 'slugify';
|
||||||
import { useActiveWorkspace } from '../hooks/useActiveWorkspace';
|
import { useActiveWorkspace } from '../hooks/useActiveWorkspace';
|
||||||
import { useWorkspaces } from '../hooks/useWorkspaces';
|
import { useWorkspaces } from '../hooks/useWorkspaces';
|
||||||
import { count } from '../lib/pluralize';
|
import { pluralizeCount } from '../lib/pluralize';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { Button } from './core/Button';
|
import { Button } from './core/Button';
|
||||||
import { Checkbox } from './core/Checkbox';
|
import { Checkbox } from './core/Checkbox';
|
||||||
@@ -128,7 +128,7 @@ function ExportDataDialogContent({
|
|||||||
disabled={noneSelected}
|
disabled={noneSelected}
|
||||||
onClick={() => handleExport()}
|
onClick={() => handleExport()}
|
||||||
>
|
>
|
||||||
Export {count('Workspace', numSelected, { omitSingle: true, noneWord: 'Nothing' })}
|
Export {pluralizeCount('Workspace', numSelected, { omitSingle: true, noneWord: 'Nothing' })}
|
||||||
</Button>
|
</Button>
|
||||||
</HStack>
|
</HStack>
|
||||||
</VStack>
|
</VStack>
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import { useAlert } from '../hooks/useAlert';
|
|||||||
import type { ReflectResponseService } from '../hooks/useGrpc';
|
import type { ReflectResponseService } from '../hooks/useGrpc';
|
||||||
import { tryFormatJson } from '../lib/formatters';
|
import { tryFormatJson } from '../lib/formatters';
|
||||||
import type { GrpcRequest } from '@yaakapp-internal/models';
|
import type { GrpcRequest } from '@yaakapp-internal/models';
|
||||||
import { count } from '../lib/pluralize';
|
import { pluralizeCount } from '../lib/pluralize';
|
||||||
import { Button } from './core/Button';
|
import { Button } from './core/Button';
|
||||||
import { FormattedError } from './core/FormattedError';
|
import { FormattedError } from './core/FormattedError';
|
||||||
import { InlineCode } from './core/InlineCode';
|
import { InlineCode } from './core/InlineCode';
|
||||||
@@ -164,7 +164,7 @@ export function GrpcEditor({
|
|||||||
: reflectionError
|
: reflectionError
|
||||||
? 'Server Error'
|
? 'Server Error'
|
||||||
: protoFiles.length > 0
|
: protoFiles.length > 0
|
||||||
? count('File', protoFiles.length)
|
? pluralizeCount('File', protoFiles.length)
|
||||||
: services != null && protoFiles.length === 0
|
: services != null && protoFiles.length === 0
|
||||||
? 'Schema Detected'
|
? 'Schema Detected'
|
||||||
: 'Select Schema'}
|
: 'Select Schema'}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { open } from '@tauri-apps/plugin-dialog';
|
|||||||
import { useGrpc } from '../hooks/useGrpc';
|
import { useGrpc } from '../hooks/useGrpc';
|
||||||
import { useGrpcProtoFiles } from '../hooks/useGrpcProtoFiles';
|
import { useGrpcProtoFiles } from '../hooks/useGrpcProtoFiles';
|
||||||
import { useGrpcRequest } from '../hooks/useGrpcRequest';
|
import { useGrpcRequest } from '../hooks/useGrpcRequest';
|
||||||
import { count } from '../lib/pluralize';
|
import { pluralizeCount } from '../lib/pluralize';
|
||||||
import { Banner } from './core/Banner';
|
import { Banner } from './core/Banner';
|
||||||
import { Button } from './core/Button';
|
import { Button } from './core/Button';
|
||||||
import { IconButton } from './core/IconButton';
|
import { IconButton } from './core/IconButton';
|
||||||
@@ -76,7 +76,7 @@ export function GrpcProtoSelection({ requestId }: Props) {
|
|||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
{services?.length > 5 && count('other', services?.length - 5)}
|
{services?.length > 5 && pluralizeCount('other', services?.length - 5)}
|
||||||
</p>
|
</p>
|
||||||
</Banner>
|
</Banner>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { formatDistanceToNowStrict } from 'date-fns';
|
|||||||
import { useDeleteGrpcConnection } from '../hooks/useDeleteGrpcConnection';
|
import { useDeleteGrpcConnection } from '../hooks/useDeleteGrpcConnection';
|
||||||
import { useDeleteGrpcConnections } from '../hooks/useDeleteGrpcConnections';
|
import { useDeleteGrpcConnections } from '../hooks/useDeleteGrpcConnections';
|
||||||
import type { GrpcConnection } from '@yaakapp-internal/models';
|
import type { GrpcConnection } from '@yaakapp-internal/models';
|
||||||
import { count } from '../lib/pluralize';
|
import { pluralizeCount } from '../lib/pluralize';
|
||||||
import { Dropdown } from './core/Dropdown';
|
import { Dropdown } from './core/Dropdown';
|
||||||
import { Icon } from './core/Icon';
|
import { Icon } from './core/Icon';
|
||||||
import { IconButton } from './core/IconButton';
|
import { IconButton } from './core/IconButton';
|
||||||
@@ -34,7 +34,7 @@ export function RecentConnectionsDropdown({
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'clear-all',
|
key: 'clear-all',
|
||||||
label: `Clear ${count('Connection', connections.length)}`,
|
label: `Clear ${pluralizeCount('Connection', connections.length)}`,
|
||||||
onSelect: deleteAllConnections.mutate,
|
onSelect: deleteAllConnections.mutate,
|
||||||
hidden: connections.length <= 1,
|
hidden: connections.length <= 1,
|
||||||
disabled: connections.length === 0,
|
disabled: connections.length === 0,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { defaultKeymap } from '@codemirror/commands';
|
import { defaultKeymap, historyField } from '@codemirror/commands';
|
||||||
import { forceParsing } from '@codemirror/language';
|
import { foldState, forceParsing } from '@codemirror/language';
|
||||||
import { Compartment, EditorState, type Extension } from '@codemirror/state';
|
import type { EditorStateConfig, Extension } from '@codemirror/state';
|
||||||
|
import { Compartment, EditorState } from '@codemirror/state';
|
||||||
import { keymap, placeholder as placeholderExt, tooltips } from '@codemirror/view';
|
import { keymap, placeholder as placeholderExt, tooltips } from '@codemirror/view';
|
||||||
import type { EnvironmentVariable } from '@yaakapp-internal/models';
|
import type { EnvironmentVariable } from '@yaakapp-internal/models';
|
||||||
import type { TemplateFunction } from '@yaakapp-internal/plugin';
|
import type { TemplateFunction } from '@yaakapp-internal/plugin';
|
||||||
@@ -74,6 +75,8 @@ export interface EditorProps {
|
|||||||
stateKey: string | null;
|
stateKey: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const stateFields = { history: historyField, folds: foldState };
|
||||||
|
|
||||||
const emptyVariables: EnvironmentVariable[] = [];
|
const emptyVariables: EnvironmentVariable[] = [];
|
||||||
|
|
||||||
export const Editor = forwardRef<EditorView | undefined, EditorProps>(function Editor(
|
export const Editor = forwardRef<EditorView | undefined, EditorProps>(function Editor(
|
||||||
@@ -305,40 +308,42 @@ export const Editor = forwardRef<EditorView | undefined, EditorProps>(function E
|
|||||||
onClickPathParameter,
|
onClickPathParameter,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const extensions = [
|
||||||
|
languageCompartment.of(langExt),
|
||||||
|
placeholderCompartment.current.of(
|
||||||
|
placeholderExt(placeholderElFromText(placeholder ?? '')),
|
||||||
|
),
|
||||||
|
wrapLinesCompartment.current.of(wrapLines ? [EditorView.lineWrapping] : []),
|
||||||
|
...getExtensions({
|
||||||
|
container,
|
||||||
|
readOnly,
|
||||||
|
singleLine,
|
||||||
|
hideGutter,
|
||||||
|
stateKey,
|
||||||
|
onChange: handleChange,
|
||||||
|
onPaste: handlePaste,
|
||||||
|
onPasteOverwrite: handlePasteOverwrite,
|
||||||
|
onFocus: handleFocus,
|
||||||
|
onBlur: handleBlur,
|
||||||
|
onKeyDown: handleKeyDown,
|
||||||
|
}),
|
||||||
|
...(extraExtensions ?? []),
|
||||||
|
];
|
||||||
|
|
||||||
const cachedJsonState = getCachedEditorState(defaultValue ?? '', stateKey);
|
const cachedJsonState = getCachedEditorState(defaultValue ?? '', stateKey);
|
||||||
|
|
||||||
const state =
|
const doc = `${defaultValue ?? ''}`;
|
||||||
cachedJsonState ??
|
const config: EditorStateConfig = { extensions, doc };
|
||||||
EditorState.create({
|
|
||||||
doc: `${defaultValue ?? ''}`,
|
const state = cachedJsonState
|
||||||
extensions: [
|
? EditorState.fromJSON(cachedJsonState, config, stateFields)
|
||||||
languageCompartment.of(langExt),
|
: EditorState.create(config);
|
||||||
placeholderCompartment.current.of(
|
|
||||||
placeholderExt(placeholderElFromText(placeholder ?? '')),
|
|
||||||
),
|
|
||||||
wrapLinesCompartment.current.of(wrapLines ? [EditorView.lineWrapping] : []),
|
|
||||||
...getExtensions({
|
|
||||||
container,
|
|
||||||
readOnly,
|
|
||||||
singleLine,
|
|
||||||
hideGutter,
|
|
||||||
stateKey,
|
|
||||||
onChange: handleChange,
|
|
||||||
onPaste: handlePaste,
|
|
||||||
onPasteOverwrite: handlePasteOverwrite,
|
|
||||||
onFocus: handleFocus,
|
|
||||||
onBlur: handleBlur,
|
|
||||||
onKeyDown: handleKeyDown,
|
|
||||||
}),
|
|
||||||
...(extraExtensions ?? []),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
const view = new EditorView({ state, parent: container });
|
const view = new EditorView({ state, parent: container });
|
||||||
|
|
||||||
// For large documents, the parser may parse the max number of lines and fail to add
|
// For large documents, the parser may parse the max number of lines and fail to add
|
||||||
// things like fold markers because of it.
|
// things like fold markers because of it.
|
||||||
// This forces it to parse more but keeps the timeout to the default of 100ms.
|
// This forces it to parse more but keeps the timeout to the default of 100 ms.
|
||||||
forceParsing(view, 9e6, 100);
|
forceParsing(view, 9e6, 100);
|
||||||
|
|
||||||
cm.current = { view, languageCompartment };
|
cm.current = { view, languageCompartment };
|
||||||
@@ -544,24 +549,25 @@ const placeholderElFromText = (text: string) => {
|
|||||||
return el;
|
return el;
|
||||||
};
|
};
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface Window {
|
|
||||||
editorStates: Record<string, EditorState>;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
window.editorStates = window.editorStates ?? {};
|
|
||||||
|
|
||||||
function saveCachedEditorState(stateKey: string | null, state: EditorState | null) {
|
function saveCachedEditorState(stateKey: string | null, state: EditorState | null) {
|
||||||
if (!stateKey || state == null) return;
|
if (!stateKey || state == null) return;
|
||||||
window.editorStates[stateKey] = state;
|
sessionStorage.setItem(stateKey, JSON.stringify(state.toJSON(stateFields)));
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCachedEditorState(doc: string, stateKey: string | null) {
|
function getCachedEditorState(doc: string, stateKey: string | null) {
|
||||||
if (stateKey == null) return;
|
if (stateKey == null) return;
|
||||||
|
|
||||||
const state = window.editorStates[stateKey] ?? null;
|
const stateStr = sessionStorage.getItem(stateKey)
|
||||||
if (state == null) return null;
|
if (stateStr == null) return null;
|
||||||
if (state.doc.toString() !== doc) return null;
|
|
||||||
|
|
||||||
return state;
|
try {
|
||||||
|
const state = JSON.parse(stateStr);
|
||||||
|
if (state.doc !== doc) return null;
|
||||||
|
|
||||||
|
return state;
|
||||||
|
} catch {
|
||||||
|
// Nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import {
|
|||||||
} from '@codemirror/autocomplete';
|
} from '@codemirror/autocomplete';
|
||||||
import { history, historyKeymap, indentWithTab } from '@codemirror/commands';
|
import { history, historyKeymap, indentWithTab } from '@codemirror/commands';
|
||||||
import { javascript } from '@codemirror/lang-javascript';
|
import { javascript } from '@codemirror/lang-javascript';
|
||||||
import { markdown } from '@codemirror/lang-markdown';
|
|
||||||
import { json } from '@codemirror/lang-json';
|
import { json } from '@codemirror/lang-json';
|
||||||
|
import { markdown } from '@codemirror/lang-markdown';
|
||||||
import { xml } from '@codemirror/lang-xml';
|
import { xml } from '@codemirror/lang-xml';
|
||||||
import type { LanguageSupport } from '@codemirror/language';
|
import type { LanguageSupport } from '@codemirror/language';
|
||||||
import {
|
import {
|
||||||
@@ -37,7 +37,8 @@ import type { EnvironmentVariable } from '@yaakapp-internal/models';
|
|||||||
import type { TemplateFunction } from '@yaakapp-internal/plugin';
|
import type { TemplateFunction } from '@yaakapp-internal/plugin';
|
||||||
import { graphql } from 'cm6-graphql';
|
import { graphql } from 'cm6-graphql';
|
||||||
import { EditorView } from 'codemirror';
|
import { EditorView } from 'codemirror';
|
||||||
import type {EditorProps} from "./Editor";
|
import { pluralizeCount } from '../../../lib/pluralize';
|
||||||
|
import type { EditorProps } from './Editor';
|
||||||
import { pairs } from './pairs/extension';
|
import { pairs } from './pairs/extension';
|
||||||
import { text } from './text/extension';
|
import { text } from './text/extension';
|
||||||
import { twig } from './twig/extension';
|
import { twig } from './twig/extension';
|
||||||
@@ -162,11 +163,15 @@ export const multiLineExtensions = ({ hideGutter }: { hideGutter?: boolean }) =>
|
|||||||
const el = document.createElement('span');
|
const el = document.createElement('span');
|
||||||
el.onclick = onclick;
|
el.onclick = onclick;
|
||||||
el.className = 'cm-foldPlaceholder';
|
el.className = 'cm-foldPlaceholder';
|
||||||
el.innerText = prepared;
|
el.innerText = prepared || '…';
|
||||||
el.title = 'unfold';
|
el.title = 'unfold';
|
||||||
el.ariaLabel = 'folded code';
|
el.ariaLabel = 'folded code';
|
||||||
return el;
|
return el;
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* Show the number of items when code folded. NOTE: this doesn't get called when restoring
|
||||||
|
* a previous serialized editor state, which is a bummer
|
||||||
|
*/
|
||||||
preparePlaceholder(state, range) {
|
preparePlaceholder(state, range) {
|
||||||
let count: number | undefined;
|
let count: number | undefined;
|
||||||
let startToken = '{';
|
let startToken = '{';
|
||||||
@@ -191,13 +196,9 @@ export const multiLineExtensions = ({ hideGutter }: { hideGutter?: boolean }) =>
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (count !== undefined) {
|
if (count !== undefined) {
|
||||||
const label = isArray ? 'item' : 'prop';
|
const label = isArray ? 'item' : 'key';
|
||||||
const plural = count === 1 ? '' : 's';
|
return pluralizeCount(label, count);
|
||||||
|
|
||||||
return `${count} ${label}${plural}`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return '…';
|
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
EditorState.allowMultipleSelections.of(true),
|
EditorState.allowMultipleSelections.of(true),
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useSetAtom } from 'jotai/index';
|
import { useSetAtom } from 'jotai/index';
|
||||||
import { count } from '../lib/pluralize';
|
import { pluralizeCount } from '../lib/pluralize';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { getActiveWorkspaceId } from './useActiveWorkspace';
|
import { getActiveWorkspaceId } from './useActiveWorkspace';
|
||||||
import { useAlert } from './useAlert';
|
import { useAlert } from './useAlert';
|
||||||
@@ -15,8 +15,8 @@ export function useDeleteSendHistory() {
|
|||||||
const httpResponses = useHttpResponses();
|
const httpResponses = useHttpResponses();
|
||||||
const grpcConnections = useGrpcConnections();
|
const grpcConnections = useGrpcConnections();
|
||||||
const labels = [
|
const labels = [
|
||||||
httpResponses.length > 0 ? count('Http Response', httpResponses.length) : null,
|
httpResponses.length > 0 ? pluralizeCount('Http Response', httpResponses.length) : null,
|
||||||
grpcConnections.length > 0 ? count('Grpc Connection', grpcConnections.length) : null,
|
grpcConnections.length > 0 ? pluralizeCount('Grpc Connection', grpcConnections.length) : null,
|
||||||
].filter((l) => l != null);
|
].filter((l) => l != null);
|
||||||
|
|
||||||
return useFastMutation({
|
return useFastMutation({
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { Button } from '../components/core/Button';
|
|||||||
import { FormattedError } from '../components/core/FormattedError';
|
import { FormattedError } from '../components/core/FormattedError';
|
||||||
import { VStack } from '../components/core/Stacks';
|
import { VStack } from '../components/core/Stacks';
|
||||||
import { ImportDataDialog } from '../components/ImportDataDialog';
|
import { ImportDataDialog } from '../components/ImportDataDialog';
|
||||||
import { count } from '../lib/pluralize';
|
import { pluralizeCount } from '../lib/pluralize';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { getActiveWorkspace } from './useActiveWorkspace';
|
import { getActiveWorkspace } from './useActiveWorkspace';
|
||||||
import { useAlert } from './useAlert';
|
import { useAlert } from './useAlert';
|
||||||
@@ -47,11 +47,11 @@ export function useImportData() {
|
|||||||
return (
|
return (
|
||||||
<VStack space={3} className="pb-4">
|
<VStack space={3} className="pb-4">
|
||||||
<ul className="list-disc pl-6">
|
<ul className="list-disc pl-6">
|
||||||
<li>{count('Workspace', workspaces.length)}</li>
|
<li>{pluralizeCount('Workspace', workspaces.length)}</li>
|
||||||
<li>{count('Environment', environments.length)}</li>
|
<li>{pluralizeCount('Environment', environments.length)}</li>
|
||||||
<li>{count('Folder', folders.length)}</li>
|
<li>{pluralizeCount('Folder', folders.length)}</li>
|
||||||
<li>{count('HTTP Request', httpRequests.length)}</li>
|
<li>{pluralizeCount('HTTP Request', httpRequests.length)}</li>
|
||||||
<li>{count('GRPC Request', grpcRequests.length)}</li>
|
<li>{pluralizeCount('GRPC Request', grpcRequests.length)}</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div>
|
<div>
|
||||||
<Button className="ml-auto" onClick={hide} color="primary">
|
<Button className="ml-auto" onClick={hide} color="primary">
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ export function pluralize(word: string, count: number): string {
|
|||||||
return `${word}s`;
|
return `${word}s`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function count(
|
export function pluralizeCount(
|
||||||
word: string,
|
word: string,
|
||||||
count: number,
|
count: number,
|
||||||
opt: { omitSingle?: boolean; noneWord?: string } = {},
|
opt: { omitSingle?: boolean; noneWord?: string } = {},
|
||||||
|
|||||||
Reference in New Issue
Block a user