Autocomplete icons and transfer proto files on duplicate

This commit is contained in:
Gregory Schier
2024-02-26 07:39:53 -08:00
parent 5c1cf1e57d
commit f034cda7cd
5 changed files with 84 additions and 23 deletions

View File

@@ -35,14 +35,17 @@
} }
/* Don't show selection on blurred input */ /* Don't show selection on blurred input */
.cm-selectionBackground { .cm-selectionBackground {
@apply bg-transparent; @apply bg-transparent;
} }
&.cm-focused .cm-selectionBackground { &.cm-focused .cm-selectionBackground {
@apply bg-selection; @apply bg-selection;
} }
/* Style gutters */ /* Style gutters */
.cm-gutters { .cm-gutters {
@apply border-0 text-gray-500/50; @apply border-0 text-gray-500/50;
@@ -100,10 +103,10 @@
@apply font-mono text-[0.75rem]; @apply font-mono text-[0.75rem];
/* /*
* Round corners or they'll stick out of the editor bounds of editor is rounded. * Round corners or they'll stick out of the editor bounds of editor is rounded.
* Could potentially be pushed up from the editor like we do with bg color but this * Could potentially be pushed up from the editor like we do with bg color but this
* is probably fine. * is probably fine.
*/ */
@apply rounded-lg; @apply rounded-lg;
} }
} }
@@ -164,8 +167,9 @@
@apply h-full flex items-center; @apply h-full flex items-center;
/* Break characters on line wrapping mode, useful for URL field. /* Break characters on line wrapping mode, useful for URL field.
* We can make this dynamic if we need it to be configurable later * We can make this dynamic if we need it to be configurable later
*/ */
&.cm-lineWrapping { &.cm-lineWrapping {
@apply break-all; @apply break-all;
} }
@@ -176,6 +180,58 @@
.cm-tooltip.cm-tooltip { .cm-tooltip.cm-tooltip {
@apply shadow-lg bg-gray-50 rounded text-gray-700 border border-gray-200 z-50 pointer-events-auto text-[0.75rem]; @apply shadow-lg bg-gray-50 rounded text-gray-700 border border-gray-200 z-50 pointer-events-auto text-[0.75rem];
.cm-completionIcon {
@apply italic font-mono;
&.cm-completionIcon-class::after {
content: 'o' !important;
}
&.cm-completionIcon-constant::after {
content: 'c' !important;
}
&.cm-completionIcon-enum::after {
content: 'e' !important;
}
&.cm-completionIcon-function::after {
content: 'z' !important;
}
&.cm-completionIcon-interface::after {
content: 'i' !important;
}
&.cm-completionIcon-keyword::after {
content: 'k' !important;
}
&.cm-completionIcon-method::after {
content: 'm' !important;
}
&.cm-completionIcon-namespace::after {
content: 'n' !important;
}
&.cm-completionIcon-property::after {
content: 'a' !important;
}
&.cm-completionIcon-text::after {
content: 'x' !important;
}
&.cm-completionIcon-type::after {
content: 't' !important;
}
&.cm-completionIcon-variable::after {
content: 'x' !important;
}
}
&.cm-completionInfo-right { &.cm-completionInfo-right {
@apply ml-1 -mt-0.5 text-sm; @apply ml-1 -mt-0.5 text-sm;
} }
@@ -232,12 +288,8 @@
} }
/* Hide the "All" button */ /* Hide the "All" button */
button[name='select'] { button[name='select'] {
@apply hidden; @apply hidden;
} }
} }
/* Add default icon. Needs low priority so it can be overwritten */
.cm-completionIcon::after {
content: '𝑥';
}

View File

