diff --git a/plugins/themes-yaak/src/index.ts b/plugins/themes-yaak/src/index.ts index c963f5e9..504098eb 100644 --- a/plugins/themes-yaak/src/index.ts +++ b/plugins/themes-yaak/src/index.ts @@ -2,6 +2,49 @@ import type { PluginDefinition } from '@yaakapp/api'; export const plugin: PluginDefinition = { themes: [ + { + id: 'high-contrast', + label: 'High Contrast Light', + dark: false, + base: { + surface: 'white', + surfaceHighlight: 'hsl(218,24%,93%)', + text: 'black', + textSubtle: 'hsl(217,24%,40%)', + textSubtlest: 'hsl(217,24%,40%)', + border: 'hsl(217,22%,50%)', + borderSubtle: 'hsl(217,22%,60%)', + primary: 'hsl(267,67%,47%)', + secondary: 'hsl(218,18%,53%)', + info: 'hsl(206,100%,36%)', + success: 'hsl(155,100%,26%)', + notice: 'hsl(45,100%,31%)', + warning: 'hsl(30,99%,34%)', + danger: 'hsl(334,100%,35%)', + }, + }, + { + id: 'high-contrast-dark', + label: 'High Contrast Dark', + dark: true, + base: { + surface: 'hsl(0,0%,0%)', + surfaceHighlight: 'hsl(0,0%,20%)', + text: 'hsl(0,0%,100%)', + textSubtle: 'hsl(0,0%,90%)', + textSubtlest: 'hsl(0,0%,80%)', + selection: 'hsl(276,100%,30%)', + surfaceActive: 'hsl(276,100%,30%)', + border: 'hsl(0,0%,60%)', + primary: 'hsl(266,100%,85%)', + secondary: 'hsl(242,20%,72%)', + info: 'hsl(208,100%,83%)', + success: 'hsl(150,100%,63%)', + notice: 'hsl(49,100%,77%)', + warning: 'hsl(28,100%,73%)', + danger: 'hsl(343,100%,79%)', + }, + }, { id: 'catppuccin-frappe', label: 'Catppuccin Frappé', diff --git a/src-tauri/yaak-models/src/queries/environments.rs b/src-tauri/yaak-models/src/queries/environments.rs index ae19ee8c..92418f7a 100644 --- a/src-tauri/yaak-models/src/queries/environments.rs +++ b/src-tauri/yaak-models/src/queries/environments.rs @@ -51,6 +51,7 @@ impl<'a> DbContext<'a> { &Environment { workspace_id: workspace_id.to_string(), name: "Global Variables".to_string(), + parent_model: "workspace".to_string(), ..Default::default() }, &UpdateSource::Background, diff --git a/src-web/components/EnvironmentEditor.tsx b/src-web/components/EnvironmentEditor.tsx index 86d11272..deb90251 100644 --- a/src-web/components/EnvironmentEditor.tsx +++ b/src-web/components/EnvironmentEditor.tsx @@ -24,7 +24,7 @@ import { EnvironmentColorIndicator } from './EnvironmentColorIndicator'; import { EnvironmentSharableTooltip } from './EnvironmentSharableTooltip'; export function EnvironmentEditor({ - environment: selectedEnvironment, + environment, hideName, className, }: { @@ -32,7 +32,7 @@ export function EnvironmentEditor({ hideName?: boolean; className?: string; }) { - const workspaceId = selectedEnvironment.workspaceId; + const workspaceId = environment.workspaceId; const isEncryptionEnabled = useIsEncryptionEnabled(); const valueVisibility = useKeyValue({ namespace: 'global', @@ -41,15 +41,15 @@ export function EnvironmentEditor({ }); const { allEnvironments } = useEnvironmentsBreakdown(); const handleChange = useCallback( - (variables: PairWithId[]) => patchModel(selectedEnvironment, { variables }), - [selectedEnvironment], + (variables: PairWithId[]) => patchModel(environment, { variables }), + [environment], ); const [forceUpdateKey, regenerateForceUpdateKey] = useRandomKey(); // Gather a list of env names from other environments to help the user get them aligned const nameAutocomplete = useMemo(() => { const options: GenericCompletionOption[] = []; - if (isBaseEnvironment(selectedEnvironment)) { + if (isBaseEnvironment(environment)) { return { options }; } @@ -59,8 +59,10 @@ export function EnvironmentEditor({ const containingEnvs = allEnvironments.filter((e) => e.variables.some((v) => v.name === name), ); - const isAlreadyInActive = containingEnvs.find((e) => e.id === selectedEnvironment.id); - if (isAlreadyInActive) continue; + const isAlreadyInActive = containingEnvs.find((e) => e.id === environment.id); + if (isAlreadyInActive) { + continue; + } options.push({ label: name, type: 'constant', @@ -68,7 +70,7 @@ export function EnvironmentEditor({ }); } return { options }; - }, [selectedEnvironment, allEnvironments]); + }, [environment, allEnvironments]); const validateName = useCallback((name: string) => { // Empty just means the variable doesn't have a name yet and is unusable @@ -79,10 +81,8 @@ export function EnvironmentEditor({ const valueType = !isEncryptionEnabled && valueVisibility.value ? 'text' : 'password'; const allVariableAreEncrypted = useMemo( () => - selectedEnvironment.variables.every( - (v) => v.value === '' || analyzeTemplate(v.value) !== 'insecure', - ), - [selectedEnvironment.variables], + environment.variables.every((v) => v.value === '' || analyzeTemplate(v.value) !== 'insecure'), + [environment.variables], ); const encryptEnvironment = (environment: Environment) => { @@ -100,11 +100,11 @@ export function EnvironmentEditor({ return ( - - {!hideName &&
{selectedEnvironment?.name}
} + + {!hideName &&
{environment?.name}
} {isEncryptionEnabled ? ( !allVariableAreEncrypted ? ( - encryptEnvironment(selectedEnvironment)}> + encryptEnvironment(environment)}> Encrypt All Variables ) : ( @@ -121,21 +121,21 @@ export function EnvironmentEditor({ color="secondary" rightSlot={} onClick={async () => { - await patchModel(selectedEnvironment, { public: !selectedEnvironment.public }); + await patchModel(environment, { public: !environment.public }); }} > - {selectedEnvironment.public ? 'Sharable' : 'Private'} + {environment.public ? 'Sharable' : 'Private'}
- {selectedEnvironment.public && (!isEncryptionEnabled || !allVariableAreEncrypted) && ( + {environment.public && (!isEncryptionEnabled || !allVariableAreEncrypted) && ( encryptEnvironment(selectedEnvironment), + onClick: () => encryptEnvironment(environment), color: 'primary', }, ]} @@ -153,15 +153,11 @@ export function EnvironmentEditor({ valueType={valueType} valueAutocompleteVariables valueAutocompleteFunctions - forceUpdateKey={`${selectedEnvironment.id}::${forceUpdateKey}`} - pairs={selectedEnvironment.variables} + forceUpdateKey={`${environment.id}::${forceUpdateKey}`} + pairs={environment.variables} onChange={handleChange} - stateKey={`environment.${selectedEnvironment.id}`} - forcedEnvironmentId={ - // Editing the base environment should resolve variables using the active environment. - // Editing a sub environment should resolve variables as if it's the active environment - isBaseEnvironment(selectedEnvironment) ? undefined : selectedEnvironment.id - } + stateKey={`environment.${environment.id}`} + forcedEnvironmentId={environment.id} />
diff --git a/src-web/hooks/useEnvironmentVariables.ts b/src-web/hooks/useEnvironmentVariables.ts index 5da32137..334db625 100644 --- a/src-web/hooks/useEnvironmentVariables.ts +++ b/src-web/hooks/useEnvironmentVariables.ts @@ -1,16 +1,22 @@ import type { Environment, EnvironmentVariable } from '@yaakapp-internal/models'; import { foldersAtom } from '@yaakapp-internal/models'; +import { useAtomValue } from 'jotai'; import { useMemo } from 'react'; import { jotaiStore } from '../lib/jotai'; +import { isFolderEnvironment } from '../lib/model_util'; +import { useActiveEnvironment } from './useActiveEnvironment'; import { useActiveRequest } from './useActiveRequest'; import { useEnvironmentsBreakdown } from './useEnvironmentsBreakdown'; import { useParentFolders } from './useParentFolders'; -export function useEnvironmentVariables(environmentId: string | null) { - const { baseEnvironment, folderEnvironments, subEnvironments } = useEnvironmentsBreakdown(); - const activeEnvironment = subEnvironments.find((e) => e.id === environmentId) ?? null; +export function useEnvironmentVariables(targetEnvironmentId: string | null) { + const { baseEnvironment, folderEnvironments, allEnvironments } = useEnvironmentsBreakdown(); + const activeEnvironment = useActiveEnvironment(); + const targetEnvironment = allEnvironments.find((e) => e.id === targetEnvironmentId) ?? null; const activeRequest = useActiveRequest(); - const parentFolders = useParentFolders(activeRequest); + const folders = useAtomValue(foldersAtom); + const activeFolder = folders.find((f) => f.id === targetEnvironment?.parentId) ?? null; + const parentFolders = useParentFolders(activeFolder ?? activeRequest); return useMemo(() => { const varMap: Record = {}; @@ -18,9 +24,15 @@ export function useEnvironmentVariables(environmentId: string | null) { wrapVariables(folderEnvironments.find((fe) => fe.parentId === f.id) ?? null), ); + // Folder environments also can auto-complete from the active environment + const activeEnvironmentVariables = + targetEnvironment != null && isFolderEnvironment(targetEnvironment) + ? wrapVariables(activeEnvironment) + : []; + const allVariables = [ ...folderVariables, - ...wrapVariables(activeEnvironment), + ...activeEnvironmentVariables, ...wrapVariables(baseEnvironment), ]; @@ -32,7 +44,7 @@ export function useEnvironmentVariables(environmentId: string | null) { } return Object.values(varMap); - }, [activeEnvironment, baseEnvironment, folderEnvironments, parentFolders]); + }, [activeEnvironment, baseEnvironment, folderEnvironments, parentFolders, targetEnvironment]); } export interface WrappedEnvironmentVariable { diff --git a/src-web/hooks/useParentFolders.ts b/src-web/hooks/useParentFolders.ts index 4a7dc07c..1a937e7d 100644 --- a/src-web/hooks/useParentFolders.ts +++ b/src-web/hooks/useParentFolders.ts @@ -15,10 +15,10 @@ function getParentFolders( ): Folder[] { if (currentModel == null) return []; - const folder = currentModel.folderId ? folders.find((f) => f.id === currentModel.folderId) : null; - if (folder == null) { + const parentFolder = currentModel.folderId ? folders.find((f) => f.id === currentModel.folderId) : null; + if (parentFolder == null) { return []; } - return [folder, ...getParentFolders(folders, folder)]; + return [parentFolder, ...getParentFolders(folders, parentFolder)]; } diff --git a/src-web/lib/model_util.ts b/src-web/lib/model_util.ts index 66b9c662..5d842009 100644 --- a/src-web/lib/model_util.ts +++ b/src-web/lib/model_util.ts @@ -51,3 +51,11 @@ export function getCharsetFromContentType(headers: HttpResponseHeader[]): string export function isBaseEnvironment(environment: Environment): boolean { return environment.parentId == null; } + +export function isSubEnvironment(environment: Environment): boolean { + return environment.parentModel == 'environment'; +} + +export function isFolderEnvironment(environment: Environment): boolean { + return environment.parentModel == 'folder'; +} diff --git a/src-web/lib/theme/themes.ts b/src-web/lib/theme/themes.ts index 4e8da2e7..ebeac079 100644 --- a/src-web/lib/theme/themes.ts +++ b/src-web/lib/theme/themes.ts @@ -36,7 +36,7 @@ const yaakDark = { base: { surface: 'hsl(244,23%,14%)', surfaceHighlight: 'hsl(244,23%,20%)', - text: 'hsl(245,23%,84%)', + text: 'hsl(245,23%,85%)', textSubtle: 'hsl(245,18%,58%)', textSubtlest: 'hsl(245,18%,45%)', border: 'hsl(244,23%,25%)', @@ -67,11 +67,11 @@ const yaakDark = { }, responsePane: { surface: 'hsl(243,23%,16%)', - border: 'hsl(246,23%,22.72%)', + border: 'hsl(246,23%,23%)', }, appHeader: { surface: 'hsl(244,23%,12%)', - border: 'hsl(244,23%,20.8%)', + border: 'hsl(244,23%,21%)', }, }, }; @@ -83,22 +83,22 @@ const yaakLight = { base: { surface: 'hsl(0,0%,100%)', surfaceHighlight: 'hsl(218,24%,87%)', - text: 'hsl(217,24%,15%)', + text: 'hsl(217,24%,10%)', textSubtle: 'hsl(217,24%,40%)', textSubtlest: 'hsl(217,24%,58%)', - border: 'hsl(217,22%,93%)', - primary: 'hsl(266,100%,70%)', - secondary: 'hsl(220,24%,59%)', - info: 'hsl(206,100%,48%)', - success: 'hsl(155,95%,33%)', - notice: 'hsl(45,100%,41%)', - warning: 'hsl(30,100%,43%)', - danger: 'hsl(335,75%,57%)', + border: 'hsl(217,22%,90%)', + primary: 'hsl(266,100%,60%)', + secondary: 'hsl(220,24%,50%)', + info: 'hsl(206,100%,40%)', + success: 'hsl(139,66%,34%)', + notice: 'hsl(45,100%,34%)', + warning: 'hsl(30,100%,36%)', + danger: 'hsl(335,75%,48%)', }, components: { sidebar: { - surface: 'hsl(220,20%,97%)', - border: 'hsl(217,22%,93%)', + surface: 'hsl(220,20%,98%)', + border: 'hsl(217,22%,88%)', surfaceHighlight: 'hsl(217,25%,90%)', }, }, diff --git a/src-web/package.json b/src-web/package.json index bf8efd9e..c69ea813 100644 --- a/src-web/package.json +++ b/src-web/package.json @@ -6,7 +6,7 @@ "scripts": { "dev": "vite dev --force", "build": "vite build", - "lint": "eslint . --ext .ts,.tsx" + "lint": "tsc --noEmit && eslint . --ext .ts,.tsx" }, "dependencies": { "@codemirror/commands": "^6.8.1",