mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-03-30 22:22:02 +02:00
Merge pull request #256
* Update environment model to get ready for request/folder environments * Folder environments in UI * Folder environments working * Tweaks and fixes * Tweak environment encryption UX * Tweak environment encryption UX * Address comments * Update fn name * Add tsc back to lint rules * Update src-web/components/EnvironmentEditor.tsx * Merge remote-tracking branch 'origin/folder-environments' into folder…
This commit is contained in:
@@ -1,15 +1,18 @@
|
||||
import type { Color } from '@yaakapp-internal/plugins';
|
||||
import classNames from 'classnames';
|
||||
import { useKeyValue } from '../../hooks/useKeyValue';
|
||||
import type { BannerProps } from './Banner';
|
||||
import { Banner } from './Banner';
|
||||
import { Button } from './Button';
|
||||
import { HStack } from './Stacks';
|
||||
|
||||
export function DismissibleBanner({
|
||||
children,
|
||||
className,
|
||||
id,
|
||||
actions,
|
||||
...props
|
||||
}: BannerProps & { id: string }) {
|
||||
}: BannerProps & { id: string; actions?: { label: string; onClick: () => void; color?: Color }[] }) {
|
||||
const { set: setDismissed, value: dismissed } = useKeyValue<boolean>({
|
||||
namespace: 'global',
|
||||
key: ['dismiss-banner', id],
|
||||
@@ -19,17 +22,34 @@ export function DismissibleBanner({
|
||||
if (dismissed) return null;
|
||||
|
||||
return (
|
||||
<Banner className={classNames(className, 'relative grid grid-cols-[1fr_auto] gap-3')} {...props}>
|
||||
<Banner
|
||||
className={classNames(className, 'relative grid grid-cols-[1fr_auto] gap-3')}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<Button
|
||||
variant="border"
|
||||
color={props.color}
|
||||
size="xs"
|
||||
onClick={() => setDismissed((d) => !d)}
|
||||
title="Dismiss message"
|
||||
>
|
||||
Dismiss
|
||||
</Button>
|
||||
<HStack space={1.5}>
|
||||
{actions?.map((a, i) => (
|
||||
<Button
|
||||
key={a.label + i}
|
||||
variant="border"
|
||||
color={a.color ?? props.color}
|
||||
size="xs"
|
||||
onClick={a.onClick}
|
||||
title="Dismiss message"
|
||||
>
|
||||
{a.label}
|
||||
</Button>
|
||||
))}
|
||||
<Button
|
||||
variant="border"
|
||||
color={props.color}
|
||||
size="xs"
|
||||
onClick={() => setDismissed((d) => !d)}
|
||||
title="Dismiss message"
|
||||
>
|
||||
Dismiss
|
||||
</Button>
|
||||
</HStack>
|
||||
</Banner>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -519,7 +519,7 @@ const Menu = forwardRef<Omit<DropdownRef, 'open' | 'isOpen' | 'toggle' | 'items'
|
||||
className={classNames(
|
||||
className,
|
||||
'x-theme-menu',
|
||||
'outline-none my-1 pointer-events-auto fixed z-50',
|
||||
'outline-none my-1 pointer-events-auto fixed z-40',
|
||||
)}
|
||||
>
|
||||
{showTriangle && (
|
||||
|
||||
@@ -7,7 +7,7 @@ import { emacs } from '@replit/codemirror-emacs';
|
||||
import { vim } from '@replit/codemirror-vim';
|
||||
|
||||
import { vscodeKeymap } from '@replit/codemirror-vscode-keymap';
|
||||
import type { EditorKeymap, EnvironmentVariable } from '@yaakapp-internal/models';
|
||||
import type { EditorKeymap } from '@yaakapp-internal/models';
|
||||
import { settingsAtom } from '@yaakapp-internal/models';
|
||||
import type { EditorLanguage, TemplateFunction } from '@yaakapp-internal/plugins';
|
||||
import { parseTemplate } from '@yaakapp-internal/templates';
|
||||
@@ -28,10 +28,12 @@ import {
|
||||
useRef,
|
||||
} from 'react';
|
||||
import { activeEnvironmentIdAtom } from '../../../hooks/useActiveEnvironment';
|
||||
import type { WrappedEnvironmentVariable } from '../../../hooks/useEnvironmentVariables';
|
||||
import { useEnvironmentVariables } from '../../../hooks/useEnvironmentVariables';
|
||||
import { useRequestEditor } from '../../../hooks/useRequestEditor';
|
||||
import { useTemplateFunctionCompletionOptions } from '../../../hooks/useTemplateFunctions';
|
||||
import { showDialog } from '../../../lib/dialog';
|
||||
import { editEnvironment } from '../../../lib/editEnvironment';
|
||||
import { tryFormatJson, tryFormatXml } from '../../../lib/formatters';
|
||||
import { withEncryptionEnabled } from '../../../lib/setupOrConfigureEncryption';
|
||||
import { TemplateFunctionDialog } from '../../TemplateFunctionDialog';
|
||||
@@ -96,7 +98,7 @@ export interface EditorProps {
|
||||
|
||||
const stateFields = { history: historyField, folds: foldState };
|
||||
|
||||
const emptyVariables: EnvironmentVariable[] = [];
|
||||
const emptyVariables: WrappedEnvironmentVariable[] = [];
|
||||
const emptyExtension: Extension = [];
|
||||
|
||||
export const Editor = forwardRef<EditorView | undefined, EditorProps>(function Editor(
|
||||
@@ -306,24 +308,9 @@ export const Editor = forwardRef<EditorView | undefined, EditorProps>(function E
|
||||
);
|
||||
|
||||
const onClickVariable = useCallback(
|
||||
async (_v: EnvironmentVariable, tagValue: string, startPos: number) => {
|
||||
const initialTokens = parseTemplate(tagValue);
|
||||
showDialog({
|
||||
size: 'dynamic',
|
||||
id: 'template-variable',
|
||||
title: 'Change Variable',
|
||||
render: ({ hide }) => (
|
||||
<TemplateVariableDialog
|
||||
hide={hide}
|
||||
initialTokens={initialTokens}
|
||||
onChange={(insert) => {
|
||||
cm.current?.view.dispatch({
|
||||
changes: [{ from: startPos, to: startPos + tagValue.length, insert }],
|
||||
});
|
||||
}}
|
||||
/>
|
||||
),
|
||||
});
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
async (v: WrappedEnvironmentVariable, _tagValue: string, _startPos: number) => {
|
||||
editEnvironment(v.environment);
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
@@ -35,10 +35,10 @@ import {
|
||||
rectangularSelection,
|
||||
} from '@codemirror/view';
|
||||
import { tags as t } from '@lezer/highlight';
|
||||
import type { EnvironmentVariable } from '@yaakapp-internal/models';
|
||||
import { graphql } from 'cm6-graphql';
|
||||
import type { GraphQLSchema } from 'graphql';
|
||||
import { activeRequestIdAtom } from '../../../hooks/useActiveRequestId';
|
||||
import type { WrappedEnvironmentVariable } from '../../../hooks/useEnvironmentVariables';
|
||||
import { jotaiStore } from '../../../lib/jotai';
|
||||
import { renderMarkdown } from '../../../lib/markdown';
|
||||
import { pluralizeCount } from '../../../lib/pluralize';
|
||||
@@ -110,8 +110,8 @@ export function getLanguageExtension({
|
||||
graphQLSchema,
|
||||
}: {
|
||||
useTemplating: boolean;
|
||||
environmentVariables: EnvironmentVariable[];
|
||||
onClickVariable: (option: EnvironmentVariable, tagValue: string, startPos: number) => void;
|
||||
environmentVariables: WrappedEnvironmentVariable[];
|
||||
onClickVariable: (option: WrappedEnvironmentVariable, tagValue: string, startPos: number) => void;
|
||||
onClickMissingVariable: (name: string, tagValue: string, startPos: number) => void;
|
||||
onClickPathParameter: (name: string) => void;
|
||||
completionOptions: TwigCompletionOption[];
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { LanguageSupport } from '@codemirror/language';
|
||||
import { LRLanguage } from '@codemirror/language';
|
||||
import type { Extension } from '@codemirror/state';
|
||||
import { parseMixed } from '@lezer/common';
|
||||
import type { EnvironmentVariable } from '@yaakapp-internal/models';
|
||||
import type { WrappedEnvironmentVariable } from '../../../../hooks/useEnvironmentVariables';
|
||||
import type { GenericCompletionConfig } from '../genericCompletion';
|
||||
import { genericCompletion } from '../genericCompletion';
|
||||
import { textLanguage } from '../text/extension';
|
||||
@@ -21,10 +21,10 @@ export function twig({
|
||||
extraExtensions,
|
||||
}: {
|
||||
base: LanguageSupport;
|
||||
environmentVariables: EnvironmentVariable[];
|
||||
environmentVariables: WrappedEnvironmentVariable[];
|
||||
completionOptions: TwigCompletionOption[];
|
||||
autocomplete?: GenericCompletionConfig;
|
||||
onClickVariable: (option: EnvironmentVariable, tagValue: string, startPos: number) => void;
|
||||
onClickVariable: (option: WrappedEnvironmentVariable, tagValue: string, startPos: number) => void;
|
||||
onClickMissingVariable: (name: string, tagValue: string, startPos: number) => void;
|
||||
onClickPathParameter: (name: string) => void;
|
||||
extraExtensions: Extension[];
|
||||
@@ -33,9 +33,11 @@ export function twig({
|
||||
|
||||
const variableOptions: TwigCompletionOption[] =
|
||||
environmentVariables.map((v) => ({
|
||||
...v,
|
||||
name: v.variable.name,
|
||||
value: v.variable.value,
|
||||
type: 'variable',
|
||||
label: v.name,
|
||||
label: v.variable.name,
|
||||
description: `Inherited from ${v.source}`,
|
||||
onClick: (rawTag: string, startPos: number) => onClickVariable(v, rawTag, startPos),
|
||||
})) ?? [];
|
||||
|
||||
|
||||
@@ -94,13 +94,16 @@ function templateTags(
|
||||
(o) => o.name === name || (o.type === 'function' && o.aliases?.includes(name)),
|
||||
);
|
||||
if (option == null) {
|
||||
const from = node.from; // Cache here so the reference doesn't change
|
||||
option = {
|
||||
invalid: true,
|
||||
type: 'variable',
|
||||
name: inner,
|
||||
value: null,
|
||||
label: inner,
|
||||
onClick: () => onClickMissingVariable(name, rawTag, node.from),
|
||||
onClick: () => {
|
||||
onClickMissingVariable(name, rawTag, from);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user