@@ -126,7 +126,7 @@ export const baseExtensions = [
// debouncedAutocompletionDisplay({ millis: 1000 }), // debouncedAutocompletionDisplay({ millis: 1000 }),
// autocompletion({ closeOnBlur: true, interactionDelay: 200, activateOnTyping: false }), // autocompletion({ closeOnBlur: true, interactionDelay: 200, activateOnTyping: false }),
autocompletion({ autocompletion({
// closeOnBlur: false, closeOnBlur: false, // For debugging in devtools without closing it
compareCompletions: (a, b) => { compareCompletions: (a, b) => {
// Don't sort completions at all, only on boost // Don't sort completions at all, only on boost
return (a.boost ?? 0) - (b.boost ?? 0); return (a.boost ?? 0) - (b.boost ?? 0);

View File

@@ -1,10 +1,12 @@
import { useMutation } from '@tanstack/react-query'; import { useMutation } from '@tanstack/react-query';
import { invoke } from '@tauri-apps/api'; import { invoke } from '@tauri-apps/api';
import { trackEvent } from '../lib/analytics'; import { trackEvent } from '../lib/analytics';
import { setKeyValue } from '../lib/keyValueStore';
import type { GrpcRequest } from '../lib/models'; import type { GrpcRequest } from '../lib/models';
import { useActiveEnvironmentId } from './useActiveEnvironmentId'; import { useActiveEnvironmentId } from './useActiveEnvironmentId';
import { useActiveWorkspaceId } from './useActiveWorkspaceId'; import { useActiveWorkspaceId } from './useActiveWorkspaceId';
import { useAppRoutes } from './useAppRoutes'; import { useAppRoutes } from './useAppRoutes';
import { protoFilesArgs, useGrpcProtoFiles } from './useGrpcProtoFiles';
export function useDuplicateGrpcRequest({ export function useDuplicateGrpcRequest({
id, id,
@@ -16,6 +18,7 @@ export function useDuplicateGrpcRequest({
const activeWorkspaceId = useActiveWorkspaceId(); const activeWorkspaceId = useActiveWorkspaceId();
const activeEnvironmentId = useActiveEnvironmentId(); const activeEnvironmentId = useActiveEnvironmentId();
const routes = useAppRoutes(); const routes = useAppRoutes();
const protoFiles = useGrpcProtoFiles(id);
return useMutation<GrpcRequest, string>({ return useMutation<GrpcRequest, string>({
mutationFn: async () => { mutationFn: async () => {
if (id === null) throw new Error("Can't duplicate a null grpc request"); if (id === null) throw new Error("Can't duplicate a null grpc request");
@@ -23,6 +26,9 @@ export function useDuplicateGrpcRequest({
}, },
onSettled: () => trackEvent('grpc_request', 'duplicate'), onSettled: () => trackEvent('grpc_request', 'duplicate'),
onSuccess: async (request) => { onSuccess: async (request) => {
// Also copy proto files to new request
await setKeyValue({ ...protoFilesArgs(request.id), value: protoFiles.value ?? [] });
if (navigateAfter && activeWorkspaceId !== null) { if (navigateAfter && activeWorkspaceId !== null) {
routes.navigate('request', { routes.navigate('request', {
workspaceId: activeWorkspaceId, workspaceId: activeWorkspaceId,

View File

@@ -1,10 +1,13 @@
import { NAMESPACE_GLOBAL } from '../lib/keyValueStore'; import { NAMESPACE_GLOBAL } from '../lib/keyValueStore';
import { useKeyValue } from './useKeyValue'; import { useKeyValue } from './useKeyValue';
export function useGrpcProtoFiles(activeRequestId: string | null) { export function protoFilesArgs(requestId: string | null) {
return useKeyValue<string[]>({ return {
namespace: NAMESPACE_GLOBAL, namespace: NAMESPACE_GLOBAL,
key: ['proto_files', activeRequestId ?? 'n/a'], key: ['proto_files', requestId ?? 'n/a'],
defaultValue: [], };
}); }
export function useGrpcProtoFiles(activeRequestId: string | null) {
return useKeyValue<string[]>({ ...protoFilesArgs(activeRequestId), fallback: [] });
} }

View File

@@ -18,16 +18,16 @@ export function keyValueQueryKey({
export function useKeyValue<T extends Object | null>({ export function useKeyValue<T extends Object | null>({
namespace = DEFAULT_NAMESPACE, namespace = DEFAULT_NAMESPACE,
key, key,
defaultValue, fallback,
}: { }: {
namespace?: string; namespace?: string;
key: string | string[]; key: string | string[];
defaultValue: T; fallback: T;
}) { }) {
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const query = useQuery<T>({ const query = useQuery<T>({
queryKey: keyValueQueryKey({ namespace, key }), queryKey: keyValueQueryKey({ namespace, key }),
queryFn: async () => getKeyValue({ namespace, key, fallback: defaultValue }), queryFn: async () => getKeyValue({ namespace, key, fallback }),
refetchOnWindowFocus: false, refetchOnWindowFocus: false,
}); });
@@ -40,7 +40,7 @@ export function useKeyValue<T extends Object | null>({
const set = useCallback( const set = useCallback(
async (value: ((v: T) => T) | T) => { async (value: ((v: T) => T) | T) => {
if (typeof value === 'function') { if (typeof value === 'function') {
await getKeyValue({ namespace, key, fallback: defaultValue }).then((kv) => { await getKeyValue({ namespace, key, fallback }).then((kv) => {
const newV = value(kv); const newV = value(kv);
if (newV === kv) return; if (newV === kv) return;
return mutate.mutateAsync(newV); return mutate.mutateAsync(newV);
@@ -51,10 +51,10 @@ export function useKeyValue<T extends Object | null>({
await mutate.mutateAsync(value); await mutate.mutateAsync(value);
} }
}, },
[defaultValue, key, mutate, namespace], [fallback, key, mutate, namespace],
); );
const reset = useCallback(async () => mutate.mutateAsync(defaultValue), [mutate, defaultValue]); const reset = useCallback(async () => mutate.mutateAsync(fallback), [mutate, fallback]);
return useMemo( return useMemo(
() => ({ () => ({