mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-03-11 17:46:41 -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 { useActiveWorkspace } from '../hooks/useActiveWorkspace';
|
||||
import { useWorkspaces } from '../hooks/useWorkspaces';
|
||||
import { count } from '../lib/pluralize';
|
||||
import { pluralizeCount } from '../lib/pluralize';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { Button } from './core/Button';
|
||||
import { Checkbox } from './core/Checkbox';
|
||||
@@ -128,7 +128,7 @@ function ExportDataDialogContent({
|
||||
disabled={noneSelected}
|
||||
onClick={() => handleExport()}
|
||||
>
|
||||
Export {count('Workspace', numSelected, { omitSingle: true, noneWord: 'Nothing' })}
|
||||
Export {pluralizeCount('Workspace', numSelected, { omitSingle: true, noneWord: 'Nothing' })}
|
||||
</Button>
|
||||
</HStack>
|
||||
</VStack>
|
||||
|
||||
@@ -14,7 +14,7 @@ import { useAlert } from '../hooks/useAlert';
|
||||
import type { ReflectResponseService } from '../hooks/useGrpc';
|
||||
import { tryFormatJson } from '../lib/formatters';
|
||||
import type { GrpcRequest } from '@yaakapp-internal/models';
|
||||
import { count } from '../lib/pluralize';
|
||||
import { pluralizeCount } from '../lib/pluralize';
|
||||
import { Button } from './core/Button';
|
||||
import { FormattedError } from './core/FormattedError';
|
||||
import { InlineCode } from './core/InlineCode';
|
||||
@@ -164,7 +164,7 @@ export function GrpcEditor({
|
||||
: reflectionError
|
||||
? 'Server Error'
|
||||
: protoFiles.length > 0
|
||||
? count('File', protoFiles.length)
|
||||
? pluralizeCount('File', protoFiles.length)
|
||||
: services != null && protoFiles.length === 0
|
||||
? 'Schema Detected'
|
||||
: 'Select Schema'}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { open } from '@tauri-apps/plugin-dialog';
|
||||
import { useGrpc } from '../hooks/useGrpc';
|
||||
import { useGrpcProtoFiles } from '../hooks/useGrpcProtoFiles';
|
||||
import { useGrpcRequest } from '../hooks/useGrpcRequest';
|
||||
import { count } from '../lib/pluralize';
|
||||
import { pluralizeCount } from '../lib/pluralize';
|
||||
import { Banner } from './core/Banner';
|
||||
import { Button } from './core/Button';
|
||||
import { IconButton } from './core/IconButton';
|
||||
@@ -76,7 +76,7 @@ export function GrpcProtoSelection({ requestId }: Props) {
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
{services?.length > 5 && count('other', services?.length - 5)}
|
||||
{services?.length > 5 && pluralizeCount('other', services?.length - 5)}
|
||||
</p>
|
||||
</Banner>
|
||||
)}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { formatDistanceToNowStrict } from 'date-fns';
|
||||
import { useDeleteGrpcConnection } from '../hooks/useDeleteGrpcConnection';
|
||||
import { useDeleteGrpcConnections } from '../hooks/useDeleteGrpcConnections';
|
||||
import type { GrpcConnection } from '@yaakapp-internal/models';
|
||||
import { count } from '../lib/pluralize';
|
||||
import { pluralizeCount } from '../lib/pluralize';
|
||||
import { Dropdown } from './core/Dropdown';
|
||||
import { Icon } from './core/Icon';
|
||||
import { IconButton } from './core/IconButton';
|
||||
@@ -34,7 +34,7 @@ export function RecentConnectionsDropdown({
|
||||
},
|
||||
{
|
||||
key: 'clear-all',
|
||||
label: `Clear ${count('Connection', connections.length)}`,
|
||||
label: `Clear ${pluralizeCount('Connection', connections.length)}`,
|
||||
onSelect: deleteAllConnections.mutate,
|
||||
hidden: connections.length <= 1,
|
||||
disabled: connections.length === 0,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { defaultKeymap } from '@codemirror/commands';
|
||||
import { forceParsing } from '@codemirror/language';
|
||||
import { Compartment, EditorState, type Extension } from '@codemirror/state';
|
||||
import { defaultKeymap, historyField } from '@codemirror/commands';
|
||||
import { foldState, forceParsing } from '@codemirror/language';
|
||||
import type { EditorStateConfig, Extension } from '@codemirror/state';
|
||||
import { Compartment, EditorState } from '@codemirror/state';
|
||||
import { keymap, placeholder as placeholderExt, tooltips } from '@codemirror/view';
|
||||
import type { EnvironmentVariable } from '@yaakapp-internal/models';
|
||||
import type { TemplateFunction } from '@yaakapp-internal/plugin';
|
||||
@@ -74,6 +75,8 @@ export interface EditorProps {
|
||||
stateKey: string | null;
|
||||
}
|
||||
|
||||
const stateFields = { history: historyField, folds: foldState };
|
||||
|
||||
const emptyVariables: EnvironmentVariable[] = [];
|
||||
|
||||
export const Editor = forwardRef<EditorView | undefined, EditorProps>(function Editor(
|
||||
@@ -305,40 +308,42 @@ export const Editor = forwardRef<EditorView | undefined, EditorProps>(function E
|
||||
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 state =
|
||||
cachedJsonState ??
|
||||
EditorState.create({
|
||||
doc: `${defaultValue ?? ''}`,
|
||||
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 doc = `${defaultValue ?? ''}`;
|
||||
const config: EditorStateConfig = { extensions, doc };
|
||||
|
||||
const state = cachedJsonState
|
||||
? EditorState.fromJSON(cachedJsonState, config, stateFields)
|
||||
: EditorState.create(config);
|
||||
|
||||
const view = new EditorView({ state, parent: container });
|
||||
|
||||
// For large documents, the parser may parse the max number of lines and fail to add
|
||||
// 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);
|
||||
|
||||
cm.current = { view, languageCompartment };
|
||||
@@ -544,24 +549,25 @@ const placeholderElFromText = (text: string) => {
|
||||
return el;
|
||||
};
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
editorStates: Record<string, EditorState>;
|
||||
}
|
||||
}
|
||||
window.editorStates = window.editorStates ?? {};
|
||||
|
||||
function saveCachedEditorState(stateKey: string | null, state: EditorState | null) {
|
||||
if (!stateKey || state == null) return;
|
||||
window.editorStates[stateKey] = state;
|
||||
sessionStorage.setItem(stateKey, JSON.stringify(state.toJSON(stateFields)));
|
||||
}
|
||||
|
||||
function getCachedEditorState(doc: string, stateKey: string | null) {
|
||||
if (stateKey == null) return;
|
||||
|
||||
const state = window.editorStates[stateKey] ?? null;
|
||||
if (state == null) return null;
|
||||
if (state.doc.toString() !== doc) return null;
|
||||
const stateStr = sessionStorage.getItem(stateKey)
|
||||
if (stateStr == null) 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';
|
||||
import { history, historyKeymap, indentWithTab } from '@codemirror/commands';
|
||||
import { javascript } from '@codemirror/lang-javascript';
|
||||
import { markdown } from '@codemirror/lang-markdown';
|
||||
import { json } from '@codemirror/lang-json';
|
||||
import { markdown } from '@codemirror/lang-markdown';
|
||||
import { xml } from '@codemirror/lang-xml';
|
||||
import type { LanguageSupport } from '@codemirror/language';
|
||||
import {
|
||||
@@ -37,7 +37,8 @@ import type { EnvironmentVariable } from '@yaakapp-internal/models';
|
||||
import type { TemplateFunction } from '@yaakapp-internal/plugin';
|
||||
import { graphql } from 'cm6-graphql';
|
||||
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 { text } from './text/extension';
|
||||
import { twig } from './twig/extension';
|
||||
@@ -162,11 +163,15 @@ export const multiLineExtensions = ({ hideGutter }: { hideGutter?: boolean }) =>
|
||||
const el = document.createElement('span');
|
||||
el.onclick = onclick;
|
||||
el.className = 'cm-foldPlaceholder';
|
||||
el.innerText = prepared;
|
||||
el.innerText = prepared || '…';
|
||||
el.title = 'unfold';
|
||||
el.ariaLabel = 'folded code';
|
||||
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) {
|
||||
let count: number | undefined;
|
||||
let startToken = '{';
|
||||
@@ -191,13 +196,9 @@ export const multiLineExtensions = ({ hideGutter }: { hideGutter?: boolean }) =>
|
||||
}
|
||||
|
||||
if (count !== undefined) {
|
||||
const label = isArray ? 'item' : 'prop';
|
||||
const plural = count === 1 ? '' : 's';
|
||||
|
||||
return `${count} ${label}${plural}`;
|
||||
const label = isArray ? 'item' : 'key';
|
||||
return pluralizeCount(label, count);
|
||||
}
|
||||
|
||||
return '…';
|
||||
},
|
||||
}),
|
||||
EditorState.allowMultipleSelections.of(true),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useSetAtom } from 'jotai/index';
|
||||
import { count } from '../lib/pluralize';
|
||||
import { pluralizeCount } from '../lib/pluralize';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { getActiveWorkspaceId } from './useActiveWorkspace';
|
||||
import { useAlert } from './useAlert';
|
||||
@@ -15,8 +15,8 @@ export function useDeleteSendHistory() {
|
||||
const httpResponses = useHttpResponses();
|
||||
const grpcConnections = useGrpcConnections();
|
||||
const labels = [
|
||||
httpResponses.length > 0 ? count('Http Response', httpResponses.length) : null,
|
||||
grpcConnections.length > 0 ? count('Grpc Connection', grpcConnections.length) : null,
|
||||
httpResponses.length > 0 ? pluralizeCount('Http Response', httpResponses.length) : null,
|
||||
grpcConnections.length > 0 ? pluralizeCount('Grpc Connection', grpcConnections.length) : null,
|
||||
].filter((l) => l != null);
|
||||
|
||||
return useFastMutation({
|
||||
|
||||
@@ -10,7 +10,7 @@ import { Button } from '../components/core/Button';
|
||||
import { FormattedError } from '../components/core/FormattedError';
|
||||
import { VStack } from '../components/core/Stacks';
|
||||
import { ImportDataDialog } from '../components/ImportDataDialog';
|
||||
import { count } from '../lib/pluralize';
|
||||
import { pluralizeCount } from '../lib/pluralize';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { getActiveWorkspace } from './useActiveWorkspace';
|
||||
import { useAlert } from './useAlert';
|
||||
@@ -47,11 +47,11 @@ export function useImportData() {
|
||||
return (
|
||||
<VStack space={3} className="pb-4">
|
||||
<ul className="list-disc pl-6">
|
||||
<li>{count('Workspace', workspaces.length)}</li>
|
||||
<li>{count('Environment', environments.length)}</li>
|
||||
<li>{count('Folder', folders.length)}</li>
|
||||
<li>{count('HTTP Request', httpRequests.length)}</li>
|
||||
<li>{count('GRPC Request', grpcRequests.length)}</li>
|
||||
<li>{pluralizeCount('Workspace', workspaces.length)}</li>
|
||||
<li>{pluralizeCount('Environment', environments.length)}</li>
|
||||
<li>{pluralizeCount('Folder', folders.length)}</li>
|
||||
<li>{pluralizeCount('HTTP Request', httpRequests.length)}</li>
|
||||
<li>{pluralizeCount('GRPC Request', grpcRequests.length)}</li>
|
||||
</ul>
|
||||
<div>
|
||||
<Button className="ml-auto" onClick={hide} color="primary">
|
||||
|
||||
@@ -5,7 +5,7 @@ export function pluralize(word: string, count: number): string {
|
||||
return `${word}s`;
|
||||
}
|
||||
|
||||
export function count(
|
||||
export function pluralizeCount(
|
||||
word: string,
|
||||
count: number,
|
||||
opt: { omitSingle?: boolean; noneWord?: string } = {},
|
||||
|
||||
Reference in New Issue
Block a user