diff --git a/README.md b/README.md index 50a3041c3..88da26150 100644 --- a/README.md +++ b/README.md @@ -25,8 +25,9 @@ Beak is a simple, extensible, and powerful API creation and management tool. Bui Beak includes: - Powerful feature set for creating APIs interactions -- Realtime values for dynamic variable replacement -- Extensions API to create custom realtime values +- Variables, which allow you to use dynamic values in requests +- Variable Sets, which allow you to group variables together and easily switch between sets +- An extensions API to create custom Beak Variables - Un-opinionated project syncing, just use the version control of your choice - Beautiful design language - And of course, fully cross platform diff --git a/apps-host/electron/package.json b/apps-host/electron/package.json index 7d187981b..3db8ba492 100644 --- a/apps-host/electron/package.json +++ b/apps-host/electron/package.json @@ -3,7 +3,6 @@ "description": "A feathery cross-platform API crafting tool", "version": "1.1.7-beta.9", "private": true, - "type": "module", "author": { "name": "Alexander Forbes-Reed (0xdeafcafe)", "email": "info@getbeak.app" @@ -46,8 +45,8 @@ }, "devDependencies": { "@electron/notarize": "^2.5.0", - "@getbeak/types": "^1.0.0", - "@getbeak/types-realtime-value": "^1.0.0", + "@getbeak/types": "^2.1.0", + "@getbeak/types-variables": "^2.1.0", "@types/electron-devtools-installer": "^2.2.5", "@types/fs-extra": "^11.0.4", "@types/lodash.clonedeep": "^4.5.9", diff --git a/apps-host/electron/scripts/notarize.js b/apps-host/electron/scripts/notarize.js index 44f591d52..e6b8cfc2c 100644 --- a/apps-host/electron/scripts/notarize.js +++ b/apps-host/electron/scripts/notarize.js @@ -1,8 +1,8 @@ /* eslint-disable @typescript-eslint/no-var-requires */ -import { notarize } from '@electron/notarize'; -import path from 'path'; +const { notarize } = require('@electron/notarize'); +const path = require('path'); -export default async function notarizing(context) { +module.exports = async function notarizing(context) { const { electronPlatformName, appOutDir } = context; if (electronPlatformName !== 'darwin') diff --git a/apps-host/electron/src/augmentations.d.ts b/apps-host/electron/src/augmentations.d.ts index 9d71f8b4e..69c9bd840 100644 --- a/apps-host/electron/src/augmentations.d.ts +++ b/apps-host/electron/src/augmentations.d.ts @@ -1,16 +1,16 @@ import type { Context } from '@getbeak/types/values'; -declare module '@getbeak/types-realtime-value' { +declare module '@getbeak/types-variables' { interface GenericDictionary { [k: string]: any; } - interface RealtimeValueBase { + interface VariableBase { type: string; external: boolean; } - interface RealtimeValue { + interface Variable { /** * Gets the string value of the value, given the payload body @@ -21,7 +21,7 @@ declare module '@getbeak/types-realtime-value' { getValue: (ctx: Context, payload: TPayload, recursiveDepth: number) => Promise; } - interface EditableRealtimeValue { + interface EditableVariable { /** * Gets the string value of the value, given the payload body diff --git a/apps-host/electron/src/ipc-layer/encryption-service.ts b/apps-host/electron/src/ipc-layer/encryption-service.ts index b93c9625b..011975d09 100644 --- a/apps-host/electron/src/ipc-layer/encryption-service.ts +++ b/apps-host/electron/src/ipc-layer/encryption-service.ts @@ -1,6 +1,6 @@ import { IpcEncryptionServiceMain } from '@beak/common/ipc/encryption'; import { clipboard, ipcMain } from 'electron'; -import { ValueParts } from 'packages/types/values'; +import { ValueSections } from 'packages/types/values'; import getBeakHost from '../host'; import { getProjectId } from './utils'; @@ -58,7 +58,7 @@ service.registerEncryptObject(async (event, { iv, payload }) => { return await getBeakHost().providers.aes.encryptString(json, encryption.key, iv); }); -service.registerDecryptObject(async (event, { iv, payload }): Promise => { +service.registerDecryptObject(async (event, { iv, payload }): Promise => { const projectId = getProjectId(event); const encryption = await getBeakHost().providers.credentials.getProjectEncryption(projectId); diff --git a/apps-host/electron/src/lib/extension/index.ts b/apps-host/electron/src/lib/extension/index.ts index 1120663f7..db25a14c5 100644 --- a/apps-host/electron/src/lib/extension/index.ts +++ b/apps-host/electron/src/lib/extension/index.ts @@ -1,12 +1,12 @@ import { ensureWithinProject } from '@beak/apps-host-electron/ipc-layer/fs-service'; import { getProjectFilePathWindowMapping } from '@beak/apps-host-electron/ipc-layer/fs-shared'; -import { ExtensionsMessages, IpcExtensionsServiceMain, RtvParseValuePartsResponse } from '@beak/common/ipc/extensions'; +import { ExtensionsMessages, IpcExtensionsServiceMain, RtvParseValueSectionsResponse } from '@beak/common/ipc/extensions'; import { IpcEvent, RequestPayload } from '@beak/common/ipc/ipc'; -import { RealtimeValueExtension } from '@beak/common/types/extensions'; +import { VariableExtension } from '@beak/common/types/extensions'; import Squawk from '@beak/common/utils/squawk'; import ksuid from '@beak/ksuid'; -import { Context, ValueParts } from '@getbeak/types/values'; -import { EditableRealtimeValue } from '@getbeak/types-realtime-value/'; +import { Context, ValueSections } from '@getbeak/types/values'; +import { EditableVariable } from '@getbeak/types-variables'; import { ipcMain, WebContents } from 'electron'; import fs from 'fs-extra'; import clone from 'lodash.clonedeep'; @@ -26,7 +26,7 @@ interface RtvExtensionStorage { scriptContent: string; vm: NodeVM; script: VMScript; - extension: EditableRealtimeValue; + extension: EditableVariable; } const logger = new Logger({ name: 'extensions' }); @@ -41,7 +41,7 @@ export default class ExtensionManager { this.extensionService = extensionService; } - async registerRtv(event: IpcEvent, projectId: string, extensionPath: string): Promise { + async registerRtv(event: IpcEvent, projectId: string, extensionPath: string): Promise { if (!this.projectExtensions[projectId]) this.projectExtensions[projectId] = {}; @@ -57,7 +57,7 @@ export default class ExtensionManager { sandbox: { beakApi: { log: (level: LogLevel, message: string) => (logger[level] ?? logger.warn)(message), - parseValueParts: (_ctx: unknown, _parts: unknown, _recursiveSet: unknown) => [], + parseValueSections: (_ctx: unknown, _parts: unknown, _recursiveSet: unknown) => [], }, }, }); @@ -71,7 +71,7 @@ export default class ExtensionManager { const compiledScript = new VMScript(scriptContent); const extensionContext = extensionVm.run(compiledScript); - const extension = extensionContext?.default as EditableRealtimeValue; + const extension = extensionContext?.default as EditableVariable; this.validateExtensionSignature(extension); this.projectExtensions[projectId][type] = { @@ -88,7 +88,7 @@ export default class ExtensionManager { version, filePath: extensionPath, valid: true, - realtimeValue: { + variable: { type, external: true, name: extension.name, @@ -119,11 +119,11 @@ export default class ExtensionManager { ) { const { vm, extension } = this.getExtensionContext(projectId, type); - vm.sandbox.beakApi.parseValueParts = async (ctx: Context, parts: ValueParts) => { + vm.sandbox.beakApi.parseValueSections = async (ctx: Context, parts: ValueSections) => { const uniqueSessionId = ksuid.generate('rtvparsersp').toString(); // send IPC request - this.extensionService.rtvParseValueParts(webContents, { + this.extensionService.rtvParseValueSections(webContents, { uniqueSessionId, context: ctx, parts, @@ -132,9 +132,9 @@ export default class ExtensionManager { return await new Promise(resolve => { ipcMain.on(this.extensionService.getChannel(), async (_event, message) => { - const { code, payload } = message as RequestPayload; + const { code, payload } = message as RequestPayload; - if (code !== ExtensionsMessages.RtvParseValuePartsResponse) + if (code !== ExtensionsMessages.RtvParseValueSectionsResponse) return; if (payload.uniqueSessionId !== uniqueSessionId) @@ -157,6 +157,10 @@ export default class ExtensionManager { async rtvEditorLoad(projectId: string, type: string, context: Context, payload: unknown) { const { extension } = this.getExtensionContext(projectId, type); + + if (extension.editor.load === void 0) + return payload; + const editorState = await extension.editor.load(context, payload); return clone(editorState); @@ -164,6 +168,10 @@ export default class ExtensionManager { async rtvEditorSave(projectId: string, type: string, context: Context, existingPayload: unknown, state: unknown) { const { extension } = this.getExtensionContext(projectId, type); + + if (extension.editor.save === void 0) + return state; + const payload = await extension.editor.save(context, existingPayload, state); return clone(payload); @@ -175,7 +183,7 @@ export default class ExtensionManager { if (!extensionStorage) throw new Squawk('unknown_registered_extension', { projectId, type }); - extensionStorage.vm.sandbox.beakApi.parseValueParts = () => []; + extensionStorage.vm.sandbox.beakApi.parseValueSections = () => []; return { vm: extensionStorage.vm, extension: extensionStorage.extension }; } @@ -185,11 +193,11 @@ export default class ExtensionManager { const packageJson = await fs.readJson(packageJsonPath); const { name, version, beakExtensionType, main } = packageJson; - if (beakExtensionType !== 'realtime-value') { + if (beakExtensionType !== 'variable') { throw new Squawk('invalid_extension_type', { extensionPath, packageJsonKey: 'beakExtensionType', - expected: 'realtime-value', + expected: 'variable', actual: beakExtensionType ?? '[missing]', }); } @@ -235,7 +243,7 @@ export default class ExtensionManager { return { main, name, scriptPath, version }; } - private validateExtensionSignature(extension: EditableRealtimeValue) { + private validateExtensionSignature(extension: EditableVariable) { if (!('name' in extension)) throw new Squawk('incorrect_extension_signature', { key: 'name', reason: 'missing' }); if (typeof extension.name !== 'string') diff --git a/apps-host/web/package.json b/apps-host/web/package.json index 0fea15441..373cd1464 100644 --- a/apps-host/web/package.json +++ b/apps-host/web/package.json @@ -26,8 +26,8 @@ "@beak/ksuid": "*", "@beak/ui": "*", "@esbuild-plugins/node-globals-polyfill": "^0.2.3", - "@getbeak/types": "^1.0.0", - "@getbeak/types-realtime-value": "^1.0.0", + "@getbeak/types": "^2.1.0", + "@getbeak/types-variables": "^2.1.0", "@isomorphic-git/lightning-fs": "^4.6.0", "path-browserify": "^1.0.1" }, diff --git a/apps-host/web/src/augmentations.d.ts b/apps-host/web/src/augmentations.d.ts index 078c1792c..60c7e19eb 100644 --- a/apps-host/web/src/augmentations.d.ts +++ b/apps-host/web/src/augmentations.d.ts @@ -33,28 +33,28 @@ declare module 'electron' { } } -declare module '@getbeak/types-realtime-value' { +declare module '@getbeak/types-variables' { interface GenericDictionary { [k: string]: any; } - interface RealtimeValueBase { + interface VariableBase { type: string; external: boolean; } - interface RealtimeValue { + interface Variable { /** * Gets the string value of the value, given the payload body * @param {Context} ctx The project context. * @param {TPayload} payload This instance of the value's payload data. - * @param {number} recursiveDepth The current depth of realtime value recursion. + * @param {number} recursiveDepth The current depth of value recursion. */ getValue: (ctx: Context, payload: TPayload, recursiveDepth: number) => Promise; } - interface EditableRealtimeValue { + interface EditableVariable { /** * Gets the string value of the value, given the payload body diff --git a/apps-host/web/src/ipc/encryption-service.ts b/apps-host/web/src/ipc/encryption-service.ts index 0c6b6d67c..169c6032a 100644 --- a/apps-host/web/src/ipc/encryption-service.ts +++ b/apps-host/web/src/ipc/encryption-service.ts @@ -1,5 +1,5 @@ import { IpcEncryptionServiceMain } from '@beak/common/ipc/encryption'; -import { ValueParts } from 'packages/types/values'; +import { ValueSections } from 'packages/types/values'; import getBeakHost from '../host'; import { webIpcMain } from './ipc'; @@ -72,7 +72,7 @@ service.registerEncryptObject(async (_event, { iv, payload }) => { return await getBeakHost().providers.aes.encryptString(json, encryption.key, iv); }); -service.registerDecryptObject(async (_event, { iv, payload }): Promise => { +service.registerDecryptObject(async (_event, { iv, payload }): Promise => { const projectId = getCurrentProjectId(); if (!projectId) return ['Project not loaded']; diff --git a/apps-web/marketing/src/features/home/components/molecules/FeatureOverview.tsx b/apps-web/marketing/src/features/home/components/molecules/FeatureOverview.tsx index d5b1ad2d8..122acdaa6 100644 --- a/apps-web/marketing/src/features/home/components/molecules/FeatureOverview.tsx +++ b/apps-web/marketing/src/features/home/components/molecules/FeatureOverview.tsx @@ -34,7 +34,7 @@ const FeatureOverview: React.FC> = () => { {'Powerful feature set'} - {'From support for large API projects, realtime values, '} + {'From support for large API projects, variables, '} {'rich value editors, to baked in project encryption, for '} {'your most secretive of secrets 🤫.'} @@ -48,12 +48,12 @@ const FeatureOverview: React.FC> = () => { /> - {'Realtime values'} + {'Variables'} - {'Realtime values are inline variables you can insert into '} - {'any part of your request that are calculated in real time '} - {'as you type, and as you send requests. '} + {'Variables are inline values you can insert into any part '} + {'of your request that are calculated dynamically in real '} + {'time as you type, and as you send requests.'} @@ -105,7 +105,7 @@ const FeatureOverview: React.FC> = () => { {'Coming soon, is an expansive extensions API, allowing you '} - {'to create custom extensions for realtime values, '} + {'to create custom extensions for variables, '} {'API workflows, and more. Make Beak your own.'} diff --git a/apps-web/marketing/src/features/pricing/components/organisms/PricingCard.tsx b/apps-web/marketing/src/features/pricing/components/organisms/PricingCard.tsx index 6c4ee974e..1a065e39a 100644 --- a/apps-web/marketing/src/features/pricing/components/organisms/PricingCard.tsx +++ b/apps-web/marketing/src/features/pricing/components/organisms/PricingCard.tsx @@ -20,7 +20,7 @@ const versions: Record = { items: [ 'Requests', 'Responses', - 'Realtime values', + 'Variables', 'Literally everything', ], }, @@ -30,7 +30,7 @@ const versions: Record = { items: [ 'Requests', 'Responses', - 'Realtime values', + 'Variables', 'Literally everything', ], }, @@ -40,7 +40,7 @@ const versions: Record = { items: [ 'Requests', 'Responses', - 'Realtime values', + 'Variables', 'Literally everything', ], }, diff --git a/docs/ksuid-resources.md b/docs/ksuid-resources.md index 50dac18e2..cf88933f0 100644 --- a/docs/ksuid-resources.md +++ b/docs/ksuid-resources.md @@ -12,6 +12,7 @@ While we don't use the environment portion of the KSUID (for obvious reasons), w | `flight` | A flight (or historical request) made by Beak. | | `query` | A query item, used in the request info. | | `header` | A header item, used in the request info. | -| `item` | An item in a variable group. Closely related to `group`. | -| `group` | A group in a variable group. Closely related to `item`. | -| `value` | A value linking an `item` and a `group` from a variable group. | +| `item` | An item in a variable set. Closely related to `set`. | +| `group` | A group in a variable group. Legacy, this is called `set` going forward. Closely related to `item`. | +| `set` | A set in a variable set. Closely related to `item`. | +| `value` | A value linking an `item` and a `set` from a variable set. | diff --git a/packages/common-host/package.json b/packages/common-host/package.json index fb80903d1..a80f38313 100644 --- a/packages/common-host/package.json +++ b/packages/common-host/package.json @@ -17,7 +17,7 @@ "dependencies": { "@beak/common": "*", "@beak/ksuid": "*", - "@getbeak/types": "^1.0.0", - "@getbeak/types-realtime-value": "^1.0.0" + "@getbeak/types": "^2.1.0", + "@getbeak/types-variables": "^2.1.0" } } diff --git a/packages/common-host/src/project/extensions.ts b/packages/common-host/src/project/extensions.ts index 05bf58ce6..266d035f8 100644 --- a/packages/common-host/src/project/extensions.ts +++ b/packages/common-host/src/project/extensions.ts @@ -25,8 +25,8 @@ export default class BeakExtensions extends BeakBase { '', '## Getting started', 'Below are some useful resources for getting started with Beak\'s extensions', - '- [Extensions manual](https://getbeak.notion.site/Extensions-realtime-values-4c16ca640b35460787056f8be815b904)', - '- [GitHub extension template](https://github.com/getbeak/realtime-value-extension-template)', + '- [Extensions manual](https://www.notion.so/getbeak/Extensions-4c16ca640b35460787056f8be815b904)', + '- [GitHub extension template](https://github.com/getbeak/extension-variable-template)', '', ].join('\n'); } diff --git a/packages/common-host/src/project/index.ts b/packages/common-host/src/project/index.ts index c50717d27..85f811d90 100644 --- a/packages/common-host/src/project/index.ts +++ b/packages/common-host/src/project/index.ts @@ -1,8 +1,7 @@ -import { ProjectEncryption } from '@beak/common/types/beak-project'; import ksuid from '@beak/ksuid'; import type { RequestNodeFile } from '@getbeak/types/nodes'; import type { ProjectFile } from '@getbeak/types/project'; -import type { VariableGroup } from '@getbeak/types/variable-groups'; +import type { VariableSet } from '@getbeak/types/variable-sets'; import git from 'isomorphic-git'; import { BeakBase, Providers } from '../base'; @@ -62,21 +61,27 @@ export default class BeakProject extends BeakBase { }, }; - const productionGroupId = ksuid.generate('group').toString(); - const localGroupId = ksuid.generate('group').toString(); + const productionSetId = ksuid.generate('set').toString(); + const stagingSetId = ksuid.generate('set').toString(); + const developmentSetId = ksuid.generate('set').toString(); + const localSetId = ksuid.generate('set').toString(); const environmentIdentifierItemId = ksuid.generate('item').toString(); - const variableGroup: VariableGroup = { - groups: { - [productionGroupId]: 'Production', - [localGroupId]: 'Local', + const variableSet: VariableSet = { + sets: { + [productionSetId]: 'Production', + [stagingSetId]: 'Staging', + [developmentSetId]: 'Development', + [localSetId]: 'Local', }, items: { [environmentIdentifierItemId]: 'env_identifier', }, values: { - [`${productionGroupId}&${environmentIdentifierItemId}`]: ['prod'], - [`${localGroupId}&${environmentIdentifierItemId}`]: ['local'], + [`${productionSetId}&${environmentIdentifierItemId}`]: ['production'], + [`${stagingSetId}&${environmentIdentifierItemId}`]: ['staging'], + [`${developmentSetId}&${environmentIdentifierItemId}`]: ['development'], + [`${localSetId}&${environmentIdentifierItemId}`]: ['local'], }, }; @@ -96,13 +101,13 @@ export default class BeakProject extends BeakBase { await this.p.node.fs.promises.readFile(this.p.node.path.join(projectFolderPath, 'tree', 'Request.json'), 'utf8'); - // Create variable groups structure + // Create variable sets structure await this.p.node.fs.promises.mkdir( - this.p.node.path.join(projectFolderPath, 'variable-groups'), + this.p.node.path.join(projectFolderPath, 'variable-sets'), ); await this.p.node.fs.promises.writeFile( - this.p.node.path.join(projectFolderPath, 'variable-groups', 'Environment.json'), - JSON.stringify(variableGroup, null, '\t'), + this.p.node.path.join(projectFolderPath, 'variable-sets', 'Environment.json'), + JSON.stringify(variableSet, null, '\t'), 'utf8', ); @@ -165,7 +170,7 @@ export default class BeakProject extends BeakBase { try { // TODO(afr): validate schema of project file! projectFile = JSON.parse(projectFileJson) as ProjectFile; - } catch (error) { + } catch { return null; } @@ -195,7 +200,7 @@ export default class BeakProject extends BeakBase { const profileFile: ProjectFile = { id: projectId ?? ksuid.generate('project').toString(), name, - version: '0.3.0', + version: '0.4.0', }; await this.p.node.fs.promises.writeFile( diff --git a/packages/common-host/src/project/migrations/standard.ts b/packages/common-host/src/project/migrations/standard.ts index f4b2b27da..35a96794a 100644 --- a/packages/common-host/src/project/migrations/standard.ts +++ b/packages/common-host/src/project/migrations/standard.ts @@ -25,8 +25,9 @@ export default class BeakStandardMigrations extends BeakBase { private readonly beakExtensions: BeakExtensions; private readonly migrationHistory: Record = { - '0.2.0': this.handle_0_2_0_to_0_2_1, // Migrate from 0.2.0 -> 0.2.1 - '0.2.1': this.handle_0_2_1_to_0_3_0, // Migrate from 0.2.1 -> 0.3.0 + '0.2.0': this.handle_0_2_0_to_0_2_1.bind(this), // Migrate from 0.2.0 -> 0.2.1 + '0.2.1': this.handle_0_2_1_to_0_3_0.bind(this), // Migrate from 0.2.1 -> 0.3.0 + '0.3.0': this.handle_0_3_0_to_0_4_0.bind(this), // Migrate from 0.3.0 -> 0.4.0 } as const; constructor(providers: Providers, beakExtensions: BeakExtensions) { @@ -58,6 +59,18 @@ export default class BeakStandardMigrations extends BeakBase { } } + /** + * Handles the migration of a project file from version 0.2.0 to 0.2.1. + * + * This function checks for the existence of a `supersecret.json` file in the project's `.beak` directory. + * If the file exists, it reads and parses the file to extract encryption details. + * The extracted encryption details are then set for the project using the `setProjectEncryption` method. + * Finally, the `supersecret.json` file is removed and the project file version is updated to 0.2.1. + * + * @param projectFile - The project file object that needs to be migrated. + * @param projectFolderPath - The path to the project folder. + * @returns A promise that resolves when the migration is complete. + */ private async handle_0_2_0_to_0_2_1(projectFile: ProjectFile, projectFolderPath: string): Promise { const supersecretFilePath = this.p.node.path.join(projectFolderPath, '.beak', 'supersecret.json'); @@ -82,6 +95,19 @@ export default class BeakStandardMigrations extends BeakBase { } } + /** + * Handles the migration of a project file from version 0.2.1 to 0.3.0. + * + * This function checks if the 'extensions' directory exists within the project folder. + * If the directory does not exist, it creates the directory and adds a 'package.json' + * and 'README.md' file with the appropriate content. + * + * Finally, it updates the project file version to '0.3.0'. + * + * @param projectFile - The project file to be migrated. + * @param projectFolderPath - The path to the project folder. + * @returns A promise that resolves when the migration is complete. + */ private async handle_0_2_1_to_0_3_0(projectFile: ProjectFile, projectFolderPath: string): Promise { const extensionsPath = this.p.node.path.join(projectFolderPath, 'extensions'); @@ -91,7 +117,6 @@ export default class BeakStandardMigrations extends BeakBase { hasExtensions = true; // Only try and migrate if extensions don't exist... May be left over from beta testers - // eslint-disable-next-line no-sync if (!hasExtensions) { await this.p.node.fs.promises.mkdir(extensionsPath); @@ -112,6 +137,106 @@ export default class BeakStandardMigrations extends BeakBase { await this.changeProjectFileVersion(projectFile, projectFolderPath, '0.3.0'); } + /** + * Handles the migration of a project from version 0.3.0 to 0.4.0. + * + * This migration performs the following tasks: + * + * 1. Updates hidden files, replacing references to variable groups with variable sets. + * + * 2. Renames folders, changing 'realtime-values' to 'variables' and 'variable-groups' to 'variable-sets'. + * + * 3. Edits variable group files, replacing references to 'groups' with 'sets'. + * + * 4. Edits request files, replacing references to variable groups with variable sets. + * + * 5. Updates the project file version to '0.4.0'. + * + * @param projectFile - The project file to be migrated. + * @param projectFolderPath - The path to the project folder. + * @returns A promise that resolves when the migration is complete. + */ + private async handle_0_3_0_to_0_4_0(projectFile: ProjectFile, projectFolderPath: string): Promise { + // Edit hidden files + await this.replaceStringInBeakFile(projectFolderPath, '.beak/editor.json', 'selectedVariableGroups', 'selectedVariableSets'); + await this.replaceStringInBeakFile(projectFolderPath, '.beak/tab-state.json', '{"type":"variable_group_editor"', '"type":"variable_set_editor"'); + await this.replaceStringInBeakFile(projectFolderPath, '.beak/sidebar.json', 'beak.project.variable-groups', 'beak.project.variable-sets'); + + // Rename folders + if (await fileExists(this, this.p.node.path.join(projectFolderPath, '.beak', 'realtime-values'))) { + await this.p.node.fs.promises.rename( + this.p.node.path.join(projectFolderPath, '.beak', 'realtime-values'), + this.p.node.path.join(projectFolderPath, '.beak', 'variables'), + ); + } + + if (await fileExists(this, this.p.node.path.join(projectFolderPath, 'variable-groups'))) { + await this.p.node.fs.promises.rename( + this.p.node.path.join(projectFolderPath, 'variable-groups'), + this.p.node.path.join(projectFolderPath, 'variable-sets'), + ); + } + + // Edit variable group files + const variableSetFilePaths = await this.p.node.fs.promises.readdir( + this.p.node.path.join(projectFolderPath, 'variable-sets'), + { withFileTypes: true }, + ); + + await Promise.all(variableSetFilePaths.map(async file => { + if (!file.isFile() || !file.name.endsWith('.json')) + return; + + await this.replaceStringInFile( + this.p.node.path.join(file.parentPath, file.name), + '"groups"', '"sets"', + ); + })); + + // Edit requests + const requestFilePaths = await this.p.node.fs.promises.readdir( + this.p.node.path.join(projectFolderPath, 'tree'), + { withFileTypes: true, recursive: true }, + ); + + await Promise.all(requestFilePaths.map(async file => { + if (!file.isFile() || !file.name.endsWith('.json')) + return; + + await this.replaceStringInFile( + this.p.node.path.join(file.parentPath, file.name), + '"type": "variable_group_item"', + '"type": "variable_set_item"', + ); + })); + + await this.changeProjectFileVersion(projectFile, projectFolderPath, '0.4.0'); + } + + private async replaceStringInBeakFile( + projectFolderPath: string, + filePath: string, + search: string, + replace: string, + ) { + const fullFilePath = this.p.node.path.join(projectFolderPath, filePath); + + if (!await fileExists(this, fullFilePath)) + return; + + await this.replaceStringInFile(fullFilePath, search, replace); + } + + private async replaceStringInFile(filePath: string, search: string, replace: string) { + if (!await fileExists(this, filePath)) + return; + + const fileContent = await this.p.node.fs.promises.readFile(filePath, 'utf8'); + const updatedFile = fileContent.replace(new RegExp(search, 'g'), replace); + + await this.p.node.fs.promises.writeFile(filePath, updatedFile, 'utf8'); + } + private async changeProjectFileVersion( projectFile: ProjectFile, projectFolderPath: string, @@ -123,7 +248,7 @@ export default class BeakStandardMigrations extends BeakBase { }; await this.p.node.fs.promises.writeFile( - projectFolderPath, + this.p.node.path.join(projectFolderPath, 'project.json'), JSON.stringify(newProjectFile, null, '\t'), { encoding: 'utf8' }, ); diff --git a/packages/common/package.json b/packages/common/package.json index 9fb8356c2..459503018 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -16,8 +16,8 @@ }, "dependencies": { "@beak/ksuid": "*", - "@getbeak/types": "^1.0.0", - "@getbeak/types-realtime-value": "^1.0.0" + "@getbeak/types": "^2.1.0", + "@getbeak/types-variables": "^2.1.0" }, "devDependencies": { "chokidar": "^4.0.1", diff --git a/packages/common/src/augmentations.d.ts b/packages/common/src/augmentations.d.ts index dab00d865..ec2aedc05 100644 --- a/packages/common/src/augmentations.d.ts +++ b/packages/common/src/augmentations.d.ts @@ -1,7 +1,7 @@ -import '@getbeak/types-realtime-value'; +import '@getbeak/types-variables'; -declare module '@getbeak/types-realtime-value' { - interface RealtimeValueBase { +declare module '@getbeak/types-variables' { + interface VariableBase { type: string; external: boolean; } diff --git a/packages/common/src/ipc/extensions.ts b/packages/common/src/ipc/extensions.ts index 60cb9b633..03b50640b 100644 --- a/packages/common/src/ipc/extensions.ts +++ b/packages/common/src/ipc/extensions.ts @@ -1,8 +1,8 @@ -import { Context, ValueParts } from '@getbeak/types/values'; -import { UISection } from '@getbeak/types-realtime-value'; +import { Context, ValueSections } from '@getbeak/types/values'; +import { UISection } from '@getbeak/types-variables'; import type { IpcMain, WebContents } from 'electron'; -import { RealtimeValueExtension } from '../types/extensions'; +import { VariableExtension } from '../types/extensions'; import { IpcServiceMain, IpcServiceRenderer, Listener, PartialIpcRenderer } from './ipc'; export const ExtensionsMessages = { @@ -12,8 +12,8 @@ export const ExtensionsMessages = { RtvEditorCreateUserInterface: 'rtv_editor_create_user_interface', RtvEditorLoad: 'rtv_editor_load', RtvEditorSave: 'rtv_editor_save', - RtvParseValueParts: 'rtv_parse_value_parts', - RtvParseValuePartsResponse: 'rtv_parse_value_parts_response', + RtvParseValueSections: 'rtv_parse_value_parts', + RtvParseValueSectionsResponse: 'rtv_parse_value_parts_response', }; interface RegisterRtvPayload { extensionFilePath: string } @@ -41,13 +41,13 @@ interface RtvEditorSave extends RtvBase { state: unknown; } -export interface RtvParseValueParts extends Omit { +export interface RtvParseValueSections extends Omit { uniqueSessionId: string; recursiveDepth: number; - parts: ValueParts; + parts: ValueSections; } -export interface RtvParseValuePartsResponse { +export interface RtvParseValueSectionsResponse { uniqueSessionId: string; parsed: string; } @@ -57,7 +57,7 @@ export class IpcExtensionsServiceRenderer extends IpcServiceRenderer { super('extensions', ipc); } - async registerRtv(payload: RegisterRtvPayload): Promise { + async registerRtv(payload: RegisterRtvPayload): Promise { return await this.invoke(ExtensionsMessages.RegisterRtv, payload); } @@ -81,8 +81,8 @@ export class IpcExtensionsServiceRenderer extends IpcServiceRenderer { return await this.invoke(ExtensionsMessages.RtvEditorSave, payload); } - registerRtvParseValueParts(fn: Listener) { - this.registerListener(ExtensionsMessages.RtvParseValueParts, fn); + registerRtvParseValueSections(fn: Listener) { + this.registerListener(ExtensionsMessages.RtvParseValueSections, fn); } } @@ -91,7 +91,7 @@ export class IpcExtensionsServiceMain extends IpcServiceMain { super('extensions', ipc); } - registerRegisterRtv(fn: Listener) { + registerRegisterRtv(fn: Listener) { this.registerListener(ExtensionsMessages.RegisterRtv, fn); } @@ -115,9 +115,9 @@ export class IpcExtensionsServiceMain extends IpcServiceMain { this.registerListener(ExtensionsMessages.RtvEditorSave, fn); } - rtvParseValueParts(wc: WebContents, payload: RtvParseValueParts) { + rtvParseValueSections(wc: WebContents, payload: RtvParseValueSections) { wc.send(this.channel, { - code: ExtensionsMessages.RtvParseValueParts, + code: ExtensionsMessages.RtvParseValueSections, payload, }); } diff --git a/packages/common/src/types/beak-hub.d.ts b/packages/common/src/types/beak-hub.d.ts index 77705f50a..4edabef65 100644 --- a/packages/common/src/types/beak-hub.d.ts +++ b/packages/common/src/types/beak-hub.d.ts @@ -32,7 +32,7 @@ export interface RequestPreference { } export interface EditorPreferences { - selectedVariableGroups: Record; + selectedVariableSets: Record; } export type SidebarVariant = 'project' | 'variables'; diff --git a/packages/common/src/types/beak-project.d.ts b/packages/common/src/types/beak-project.d.ts index 19f1c02ef..2b9448ca2 100644 --- a/packages/common/src/types/beak-project.d.ts +++ b/packages/common/src/types/beak-project.d.ts @@ -4,7 +4,7 @@ export interface ProjectEncryption { } // NOTE(afr): Adding a new tab item? Don't forget to update tab-preferences schema too! -export type TabItem = RequestTabItem | VariableGroupEditorTabItem | NewProjectIntroTabItem; +export type TabItem = RequestTabItem | VariableSetEditorTabItem | NewProjectIntroTabItem; export interface TabBase { type: string; @@ -17,8 +17,8 @@ export interface RequestTabItem extends TabBase { payload: string; } -export interface VariableGroupEditorTabItem extends TabBase { - type: 'variable_group_editor'; +export interface VariableSetEditorTabItem extends TabBase { + type: 'variable_set_editor'; payload: string; } diff --git a/packages/common/src/types/extensions.d.ts b/packages/common/src/types/extensions.d.ts index 9a08e3a85..eb47d9a5b 100644 --- a/packages/common/src/types/extensions.d.ts +++ b/packages/common/src/types/extensions.d.ts @@ -1,12 +1,12 @@ -import { RealtimeValueInformation } from '@getbeak/types-realtime-value'; +import { VariableStaticInformation } from '@getbeak/types-variables'; -export interface RealtimeValueExtension { +export interface VariableExtension { name: string; version: string; filePath: string; valid: true; - realtimeValue: { + variable: { type: string; editable: boolean; - } & RealtimeValueInformation; + } & VariableStaticInformation; } diff --git a/packages/design-system/src/animations.ts b/packages/design-system/src/animations.ts new file mode 100644 index 000000000..051cc6bf2 --- /dev/null +++ b/packages/design-system/src/animations.ts @@ -0,0 +1,23 @@ +import { keyframes } from 'styled-components'; + +export const scaleIn = keyframes` + 0% { + transform: scale(.97); + opacity: 0; + } + + 100% { + transform: scale(1); + opacity: 1; + } +`; + +export const fadeIn = keyframes` + 0% { + opacity: 0; + } + + 100% { + opacity: 1; + } +`; diff --git a/packages/requester-node/package.json b/packages/requester-node/package.json index afbee477b..69344f8c1 100644 --- a/packages/requester-node/package.json +++ b/packages/requester-node/package.json @@ -16,7 +16,7 @@ }, "dependencies": { "@beak/common": "*", - "@getbeak/types": "^1.0.0", + "@getbeak/types": "^2.1.0", "node-fetch": "^2.6.1" }, "devDependencies": { diff --git a/packages/types-realtime-value/README.md b/packages/types-realtime-value/README.md deleted file mode 100755 index f34c9615b..000000000 --- a/packages/types-realtime-value/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# `@getbeak/types-realtime-value` - -Contains the TypeScript definitions for Beak's Realtime Value interfaces. diff --git a/packages/types-realtime-value/.npmignore b/packages/types-variables/.npmignore similarity index 100% rename from packages/types-realtime-value/.npmignore rename to packages/types-variables/.npmignore diff --git a/packages/types-variables/README.md b/packages/types-variables/README.md new file mode 100755 index 000000000..2c68ee306 --- /dev/null +++ b/packages/types-variables/README.md @@ -0,0 +1,3 @@ +# `@getbeak/types-variables` + +Contains the TypeScript definitions for Beak Variables. diff --git a/packages/types-realtime-value/index.d.ts b/packages/types-variables/index.d.ts similarity index 70% rename from packages/types-realtime-value/index.d.ts rename to packages/types-variables/index.d.ts index 172d2e9e2..f2b965bc5 100755 --- a/packages/types-realtime-value/index.d.ts +++ b/packages/types-variables/index.d.ts @@ -1,9 +1,9 @@ /* eslint-disable max-len */ import type { Context } from '@getbeak/types/values'; -export interface RealtimeValueBase { } +export interface VariableBase { } -interface RealtimeValueGetter { +interface VariableGetter { /** * Gets the string value of the value, given the payload body @@ -17,7 +17,7 @@ interface GenericDictionary { [k: string]: any; } -export interface RealtimeValueInformation extends RealtimeValueBase { +export interface VariableStaticInformation extends VariableBase { /** * The public facing name of your extension. @@ -30,12 +30,14 @@ export interface RealtimeValueInformation extends RealtimeValueBase { description: string; /** - * Optional keywords used by Beak when searching for realtime values when the user is typing. + * Optional keywords used by Beak when searching for variables when the user is + * typing. */ keywords?: string[]; /** - * Denotes if the value's output is sensitive, and will be hidden by default in the UI and in copied responses. + * Denotes if the value's output is sensitive, and will be hidden by default in the UI + * and in copied responses. */ sensitive: boolean; @@ -45,19 +47,26 @@ export interface RealtimeValueInformation extends RealtimeValueBase { attributes: Attributes; } -export interface RealtimeValue extends RealtimeValueGetter, RealtimeValueInformation { +export interface Variable extends VariableGetter, VariableStaticInformation { /** * Creates a default payload, if the user doesn't specify any data. * @param {Context} ctx The project context. */ createDefaultPayload: (ctx: Context) => Promise; + + /** + * Gets a name for the variable, with context of the payload of this specific instance of the variable. + * @param {TPayload} payload This instance of the value's payload data. + */ + getContextAwareName?: (payload: TPayload) => string; } -export interface EditableRealtimeValue extends RealtimeValue { +export interface EditableVariable extends Variable { /** - * Details how Beak and user's should interact with the value editor for your realtime value. + * Details how Beak and user's should interact with the value editor for your + * variable. */ editor: Editor; } @@ -79,19 +88,23 @@ interface Editor Promise[]>; /** - * If the payload data isn't the same as the editor state, this will convert Payload -> State + * If the payload data isn't the same as the editor state, this will convert + * Payload -> State. This is optional if no modification of the payload is needed to + * create the editor state. * @param {Context} ctx The project context. * @param {TPayload} payload This instance of the value's payload data. */ - load: (ctx: Context, payload: TPayload) => Promise; + load?: (ctx: Context, payload: TPayload) => Promise; /** - * If the payload data isn't the same as the editor state, this will convert State -> Payload + * If the payload data isn't the same as the editor state, this will convert + * State -> Payload. This is optional if no modification of the state is needed to + * create the payload. * @param {Context} ctx The project context. * @param {TPayload} existingPayload This existing instance of the value's payload data. * @param {TEditorState} state This instance of the updated state data. */ - save: (ctx: Context, existingPayload: TPayload, state: TEditorState) => Promise; + save?: (ctx: Context, existingPayload: TPayload, state: TEditorState) => Promise; } export type UISection> = @@ -146,7 +159,7 @@ declare global { type Level = 'info' | 'warn' | 'error'; interface Beak { - parseValueParts: (ctx: Context, parts: unknown[]) => Promise; + parseValueSections: (ctx: Context, parts: unknown[]) => Promise; log: (level: Level, message: string) => void; } diff --git a/packages/types-realtime-value/package.json b/packages/types-variables/package.json similarity index 63% rename from packages/types-realtime-value/package.json rename to packages/types-variables/package.json index b2118a47f..f4788b782 100755 --- a/packages/types-realtime-value/package.json +++ b/packages/types-variables/package.json @@ -1,9 +1,9 @@ { - "name": "@getbeak/types-realtime-value", - "version": "1.0.1", + "name": "@getbeak/types-variables", + "version": "2.1.0", "private": false, - "description": "Beak types for realtime value types", - "homepage": "https://github.com/getbeak/beak/tree/master/packages/types-realtime-value", + "description": "Types for Beak Variables", + "homepage": "https://github.com/getbeak/beak/tree/master/packages/types-variables", "license": "MIT", "contributors": [ { @@ -17,10 +17,9 @@ "repository": { "type": "git", "url": "https://github.com/getbeak/beak.git", - "directory": "packages/types-realtime-value" + "directory": "packages/types-variables" }, "dependencies": { - "@getbeak/types": "1.1.0" - }, - "scripts": {} + "@getbeak/types": "2.1.0" + } } diff --git a/packages/types-realtime-value/tsconfig.json b/packages/types-variables/tsconfig.json similarity index 100% rename from packages/types-realtime-value/tsconfig.json rename to packages/types-variables/tsconfig.json diff --git a/packages/types/body-editor-json.d.ts b/packages/types/body-editor-json.d.ts index ac6ce18fd..a212167d2 100644 --- a/packages/types/body-editor-json.d.ts +++ b/packages/types/body-editor-json.d.ts @@ -1,4 +1,4 @@ -import { ValueParts } from './values'; +import { ValueSections } from './values'; export type EntryMap = Record; export type EntryType = 'string' | 'number' | 'boolean' | 'null' | 'object' | 'array'; @@ -13,12 +13,12 @@ export interface NamedEntryBase { name: string } export interface StringEntry extends Base { type: 'string'; - value: ValueParts; + value: ValueSections; } export interface NumberEntry extends Base { type: 'number'; - value: ValueParts; + value: ValueSections; } export interface BooleanEntry extends Base { diff --git a/packages/types/index.d.ts b/packages/types/index.d.ts index 2a68f8206..ddde0d65d 100644 --- a/packages/types/index.d.ts +++ b/packages/types/index.d.ts @@ -6,4 +6,4 @@ export { default as Request } from './request'; export { default as Response } from './response'; export { default as Squawk } from './squawk'; export { default as Values } from './values'; -export { default as VariableGroups } from './variable-groups'; +export { default as VariableSets } from './variable-sets'; diff --git a/packages/types/package.json b/packages/types/package.json index 4bb37577e..378b1a5ca 100755 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@getbeak/types", - "version": "1.1.0", + "version": "2.1.0", "private": false, "description": "Just general beak types", "homepage": "https://github.com/getbeak/beak/tree/master/packages/types", diff --git a/packages/types/request.d.ts b/packages/types/request.d.ts index 984e86fbe..6f1d3d446 100644 --- a/packages/types/request.d.ts +++ b/packages/types/request.d.ts @@ -1,9 +1,9 @@ import { EntryMap } from './body-editor-json'; -import { ValueParts } from './values'; +import { ValueSections } from './values'; export interface RequestOverview { verb: string; - url: ValueParts; + url: ValueSections; query: Record; headers: Record; body: RequestBody; @@ -62,6 +62,6 @@ export interface RequestOptions { export interface ToggleKeyValue { name: string; - value: ValueParts; + value: ValueSections; enabled: boolean; } diff --git a/packages/types/values.d.ts b/packages/types/values.d.ts index 5e3d17eae..e181b6175 100644 --- a/packages/types/values.d.ts +++ b/packages/types/values.d.ts @@ -1,13 +1,13 @@ import { FlightHistory } from './flight'; import { Tree } from './nodes'; -import { VariableGroups } from './variable-groups'; +import { VariableSets } from './variable-sets'; -export type ValueParts = ValuePart[]; -export type ValuePart = string | { type: string; payload: unknown }; +export type ValueSections = ValueSection[]; +export type ValueSection = string | { type: string; payload: unknown }; export interface Context { - selectedGroups: Record; - variableGroups: VariableGroups; + selectedSets: Record; + variableSets: VariableSets; projectTree: Tree; flightHistory: Record; currentRequestId?: string; diff --git a/packages/types/variable-groups.d.ts b/packages/types/variable-groups.d.ts deleted file mode 100644 index 9a31bf763..000000000 --- a/packages/types/variable-groups.d.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { ValueParts } from './values'; - -export type VariableGroups = Record; - -export interface VariableGroup { - groups: Record; - items: Record; - values: Record; -} diff --git a/packages/types/variable-sets.d.ts b/packages/types/variable-sets.d.ts new file mode 100644 index 000000000..0d2edeb3d --- /dev/null +++ b/packages/types/variable-sets.d.ts @@ -0,0 +1,9 @@ +import { ValueSections } from './values'; + +export type VariableSets = Record; + +export interface VariableSet { + sets: Record; + items: Record; + values: Record; +} diff --git a/packages/ui/package.json b/packages/ui/package.json index 2cc93b592..a1f4a9d34 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -24,8 +24,8 @@ "@beak/common": "*", "@beak/design-system": "*", "@beak/ksuid": "*", - "@getbeak/types": "^1.0.0", - "@getbeak/types-realtime-value": "^1.0.0" + "@getbeak/types": "^2.1.0", + "@getbeak/types-variables": "^2.1.0" }, "devDependencies": { "@fortawesome/fontawesome-svg-core": "^6.6.0", diff --git a/packages/ui/src/augmentations.d.ts b/packages/ui/src/augmentations.d.ts index 3ef6f80b9..992495458 100644 --- a/packages/ui/src/augmentations.d.ts +++ b/packages/ui/src/augmentations.d.ts @@ -32,28 +32,34 @@ declare module 'electron' { } } -declare module '@getbeak/types-realtime-value' { +declare module '@getbeak/types-variables' { interface GenericDictionary { [k: string]: any; } - interface RealtimeValueBase { + interface VariableBase { type: string; external: boolean; } - interface RealtimeValue { + interface Variable { /** * Gets the string value of the value, given the payload body * @param {Context} ctx The project context. * @param {TPayload} payload This instance of the value's payload data. - * @param {number} recursiveDepth The current depth of realtime value recursion. + * @param {number} recursiveDepth The current depth of value recursion. */ getValue: (ctx: Context, payload: TPayload, recursiveDepth: number) => Promise; + + /** + * Gets a name for the variable, with context of the payload of this specific instance of the variable. + * @param {TPayload} payload This instance of the value's payload data. + */ + getContextAwareName?: (payload: TPayload) => string; } - interface EditableRealtimeValue { + interface EditableVariable { /** * Gets the string value of the value, given the payload body @@ -61,5 +67,11 @@ declare module '@getbeak/types-realtime-value' { * @param {TPayload} payload This instance of the value's payload data. */ getValue: (ctx: Context, payload: TPayload, recursiveDepth: number) => Promise; + + /** + * Gets a name for the variable, with context of the payload of this specific instance of the variable. + * @param {TPayload} payload This instance of the value's payload data. + */ + getContextAwareName?: (payload: TPayload) => string; } } diff --git a/packages/ui/src/components/molecules/NewProjectIntro.tsx b/packages/ui/src/components/molecules/NewProjectIntro.tsx index c7630e56b..74932a644 100644 --- a/packages/ui/src/components/molecules/NewProjectIntro.tsx +++ b/packages/ui/src/components/molecules/NewProjectIntro.tsx @@ -41,13 +41,13 @@ const NewProjectIntro: React.FC> = () => { - {'Variable groups'} + {'Variable sets'} - {'Easily share common values between requests, and group them '} - {'by trait.'} + {'Easily share common variables between requests, and group them '} + {'in sets.'} - @@ -61,12 +61,12 @@ const NewProjectIntro: React.FC> = () => { - {'Realtime values'} + {'Variables'} {'Variables can be inserted into your request, and are '} {'calculated for every request.'} - diff --git a/packages/ui/src/components/molecules/Tooltips.tsx b/packages/ui/src/components/molecules/Tooltips.tsx index 1fe126a6a..4557692b8 100644 --- a/packages/ui/src/components/molecules/Tooltips.tsx +++ b/packages/ui/src/components/molecules/Tooltips.tsx @@ -66,7 +66,7 @@ const tooltips: TooltipDefinition[] = [{ }, { anchor: 'tt-omni-bar-finder-request-uri', }, { - anchor: 'tt-realtime-values-renderer-extension-missing', + anchor: 'tt-variables-renderer-extension-missing', }, { anchor: 'tt-sidebar-menu-item', }]; diff --git a/packages/ui/src/containers/ProjectMain.tsx b/packages/ui/src/containers/ProjectMain.tsx index e75741b92..c355907a3 100644 --- a/packages/ui/src/containers/ProjectMain.tsx +++ b/packages/ui/src/containers/ProjectMain.tsx @@ -30,11 +30,11 @@ const ProjectMain: React.FC = () => { const [setup, setSetup] = useState(false); const collapsedSidebar = useAppSelector(s => s.global.preferences.sidebar.collapsed.sidebar); const project = useAppSelector(s => s.global.project); - const variableGroups = useAppSelector(s => s.global.variableGroups); + const variableSets = useAppSelector(s => s.global.variableSets); const tabs = useAppSelector(s => s.features.tabs); const activeTab = tabs.activeTabs.find(t => t.payload === tabs.selectedTab); - const loaded = project.loaded && variableGroups.loaded && tabs.loaded; + const loaded = project.loaded && variableSets.loaded && tabs.loaded; const projectLoading = useProjectLoading(loaded, setup); useApplicationMenuEventListener(); diff --git a/packages/ui/src/features/basic-table-editor/components/BasicTableEditor.tsx b/packages/ui/src/features/basic-table-editor/components/BasicTableEditor.tsx index a977cadac..df4f3eb78 100644 --- a/packages/ui/src/features/basic-table-editor/components/BasicTableEditor.tsx +++ b/packages/ui/src/features/basic-table-editor/components/BasicTableEditor.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { TypedObject } from '@beak/common/helpers/typescript'; import DebouncedInput from '@beak/ui/components/atoms/DebouncedInput'; -import { ValueParts } from '@beak/ui/features/realtime-values/values'; +import { ValueSections } from '@beak/ui/features/variables/values'; import type { ToggleKeyValue } from '@getbeak/types/request'; import styled from 'styled-components'; @@ -27,7 +27,7 @@ interface BasicTableEditorProps { disableItemToggle?: boolean; addItem?: () => void; - updateItem?: (type: keyof ToggleKeyValue, ident: string, value: string | boolean | ValueParts) => void; + updateItem?: (type: keyof ToggleKeyValue, ident: string, value: string | boolean | ValueSections) => void; removeItem?: (ident: string) => void; } diff --git a/packages/ui/src/features/basic-table-editor/parsers.ts b/packages/ui/src/features/basic-table-editor/parsers.ts index b39327b11..42ef9c6ac 100644 --- a/packages/ui/src/features/basic-table-editor/parsers.ts +++ b/packages/ui/src/features/basic-table-editor/parsers.ts @@ -3,7 +3,7 @@ import ksuid from '@beak/ksuid'; import type { ToggleKeyValue } from '@getbeak/types/request'; import type { Context } from '@getbeak/types/values'; -import { parseValueParts } from '../realtime-values/parser'; +import { parseValueSections } from '../variables/parser'; const queryStringRegex = /[a-z0-9%=+-[\]]+/; @@ -12,7 +12,7 @@ export async function convertKeyValueToString(context: Context, items: Record i.enabled); const resolved = await Promise.all(eligible.map(async e => ({ name: e.name, - value: await parseValueParts(context, e.value), + value: await parseValueSections(context, e.value), }))); for (const resolve of resolved) diff --git a/packages/ui/src/features/graphql-editor/components/GraphQlQueryEditor.tsx b/packages/ui/src/features/graphql-editor/components/GraphQlQueryEditor.tsx index ef461fb5b..9cfc00550 100644 --- a/packages/ui/src/features/graphql-editor/components/GraphQlQueryEditor.tsx +++ b/packages/ui/src/features/graphql-editor/components/GraphQlQueryEditor.tsx @@ -17,8 +17,8 @@ import { initializeMode } from 'monaco-graphql/esm/initializeMode'; import { RequestBodyGraphQl } from 'packages/types/request'; import styled from 'styled-components'; -import useRealtimeValueContext from '../../realtime-values/hooks/use-realtime-value-context'; -import { parseValueParts } from '../../realtime-values/parser'; +import useVariableContext from '../../variables/hooks/use-variable-context'; +import { parseValueSections } from '../../variables/parser'; import { extractVariableNamesFromQuery } from '../utils'; import GraphQlError from './molecules/GraphQlError'; import GraphQlLoading from './molecules/GraphQlLoading'; @@ -36,8 +36,8 @@ const GraphQlQueryEditor: React.FC = props => { const [schemaFlightId, setSchemaFlightId] = useState('impossible-yolo'); const [hasSchema, setHasSchema] = useState(() => Boolean(schemaCache[node.id])); const [schemaFetchError, setSchemaFetchError] = useState(null); - const variableGroups = useAppSelector(s => s.global.variableGroups.variableGroups); - const selectedGroups = useAppSelector(s => s.global.preferences.editor.selectedVariableGroups); + const variableSets = useAppSelector(s => s.global.variableSets.variableSets); + const selectedGroups = useAppSelector(s => s.global.preferences.editor.selectedVariableSets); const schemaFlight = useAppSelector(s => s.global.flight.flightHistory[node.id]?.history[schemaFlightId]); const operationsUri = `${node.id}/operations.graphql`; @@ -45,7 +45,7 @@ const GraphQlQueryEditor: React.FC = props => { const schemaUri = `${node.id}/schema.graphql`; const body = node.info.body as RequestBodyGraphQl; - const context = useRealtimeValueContext(node.id); + const context = useVariableContext(node.id); // TODO(afr): Also run this when schema _changes_ useEffect(() => { @@ -108,7 +108,7 @@ const GraphQlQueryEditor: React.FC = props => { .filter(key => node.info.headers[key].enabled) .map(async key => ({ key: node.info.headers[key].name, - value: await parseValueParts(context, node.info.headers[key].value), + value: await parseValueSections(context, node.info.headers[key].value), }))); const graphQlBody: FetcherParams = { query: getIntrospectionQuery() }; @@ -154,7 +154,7 @@ const GraphQlQueryEditor: React.FC = props => { node.info.verb, node.info.url, JSON.stringify(node.info.query), - JSON.stringify(variableGroups), + JSON.stringify(variableSets), JSON.stringify(selectedGroups), ]); diff --git a/packages/ui/src/features/json-editor/parsers.ts b/packages/ui/src/features/json-editor/parsers.ts index 4fbfbeea2..3fdbc2726 100644 --- a/packages/ui/src/features/json-editor/parsers.ts +++ b/packages/ui/src/features/json-editor/parsers.ts @@ -3,7 +3,7 @@ import ksuid from '@beak/ksuid'; import type { Entries, EntryMap, NamedEntries, StringEntry } from '@getbeak/types/body-editor-json'; import type { Context } from '@getbeak/types/values'; -import { parseValueParts } from '../realtime-values/parser'; +import { parseValueSections } from '../variables/parser'; type JsonTypes = null | string | number | boolean | Record | unknown[]; @@ -27,10 +27,10 @@ async function convertEntry( return entry.value; case 'number': - return Number(await parseValueParts(context, entry.value)); + return Number(await parseValueSections(context, entry.value)); case 'string': - return await parseValueParts(context, entry.value); + return await parseValueSections(context, entry.value); case 'array': { const children = TypedObject diff --git a/packages/ui/src/features/omni-bar/components/Omnibar.tsx b/packages/ui/src/features/omni-bar/components/Omnibar.tsx index a09dc8615..e06781604 100644 --- a/packages/ui/src/features/omni-bar/components/Omnibar.tsx +++ b/packages/ui/src/features/omni-bar/components/Omnibar.tsx @@ -1,35 +1,15 @@ import React, { useEffect, useRef, useState } from 'react'; import { useDispatch } from 'react-redux'; +import { fadeIn, scaleIn } from '@beak/design-system/animations'; import { toHexAlpha } from '@beak/design-system/utils'; import { checkShortcut } from '@beak/ui/lib/keyboard-shortcuts'; import { useAppSelector } from '@beak/ui/store/redux'; -import styled, { keyframes } from 'styled-components'; +import styled from 'styled-components'; import { actions } from '../store'; import CommandsView from './organism/CommandsView'; import FinderView from './organism/FinderView'; -const scaleIn = keyframes` - 0% { - transform: scale(.97); - opacity: 0; - } - - 100% { - transform: scale(1); - opacity: 1; - } -`; -const fadeIn = keyframes` - 0% { - opacity: 0; - } - - 100% { - opacity: 1; - } -`; - const Omnibar: React.FC> = () => { const { open, mode } = useAppSelector(s => s.features.omniBar); const [content, setContent] = useState(''); diff --git a/packages/ui/src/features/omni-bar/components/organism/FinderView.tsx b/packages/ui/src/features/omni-bar/components/organism/FinderView.tsx index 1db8350cf..b71155e47 100644 --- a/packages/ui/src/features/omni-bar/components/organism/FinderView.tsx +++ b/packages/ui/src/features/omni-bar/components/organism/FinderView.tsx @@ -1,8 +1,8 @@ import React, { useEffect, useRef, useState } from 'react'; import { useDispatch } from 'react-redux'; import { TypedObject } from '@beak/common/helpers/typescript'; -import useRealtimeValueContext from '@beak/ui/features/realtime-values/hooks/use-realtime-value-context'; import { changeTab } from '@beak/ui/features/tabs/store/actions'; +import useVariableContext from '@beak/ui/features/variables/hooks/use-variable-context'; import { checkShortcut } from '@beak/ui/lib/keyboard-shortcuts'; import { useAppSelector } from '@beak/ui/store/redux'; import { movePosition } from '@beak/ui/utils/arrays'; @@ -24,7 +24,7 @@ const FinderView: React.FC> = ({ conten const flattened = TypedObject.values(tree).filter(t => t.type === 'request') as ValidRequestNode[]; const [matches, setMatches] = useState([]); const [active, setActive] = useState(-1); - const context = useRealtimeValueContext(); + const context = useVariableContext(); const activeRef = useRef(null); const fuse = new Fuse(flattened, { @@ -97,7 +97,7 @@ const FinderView: React.FC> = ({ conten {matches.length === 0 && ( - {'No matching requests found... sadface'} + {'No matching requests found'} )} {matches.map((k, idx) => { diff --git a/packages/ui/src/features/project-pane/components/ProjectPane.tsx b/packages/ui/src/features/project-pane/components/ProjectPane.tsx index 51c45ad8a..b1121ffd8 100644 --- a/packages/ui/src/features/project-pane/components/ProjectPane.tsx +++ b/packages/ui/src/features/project-pane/components/ProjectPane.tsx @@ -16,7 +16,7 @@ import TreeView from '../../tree-view/components/TreeView'; import { TreeViewItem } from '../../tree-view/types'; import RequestFlightStatus from './molecules/RequestFlightStatus'; import Git from './organisms/Git'; -import VariableGroups from './organisms/VariableGroups'; +import VariableSets from './organisms/VariableSets'; const ProjectPane: React.FC> = () => { const { id, tree, name } = useAppSelector(s => s.global.project); @@ -159,8 +159,8 @@ const ProjectPane: React.FC> = () => { - - + + > = () => { +const NoVariableSets: React.FC> = () => { const dispatch = useDispatch(); - function createVariableGroup() { + function createVariableSet() { dispatch(sidebarPreferenceSetSelected('variables')); - dispatch(createNewVariableGroup({ })); + dispatch(createNewVariableSet({ })); } return ( - {'You have no variable groups'} + {'You have no variable sets'} - @@ -35,4 +35,4 @@ const Title = styled.div` margin-bottom: 5px; `; -export default NoVariableGroups; +export default NoVariableSets; diff --git a/packages/ui/src/features/project-pane/components/molecules/VariableGroupName.tsx b/packages/ui/src/features/project-pane/components/molecules/VariableSetName.tsx similarity index 76% rename from packages/ui/src/features/project-pane/components/molecules/VariableGroupName.tsx rename to packages/ui/src/features/project-pane/components/molecules/VariableSetName.tsx index 0af9f63a0..ad11a272f 100644 --- a/packages/ui/src/features/project-pane/components/molecules/VariableGroupName.tsx +++ b/packages/ui/src/features/project-pane/components/molecules/VariableSetName.tsx @@ -4,15 +4,15 @@ import ksuid from '@beak/ksuid'; import ContextMenu from '@beak/ui/components/atoms/ContextMenu'; import tabActions from '@beak/ui/features/tabs/store/actions'; import sidebarActions from '@beak/ui/store/preferences/actions'; -import { actions as vgActions } from '@beak/ui/store/variable-groups'; +import { actions as vgActions } from '@beak/ui/store/variable-sets'; import type { MenuItemConstructorOptions } from 'electron'; import styled from 'styled-components'; -interface VariableGroupNameProps { - variableGroupName: string; +interface VariableSetNameProps { + variableSetName: string; } -export const VariableGroupName: React.FC = ({ variableGroupName }) => { +export const VariableSetName: React.FC = ({ variableSetName }) => { const [menuItems, setMenuItems] = useState([]); const targetRef = useRef(); const dispatch = useDispatch(); @@ -29,8 +29,8 @@ export const VariableGroupName: React.FC = ({ variableGr label: 'Open in editor', click: () => { dispatch(tabActions.changeTab({ - type: 'variable_group_editor', - payload: variableGroupName, + type: 'variable_set_editor', + payload: variableSetName, temporary: false, })); }, @@ -41,23 +41,23 @@ export const VariableGroupName: React.FC = ({ variableGr id: ksuid.generate('ctxmenuitem').toString(), label: 'Delete', click: () => { - dispatch(vgActions.removeVariableGroupFromDisk({ - id: variableGroupName, + dispatch(vgActions.removeVariableSetFromDisk({ + id: variableSetName, withConfirmation: true, })); }, }]); - }, [variableGroupName]); + }, [variableSetName]); return ( targetRef.current = i!} > - {variableGroupName} + {variableSetName} @@ -74,4 +74,4 @@ const Name = styled.abbr` text-decoration: none; `; -export default VariableGroupName; +export default VariableSetName; diff --git a/packages/ui/src/features/project-pane/components/organisms/VariableGroups.tsx b/packages/ui/src/features/project-pane/components/organisms/VariableSets.tsx similarity index 58% rename from packages/ui/src/features/project-pane/components/organisms/VariableGroups.tsx rename to packages/ui/src/features/project-pane/components/organisms/VariableSets.tsx index f28432ee1..4ed9950d9 100644 --- a/packages/ui/src/features/project-pane/components/organisms/VariableGroups.tsx +++ b/packages/ui/src/features/project-pane/components/organisms/VariableSets.tsx @@ -2,18 +2,18 @@ import React from 'react'; import { useDispatch } from 'react-redux'; import { TypedObject } from '@beak/common/helpers/typescript'; import useSectionBody from '@beak/ui/features/sidebar/hooks/use-section-body'; -import { editorPreferencesSetSelectedVariableGroup } from '@beak/ui/store/preferences/actions'; +import { editorPreferencesSetSelectedVariableSet } from '@beak/ui/store/preferences/actions'; import { useAppSelector } from '@beak/ui/store/redux'; import styled from 'styled-components'; -import NoVariableGroups from '../molecules/NoVariableGroups'; -import VariableGroupName from '../molecules/VariableGroupName'; +import NoVariableSets from '../molecules/NoVariableSets'; +import VariableSetName from '../molecules/VariableSetName'; -const VariableGroups: React.FC> = () => { +const VariableSets: React.FC> = () => { const dispatch = useDispatch(); - const { variableGroups } = useAppSelector(s => s.global.variableGroups)!; - const selectedGroups = useAppSelector(s => s.global.preferences.editor.selectedVariableGroups); - const empty = Object.keys(variableGroups).length === 0; + const { variableSets } = useAppSelector(s => s.global.variableSets)!; + const selectedSets = useAppSelector(s => s.global.preferences.editor.selectedVariableSets); + const empty = Object.keys(variableSets).length === 0; useSectionBody({ maxHeight: '120px', @@ -23,33 +23,33 @@ const VariableGroups: React.FC> = () => { if (empty) { return ( - + ); } return ( - {TypedObject.keys(variableGroups!).map(k => { - const groups = variableGroups![k].groups; - const groupKeys = TypedObject.keys(groups); - const value = selectedGroups[k]; + {TypedObject.keys(variableSets!).map(k => { + const sets = variableSets![k].sets; + const setKeys = TypedObject.keys(sets); + const value = selectedSets[k]; return ( - + { - dispatch(editorPreferencesSetSelectedVariableGroup({ - variableGroup: k, - groupId: e.target.value, + dispatch(editorPreferencesSetSelectedVariableSet({ + variableSet: k, + setId: e.target.value, })); }} > - {groupKeys.map(gk => ( - + {setKeys.map(gk => ( + ))} @@ -99,4 +99,4 @@ const Selector = styled.select` } `; -export default VariableGroups; +export default VariableSets; diff --git a/packages/ui/src/features/realtime-values/hooks/use-realtime-value-context.ts b/packages/ui/src/features/realtime-values/hooks/use-realtime-value-context.ts deleted file mode 100644 index f5c79138f..000000000 --- a/packages/ui/src/features/realtime-values/hooks/use-realtime-value-context.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { useAppSelector } from '@beak/ui/store/redux'; -import type { Context } from '@getbeak/types/values'; - -export default function useRealtimeValueContext(requestId?: string): Context { - const variableGroups = useAppSelector(s => s.global.variableGroups.variableGroups); - const projectTree = useAppSelector(s => s.global.project.tree); - const flightHistory = useAppSelector(s => s.global.flight.flightHistory); - const selectedGroups = useAppSelector(s => s.global.preferences.editor.selectedVariableGroups); - - return { variableGroups, selectedGroups, flightHistory, projectTree, currentRequestId: requestId }; -} diff --git a/packages/ui/src/features/realtime-values/ipc.ts b/packages/ui/src/features/realtime-values/ipc.ts deleted file mode 100644 index 8f08d80f8..000000000 --- a/packages/ui/src/features/realtime-values/ipc.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { ExtensionsMessages, RtvParseValuePartsResponse } from '@beak/common/ipc/extensions'; -import { RequestPayload } from '@beak/common/ipc/ipc'; -import { ipcExtensionsService } from '@beak/ui/lib/ipc'; - -import { parseValueParts } from './parser'; - -ipcExtensionsService.registerRtvParseValueParts(async (event, payload) => { - const parsed = await parseValueParts(payload.context, payload.parts, payload.recursiveDepth); - const message: RequestPayload = { - code: ExtensionsMessages.RtvParseValuePartsResponse, - payload: { - parsed, - uniqueSessionId: payload.uniqueSessionId, - }, - }; - - event.sender.send(ipcExtensionsService.getChannel(), message); -}); diff --git a/packages/ui/src/features/realtime-values/values/variable-group-item.ts b/packages/ui/src/features/realtime-values/values/variable-group-item.ts deleted file mode 100644 index 111d578bb..000000000 --- a/packages/ui/src/features/realtime-values/values/variable-group-item.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { TypedObject } from '@beak/common/helpers/typescript'; -import { VariableGroupItemRtv } from '@beak/ui/features/realtime-values/values'; -import type { VariableGroups } from '@getbeak/types/variable-groups'; -import { RealtimeValue } from '@getbeak/types-realtime-value'; - -import { getValueParts, parseValueParts } from '../parser'; - -const type = 'variable_group_item'; - -const definition: RealtimeValue = { - type, - name: 'Variable group item', - description: 'A realtime value, you can edit it\'s value from the Variable Group editor', - sensitive: false, - external: false, - - createDefaultPayload: () => { - throw new Error('Not supported, this should not happen.'); - }, - - getValue: async (ctx, item, recursiveDepth) => { - const parts = getValueParts(ctx, item.itemId) || []; - - return await parseValueParts(ctx, parts, recursiveDepth); - }, - - attributes: {}, -}; - -export function createFauxValue( - item: VariableGroupItemRtv, - variableGroups: VariableGroups, -): RealtimeValue { - return { - type, - name: getVariableGroupItemName(item, variableGroups), - description: 'A realtime value, you can edit it\'s value from the Variable Group editor', - sensitive: false, - external: false, - - createDefaultPayload: async () => item, - - getValue: () => { - throw new Error('Not supported, this should not happen.'); - }, - - attributes: {}, - }; -} - -export function getVariableGroupItemName(item: VariableGroupItemRtv, variableGroups: VariableGroups) { - if (!variableGroups) - return 'Unknown'; - - const keys = TypedObject.keys(variableGroups); - - for (const key of keys) { - const vg = variableGroups[key]; - const itemValue = vg.items[item.itemId]; - - if (itemValue) - return `${key} (${itemValue})`; - } - - return 'Unknown'; -} - -export default definition; diff --git a/packages/ui/src/features/request-pane/components/molecules/RequestOutput.tsx b/packages/ui/src/features/request-pane/components/molecules/RequestOutput.tsx index c24832756..cb8d28e60 100644 --- a/packages/ui/src/features/request-pane/components/molecules/RequestOutput.tsx +++ b/packages/ui/src/features/request-pane/components/molecules/RequestOutput.tsx @@ -5,8 +5,8 @@ import EditorView from '@beak/ui/components/atoms/EditorView'; import WindowSessionContext, { WindowSession } from '@beak/ui/contexts/window-session-context'; import { convertKeyValueToString } from '@beak/ui/features/basic-table-editor/parsers'; import { convertToRealJson } from '@beak/ui/features/json-editor/parsers'; -import useRealtimeValueContext from '@beak/ui/features/realtime-values/hooks/use-realtime-value-context'; -import { parseValueParts } from '@beak/ui/features/realtime-values/parser'; +import useVariableContext from '@beak/ui/features/variables/hooks/use-variable-context'; +import { parseValueSections } from '@beak/ui/features/variables/parser'; import useComponentMounted from '@beak/ui/hooks/use-component-mounted'; import { ipcFsService } from '@beak/ui/lib/ipc'; import { useAppSelector } from '@beak/ui/store/redux'; @@ -22,12 +22,12 @@ export interface RequestOutputProps { const RequestOutput: React.FC> = props => { const node = props.selectedNode; - const variableGroups = useAppSelector(s => s.global.variableGroups.variableGroups); - const selectedGroups = useAppSelector(s => s.global.preferences.editor.selectedVariableGroups); + const variableSets = useAppSelector(s => s.global.variableSets.variableSets); + const selectedGroups = useAppSelector(s => s.global.preferences.editor.selectedVariableSets); const windowSession = useContext(WindowSessionContext); const [output, setOutput] = useState(''); const mounted = useComponentMounted(); - const context = useRealtimeValueContext(node.id); + const context = useVariableContext(node.id); useEffect(() => { createBasicHttpOutput(node.info, context, windowSession) @@ -37,7 +37,7 @@ const RequestOutput: React.FC> = pro setOutput(response); }); - }, [node, selectedGroups, variableGroups]); + }, [node, selectedGroups, variableSets]); return ( q.enabled) - .map(async value => queryBuilder.append(value.name, await parseValueParts(context, value.value))), + .map(async value => queryBuilder.append(value.name, await parseValueSections(context, value.value))), ); if (!requestAllowsBody(verb) && body.type === 'graphql') @@ -107,7 +107,7 @@ export async function createBasicHttpOutput(overview: RequestOverview, context: out.push(...(await Promise.all( TypedObject.values(headers) .filter(h => h.enabled) - .map(async ({ name, value }) => `${name}: ${await parseValueParts(context, value)}`))), + .map(async ({ name, value }) => `${name}: ${await parseValueSections(context, value)}`))), ); } diff --git a/packages/ui/src/features/request-pane/components/organisms/BodyTab.tsx b/packages/ui/src/features/request-pane/components/organisms/BodyTab.tsx index bd4980af9..3b90e6cd9 100644 --- a/packages/ui/src/features/request-pane/components/organisms/BodyTab.tsx +++ b/packages/ui/src/features/request-pane/components/organisms/BodyTab.tsx @@ -10,8 +10,8 @@ import { EditorMode } from '@beak/ui/features/graphql-editor/types'; import { editorTabSubItems } from '@beak/ui/features/graphql-editor/utils'; import JsonEditor from '@beak/ui/features/json-editor/components/JsonEditor'; import { convertToEntryJson, convertToRealJson } from '@beak/ui/features/json-editor/parsers'; -import useRealtimeValueContext from '@beak/ui/features/realtime-values/hooks/use-realtime-value-context'; -import { ValueParts } from '@beak/ui/features/realtime-values/values'; +import useVariableContext from '@beak/ui/features/variables/hooks/use-variable-context'; +import { ValueSections } from '@beak/ui/features/variables/values'; import { ipcDialogService } from '@beak/ui/lib/ipc'; import actions, { requestBodyTextChanged } from '@beak/ui/store/project/actions'; import { RequestBodyTypeChangedPayload } from '@beak/ui/store/project/types'; @@ -31,7 +31,7 @@ export interface BodyTabProps { const BodyTab: React.FC> = props => { const dispatch = useDispatch(); - const context = useRealtimeValueContext(); + const context = useVariableContext(); const { node } = props; const { body } = node.info; const [graphQlMode, setGraphQlMode] = useState('query'); @@ -237,7 +237,7 @@ const BodyTab: React.FC> = props => { dispatch(actions.requestBodyUrlEncodedEditorValueChange({ requestId: node.id, id, - value: value as ValueParts, + value: value as ValueSections, })); } }} diff --git a/packages/ui/src/features/request-pane/components/organisms/Header.tsx b/packages/ui/src/features/request-pane/components/organisms/Header.tsx index 6f571d6a0..3f9c943a1 100644 --- a/packages/ui/src/features/request-pane/components/organisms/Header.tsx +++ b/packages/ui/src/features/request-pane/components/organisms/Header.tsx @@ -1,9 +1,9 @@ import React from 'react'; import { useDispatch } from 'react-redux'; -import useRealtimeValueContext from '@beak/ui/features/realtime-values/hooks/use-realtime-value-context'; -import { parseValueParts } from '@beak/ui/features/realtime-values/parser'; -import { ValueParts } from '@beak/ui/features/realtime-values/values'; import VariableInput from '@beak/ui/features/variable-input/components/VariableInput'; +import useVariableContext from '@beak/ui/features/variables/hooks/use-variable-context'; +import { parseValueSections } from '@beak/ui/features/variables/parser'; +import { ValueSections } from '@beak/ui/features/variables/values'; import { requestPreferenceSetReqMainTab } from '@beak/ui/store/preferences/actions'; import { useAppSelector } from '@beak/ui/store/redux'; import { faSpinner } from '@fortawesome/free-solid-svg-icons'; @@ -25,7 +25,7 @@ const Header: React.FC> = props => { const currentFlight = useAppSelector(s => s.global.flight.currentFlight); const flighting = currentFlight && currentFlight.flighting && currentFlight.requestId === props.node.id; const { node } = props; - const context = useRealtimeValueContext(node.id); + const context = useVariableContext(node.id); const verb = node.info.verb; function dispatchFlightRequest() { @@ -36,8 +36,8 @@ const Header: React.FC> = props => { dispatch(requestPreferenceSetReqMainTab({ id: node.id, tab: 'url_query' })); } - async function handleUrlChange(parts: ValueParts) { - const value = await parseValueParts(context, parts); + async function handleUrlChange(parts: ValueSections) { + const value = await parseValueSections(context, parts); let sanitizedParts = [...parts]; const parsed = new URL(value, true); diff --git a/packages/ui/src/features/request-pane/components/organisms/RequestPaneSplitter.tsx b/packages/ui/src/features/request-pane/components/organisms/RequestPaneSplitter.tsx index 3c4c12b6a..279f6f4d6 100644 --- a/packages/ui/src/features/request-pane/components/organisms/RequestPaneSplitter.tsx +++ b/packages/ui/src/features/request-pane/components/organisms/RequestPaneSplitter.tsx @@ -1,6 +1,6 @@ import React, { useContext } from 'react'; import WindowSessionContext from '@beak/ui/contexts/window-session-context'; -import useRealtimeValueContext from '@beak/ui/features/realtime-values/hooks/use-realtime-value-context'; +import useVariableContext from '@beak/ui/features/variables/hooks/use-variable-context'; import useShareLink from '@beak/ui/hooks/use-share-link'; import { faCopy, faShareFromSquare } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; @@ -15,7 +15,7 @@ interface RequestPaneSplitterProps { const RequestPaneSplitter: React.FC = props => { const { selectedNode } = props; - const context = useRealtimeValueContext(selectedNode.id); + const context = useVariableContext(selectedNode.id); const windowSession = useContext(WindowSessionContext); const shareUrl = useShareLink(selectedNode.id); diff --git a/packages/ui/src/features/response-pane/components/molecules/Header.tsx b/packages/ui/src/features/response-pane/components/molecules/Header.tsx index c95bbeaad..b5ee0bbb0 100644 --- a/packages/ui/src/features/response-pane/components/molecules/Header.tsx +++ b/packages/ui/src/features/response-pane/components/molecules/Header.tsx @@ -1,6 +1,6 @@ import React, { useEffect, useState } from 'react'; import { statusToColor } from '@beak/design-system/helpers'; -import useRealtimeValueContext from '@beak/ui/features/realtime-values/hooks/use-realtime-value-context'; +import useVariableContext from '@beak/ui/features/variables/hooks/use-variable-context'; import { getStatusReasonPhrase } from '@beak/ui/utils/http'; import { convertRequestToUrl } from '@beak/ui/utils/uri'; import type { Flight } from '@getbeak/types/flight'; @@ -12,7 +12,7 @@ export interface HeaderProps { const Header: React.FC> = props => { const { error, request, response } = props.selectedFlight; - const context = useRealtimeValueContext(props.selectedFlight.requestId); + const context = useVariableContext(props.selectedFlight.requestId); const [url, setUrl] = useState(''); useEffect(() => { diff --git a/packages/ui/src/features/response-pane/components/organisms/RequestTab.tsx b/packages/ui/src/features/response-pane/components/organisms/RequestTab.tsx index 53377ef2d..7b9c0ecd0 100644 --- a/packages/ui/src/features/response-pane/components/organisms/RequestTab.tsx +++ b/packages/ui/src/features/response-pane/components/organisms/RequestTab.tsx @@ -3,7 +3,7 @@ import { useDispatch } from 'react-redux'; import EditorView from '@beak/ui/components/atoms/EditorView'; import WindowSessionContext from '@beak/ui/contexts/window-session-context'; import BasicTableEditor from '@beak/ui/features/basic-table-editor/components/BasicTableEditor'; -import useRealtimeValueContext from '@beak/ui/features/realtime-values/hooks/use-realtime-value-context'; +import useVariableContext from '@beak/ui/features/variables/hooks/use-variable-context'; import { requestPreferenceSetResSubTab } from '@beak/ui/store/preferences/actions'; import { useAppSelector } from '@beak/ui/store/redux'; import type { Flight } from '@getbeak/types/flight'; @@ -27,14 +27,14 @@ const RequestTab: React.FC> = props => const requestId = flight.requestId; const dispatch = useDispatch(); const [output, setOutput] = useState(''); - const { variableGroups } = useAppSelector(s => s.global.variableGroups); - const selectedGroups = useAppSelector(s => s.global.preferences.editor.selectedVariableGroups); + const { variableSets } = useAppSelector(s => s.global.variableSets); + const selectedGroups = useAppSelector(s => s.global.preferences.editor.selectedVariableSets); const tab = useAppSelector( s => s.global.preferences.requests[requestId].response.subTab.request, ) as Tab | undefined; const windowSession = useContext(WindowSessionContext); - const context = useRealtimeValueContext(requestId); + const context = useVariableContext(requestId); // Ensure we have a valid tab useEffect(() => { @@ -48,7 +48,7 @@ const RequestTab: React.FC> = props => useEffect(() => { createBasicHttpOutput(flight.request, context, windowSession).then(setOutput); - }, [flight.request, selectedGroups, variableGroups]); + }, [flight.request, selectedGroups, variableSets]); return ( diff --git a/packages/ui/src/features/sidebar/components/Sidebar.tsx b/packages/ui/src/features/sidebar/components/Sidebar.tsx index 4722995c7..0f16864bc 100644 --- a/packages/ui/src/features/sidebar/components/Sidebar.tsx +++ b/packages/ui/src/features/sidebar/components/Sidebar.tsx @@ -10,7 +10,7 @@ import { useAppSelector } from '@beak/ui/store/redux'; import styled, { css } from 'styled-components'; import ProjectPane from '../../project-pane/components/ProjectPane'; -import VariablesPane from '../../variables/components/VariablesPane'; +import VariablesPane from '../../variables-sets/components/VariablesPane'; import SidebarMenuHighlighter from './molecules/SidebarMenuHighlighter'; import SidebarMenuItem from './molecules/SidebarMenuItem'; diff --git a/packages/ui/src/features/tabs/components/Router.tsx b/packages/ui/src/features/tabs/components/Router.tsx index 8163c31fd..7849948da 100644 --- a/packages/ui/src/features/tabs/components/Router.tsx +++ b/packages/ui/src/features/tabs/components/Router.tsx @@ -11,7 +11,7 @@ import type { RequestNode } from '@getbeak/types/nodes'; import BrokenRequest from '../../broken-request/components/BrokenRequest'; import RequestPane from '../../request-pane/components/RequestPane'; import ResponsePane from '../../response-pane/components/ResponsePane'; -import VariableGroupEditor from '../../variable-groups/components/VariableGroupEditor'; +import VariableSetEditor from '../../variable-sets/components/VariableSetEditor'; interface RouterProps { selectedTab: TabItem | undefined; @@ -62,13 +62,13 @@ const Router: React.FC> = ({ selectedTab }) } switch (selectedTab.type) { - case 'variable_group_editor': { - const variableGroupName = selectedTab.payload; + case 'variable_set_editor': { + const variableSetName = selectedTab.payload; return ( - ); } diff --git a/packages/ui/src/features/tabs/components/TabView.tsx b/packages/ui/src/features/tabs/components/TabView.tsx index d19042355..ec36a59f1 100644 --- a/packages/ui/src/features/tabs/components/TabView.tsx +++ b/packages/ui/src/features/tabs/components/TabView.tsx @@ -8,7 +8,7 @@ import TB from '../../../components/atoms/TabBar'; import { changeTabNext, changeTabPrevious, closeTab, closeTabsAll, closeTabsOther } from '../store/actions'; import NewProjectIntroTab from './molecules/NewProjectIntroTab'; import RequestTab from './molecules/RequestTab'; -import VariableGroupEditorTab from './molecules/VariableGroupEditorTab'; +import VariableSetEditorTab from './molecules/VariableSetEditorTab'; import Router from './Router'; interface TabViewProps { @@ -62,8 +62,8 @@ const TabView: React.FC> = ({ selectedTab, if (t.type === 'request') return ; - if (t.type === 'variable_group_editor') - return ; + if (t.type === 'variable_set_editor') + return ; if (t.type === 'new_project_intro') return ; diff --git a/packages/ui/src/features/tabs/components/molecules/VariableGroupEditorTab.tsx b/packages/ui/src/features/tabs/components/molecules/VariableSetEditorTab.tsx similarity index 71% rename from packages/ui/src/features/tabs/components/molecules/VariableGroupEditorTab.tsx rename to packages/ui/src/features/tabs/components/molecules/VariableSetEditorTab.tsx index 2f00489bc..973be442b 100644 --- a/packages/ui/src/features/tabs/components/molecules/VariableGroupEditorTab.tsx +++ b/packages/ui/src/features/tabs/components/molecules/VariableSetEditorTab.tsx @@ -1,17 +1,17 @@ import React, { useState } from 'react'; import { useDispatch } from 'react-redux'; -import { VariableGroupEditorTabItem } from '@beak/common/types/beak-project'; +import { VariableSetEditorTabItem } from '@beak/common/types/beak-project'; import { useAppSelector } from '@beak/ui/store/redux'; import TabItem from '../../../../components/atoms/TabItem'; import { changeTab, makeTabPermanent } from '../../store/actions'; import TabContextMenuWrapper from '../atoms/GenericTabContextMenuWrapper'; -interface VariableGroupEditorTabProps { - tab: VariableGroupEditorTabItem; +interface VariableSetEditorTabProps { + tab: VariableSetEditorTabItem; } -const VariableGroupEditorTab: React.FC> = ({ tab }) => { +const VariableSetEditorTab: React.FC> = ({ tab }) => { const dispatch = useDispatch(); const selectedTabPayload = useAppSelector(s => s.features.tabs.selectedTab); const [target, setTarget] = useState(); @@ -37,8 +37,8 @@ const VariableGroupEditorTab: React.FC s.features.tabs.activeTabs); const tree: Tree = yield select((s: ApplicationState) => s.global.project.tree); - const variableGroups: VariableGroups = yield select( - (s: ApplicationState) => s.global.variableGroups.variableGroups, + const variableSets: VariableSets = yield select( + (s: ApplicationState) => s.global.variableSets.variableSets, ); const nodes = TypedObject.values(tree); - const variableGroupNames = TypedObject.keys(variableGroups); + const variableSetNames = TypedObject.keys(variableSets); for (const tab of tabs) { switch (tab.type) { @@ -33,10 +33,10 @@ export default createTakeLatestSagaSet(actions.attemptReconciliation, function* break; } - case 'variable_group_editor': { - const variableGroup = variableGroupNames.find(n => n === tab.payload); + case 'variable_set_editor': { + const variableSet = variableSetNames.find(n => n === tab.payload); - if (!variableGroup) + if (!variableSet) yield put(closeTab(tab.payload)); break; } diff --git a/packages/ui/src/features/tree-view/components/molecules/NodeRenamer.tsx b/packages/ui/src/features/tree-view/components/molecules/NodeRenamer.tsx index bee40b1ab..6c6b92c25 100644 --- a/packages/ui/src/features/tree-view/components/molecules/NodeRenamer.tsx +++ b/packages/ui/src/features/tree-view/components/molecules/NodeRenamer.tsx @@ -58,7 +58,7 @@ const NodeRenamer: React.FC> = props = if (!renaming) { return ( void; + onChange: (parts: ValueSections) => void; onUrlQueryStringDetection?: () => void; } @@ -46,15 +46,15 @@ const VariableInput = React.forwardRef((props, const [showSelector, setShowSelector] = useState(() => false); const [query, setQuery] = useState(''); - const { variableGroups } = useAppSelector(s => s.global.variableGroups); - const selectedGroups = useAppSelector(s => s.global.preferences.editor.selectedVariableGroups); + const { variableSets } = useAppSelector(s => s.global.variableSets); + const selectedGroups = useAppSelector(s => s.global.preferences.editor.selectedVariableSets); - const context = useRealtimeValueContext(props.requestId); + const context = useVariableContext(props.requestId); const editableRef = useRef(null); const placeholderRef = useRef(null); const unmanagedStateRef = useRef({ lastUpstreamReport: 0, - valueParts: incomingParts, + ValueSections: incomingParts, }); // Setup ref @@ -69,15 +69,15 @@ const VariableInput = React.forwardRef((props, unmanagedStateRef.current = { lastUpstreamReport: 0, - valueParts: incomingParts, + ValueSections: incomingParts, }; if (readOnly) elem.contentEditable = 'false'; - elem.innerHTML = renderValueParts( - unmanagedStateRef.current.valueParts, - variableGroups, + elem.innerHTML = renderValueSections( + unmanagedStateRef.current.ValueSections, + variableSets, ); }, [requestId, readOnly, latestForceRerender]); @@ -99,7 +99,7 @@ const VariableInput = React.forwardRef((props, elem.removeEventListener('blur', handleBlur); elem.removeEventListener('paste', handlePaste); }; - }, [requestId, showSelector, query, variableGroups, selectedGroups]); + }, [requestId, showSelector, query, variableSets, selectedGroups]); useEffect(() => { if (!editableRef.current) @@ -113,7 +113,7 @@ const VariableInput = React.forwardRef((props, useEffect(() => { // Update unmanaged state if the change comes in more than 100ms after our last known write if (unmanagedStateRef.current.lastUpstreamReport + 100 < Date.now()) { - unmanagedStateRef.current.valueParts = incomingParts; + unmanagedStateRef.current.ValueSections = incomingParts; forceRerender(); } @@ -137,7 +137,7 @@ const VariableInput = React.forwardRef((props, return; } - const { variableSelectionState, valueParts } = unmanagedStateRef.current; + const { variableSelectionState, ValueSections } = unmanagedStateRef.current; // Sanity check, but by now the selector will be open if (!variableSelectionState) { @@ -149,7 +149,7 @@ const VariableInput = React.forwardRef((props, } // Selector is open, so update query - const part = valueParts[variableSelectionState.queryStartSelection.partIndex]; + const part = ValueSections[variableSelectionState.queryStartSelection.partIndex]; if (typeof part !== 'string') { if (showSelector) @@ -168,17 +168,17 @@ const VariableInput = React.forwardRef((props, } async function handleCopy(event: ClipboardEvent) { - const { anomalyDetected, valueParts } = parseDomState(); + const { anomalyDetected, ValueSections } = parseDomState(); - if (anomalyDetected || valueParts.length === 0) + if (anomalyDetected || ValueSections.length === 0) return; - const relevantParts = detectRelevantCopiedValueParts(valueParts); + const relevantParts = detectRelevantCopiedValueSections(ValueSections); if (relevantParts === null) return; - const parsed = await parseValueParts(context, relevantParts); + const parsed = await parseValueSections(context, relevantParts); const clipboard = await navigator.clipboard.read(); const html = await clipboard[0].getType('text/html'); @@ -216,9 +216,9 @@ const VariableInput = React.forwardRef((props, function parseDomState() { if (!editableRef.current) - return { anomalyDetected: false, valueParts: [] }; + return { anomalyDetected: false, ValueSections: [] }; - const reconciledParts: ValueParts = []; + const reconciledParts: ValueSections = []; const children = editableRef.current.childNodes; // If we detect some invalid state, we just ask React to re-render to clear out any @@ -268,7 +268,7 @@ const VariableInput = React.forwardRef((props, const type = elem.dataset.type!; // TODO(afr): Detect if payload is corrected, if it is ignore and mark the - // entire realtime value as an anomaly + // entire variable as an anomaly const purePayload = elem.dataset.payload; reconciledParts.push({ @@ -279,21 +279,21 @@ const VariableInput = React.forwardRef((props, return; }); - return { anomalyDetected, valueParts: reconciledParts }; + return { anomalyDetected, ValueSections: reconciledParts }; } function reconcile() { if (!editableRef.current) return; - const { anomalyDetected, valueParts } = parseDomState(); + const { anomalyDetected, ValueSections } = parseDomState(); const { lastSelectionPosition } = unmanagedStateRef.current; - unmanagedStateRef.current.valueParts = valueParts; + unmanagedStateRef.current.ValueSections = ValueSections; unmanagedStateRef.current.lastSelectionPosition = normalizeSelection(lastSelectionPosition); if (placeholderRef.current) - placeholderRef.current.style.display = valueParts.length === 0 ? 'block' : 'none'; + placeholderRef.current.style.display = ValueSections.length === 0 ? 'block' : 'none'; // This means something really weird has happened, such as an unknown element getting into our DOM state. If // that happens we just tell React to re-render and override with the state that we know about @@ -324,7 +324,7 @@ const VariableInput = React.forwardRef((props, return; } - const { debounceHandler, lastSelectionPosition, valueParts } = unmanagedStateRef.current; + const { debounceHandler, lastSelectionPosition, ValueSections } = unmanagedStateRef.current; // Make sure we aren't double reporting! if (debounceHandler) @@ -335,14 +335,14 @@ const VariableInput = React.forwardRef((props, // Cleanup the format before we pass it back to the store. If we do this internally it'll mess up some of the // DOM <-> State management. Very bad design from me. - onChange(sanitiseValueParts(valueParts)); + onChange(sanitiseValueSections(ValueSections)); } function openSelector() { setShowSelector(true); const selection = normalizeSelection(unmanagedStateRef.current.lastSelectionPosition); - const part = unmanagedStateRef.current.valueParts[selection.partIndex]; + const part = unmanagedStateRef.current.ValueSections[selection.partIndex]; if (typeof part !== 'string') return; @@ -354,7 +354,7 @@ const VariableInput = React.forwardRef((props, } function insertVariable(variable: ValuePart) { - const { valueParts, variableSelectionState } = unmanagedStateRef.current; + const { ValueSections, variableSelectionState } = unmanagedStateRef.current; if (!variableSelectionState) return; @@ -362,35 +362,35 @@ const VariableInput = React.forwardRef((props, const { queryStartSelection, queryTrailingLength } = variableSelectionState; const { offset, partIndex } = queryStartSelection; const queryLength = query.length; - const mode = determineInsertionMode(valueParts, variableSelectionState, queryLength); + const mode = determineInsertionMode(ValueSections, variableSelectionState, queryLength); const newPartSelectionIndex = mode === 'append' ? partIndex + 2 : partIndex + 1; - const mutatedValueParts = [...valueParts]; + const mutatedValueSections = [...ValueSections]; if (['prepend', 'append'].includes(mode)) { let finalPartIndex = partIndex; if (mode === 'prepend') { finalPartIndex += 1; - mutatedValueParts.splice(partIndex, 0, variable); + mutatedValueSections.splice(partIndex, 0, variable); } else { // append - mutatedValueParts.splice(partIndex + 1, 0, variable); + mutatedValueSections.splice(partIndex + 1, 0, variable); } - const part = (mutatedValueParts[finalPartIndex] as string); + const part = (mutatedValueSections[finalPartIndex] as string); const partWithoutQuery = [ part.substring(0, offset - 1), part.substr(part.length - queryTrailingLength), ].join(''); - mutatedValueParts[finalPartIndex] = partWithoutQuery; + mutatedValueSections[finalPartIndex] = partWithoutQuery; } else if (mode === 'inject') { - const part = (mutatedValueParts[partIndex] as string); + const part = (mutatedValueSections[partIndex] as string); const pre = part.substring(0, offset - 1); const post = part.substr(part.length - queryTrailingLength); - mutatedValueParts[partIndex] = pre; - mutatedValueParts.splice(partIndex + 1, 0, variable); - mutatedValueParts.splice(partIndex + 2, 0, post); + mutatedValueSections[partIndex] = pre; + mutatedValueSections.splice(partIndex + 1, 0, variable); + mutatedValueSections.splice(partIndex + 2, 0, post); } else { closeSelector(); @@ -404,7 +404,7 @@ const VariableInput = React.forwardRef((props, }; unmanagedStateRef.current.lastSelectionPosition = newSelectionPosition; - unmanagedStateRef.current.valueParts = mutatedValueParts; + unmanagedStateRef.current.ValueSections = mutatedValueSections; closeSelector(); @@ -415,8 +415,8 @@ const VariableInput = React.forwardRef((props, } function variableEditSaved(partIndex: number, type: string, item: any) { - const valueParts = unmanagedStateRef.current.valueParts; - const part = unmanagedStateRef.current.valueParts[partIndex]; + const ValueSections = unmanagedStateRef.current.ValueSections; + const part = unmanagedStateRef.current.ValueSections[partIndex]; if (typeof part !== 'object' || part.type !== type) { console.error(`Part ordering change mid edit, cannot continue. expected ${type}`); @@ -424,7 +424,7 @@ const VariableInput = React.forwardRef((props, return; } - const newParts = [...valueParts]; + const newParts = [...ValueSections]; const existingPart = newParts[partIndex] as ValuePart; if (typeof existingPart !== 'string') { @@ -434,7 +434,7 @@ const VariableInput = React.forwardRef((props, }; } - unmanagedStateRef.current.valueParts = newParts; + unmanagedStateRef.current.ValueSections = newParts; window.setTimeout(() => { reportChange(); @@ -443,9 +443,9 @@ const VariableInput = React.forwardRef((props, } function internalPartUpdate() { - editableRef.current!.innerHTML = renderValueParts( - unmanagedStateRef.current.valueParts, - variableGroups, + editableRef.current!.innerHTML = renderValueSections( + unmanagedStateRef.current.ValueSections, + variableSets, ); // eslint-disable-next-line no-new @@ -458,6 +458,25 @@ const VariableInput = React.forwardRef((props, setShowSelector(false); setQuery(''); + if (!unmanagedStateRef.current.variableSelectionState) + return; + + // const { queryStartSelection } = unmanagedStateRef.current.variableSelectionState; + + // if (editableRef.current) { + // const node = editableRef.current.childNodes[queryStartSelection.partIndex]; + + // if (node && node.nodeName === 'SPAN') { + // const span = node as HTMLSpanElement; + + // console.log('span', span.innerText); + // console.log('queryStartSelection.offset', queryStartSelection.offset); + // console.log('queryStartSelection.partIndex', queryStartSelection.partIndex); + + // span.innerText = span.innerText.substring(0, queryStartSelection.offset); + // } + // } + unmanagedStateRef.current.variableSelectionState = void 0; } @@ -467,7 +486,7 @@ const VariableInput = React.forwardRef((props, {placeholder && ( {placeholder} @@ -483,7 +502,7 @@ const VariableInput = React.forwardRef((props, /> )} {editableRef.current && ( - > = props => { const { editableElement, sel, query, requestId, onClose, onDone } = props; - const { variableGroups } = useAppSelector(s => s.global.variableGroups); + const { variableSets } = useAppSelector(s => s.global.variableSets); const activeRef = useRef(null); const [position, setPosition] = useState(null); const [active, setActive] = useState(0); - const context = useRealtimeValueContext(requestId); + const context = useVariableContext(requestId); - const items: RealtimeValueInformation[] = useMemo(() => { - const all: RealtimeValueInformation[] = [ - ...RealtimeValueManager.getRealtimeValues(requestId), + const items: VariableStaticInformation[] = useMemo(() => { + const all: VariableStaticInformation[] = [ + ...VariableManager.getVariables(requestId), - // Variable groups act a little differently - ...TypedObject.keys(variableGroups) + // Variable sets act a little differently + ...TypedObject.keys(variableSets) .map(vgKey => { - const vg = variableGroups[vgKey]; + const vg = variableSets[vgKey]; - return TypedObject.keys(vg.items).map(i => createFauxValue({ itemId: i }, variableGroups)); + return TypedObject.keys(vg.items).map(i => createFauxValue({ itemId: i }, variableSets)); }) .flat(), ]; @@ -68,7 +69,7 @@ const VariableSelector: React.FC> .sort() .map(r => r.item) .sort(); - }, [variableGroups, query]); + }, [variableSets, query]); useEffect(() => { if (!sel) @@ -150,13 +151,13 @@ const VariableSelector: React.FC> return () => window.removeEventListener('keydown', onKeyDown); }, [active, items]); - async function createDefaultVariable(item: RealtimeValueInformation) { + async function createDefaultVariable(item: VariableStaticInformation) { let payload: any; if (item.external) payload = await ipcExtensionsService.rtvCreateDefaultPayload({ type: item.type, context }); else - payload = await (item as RealtimeValue).createDefaultPayload(context); + payload = await (item as Variable).createDefaultPayload(context); onDone({ type: item.type, payload }); } @@ -164,6 +165,32 @@ const VariableSelector: React.FC> if (!position) return null; + if (items.length === 0) { + return ( + { + event.stopPropagation(); + onClose(); + }}> + + + + {'There are no variables matching your search. Try widening '} + {'your horizons.'} + + + + {'Missing a variable you would find useful?'}
+ {'You can build your own with an extension, check the '} + void await ipcExplorerService.launchUrl("https://getbeak.notion.site/Extensions-4c16ca640b35460787056f8be815b904") }> + {'docs'} + + {'.'} +
+
+
+ ); + } + return ( { event.stopPropagation(); @@ -218,6 +245,10 @@ const Wrapper = styled.div<{ $top: number; $left: number }>` border: 1px solid ${p => p.theme.ui.backgroundBorderSeparator}; background: ${p => p.theme.ui.surface}; + transform-origin: center; + animation: ${scaleIn} .2s ease; + transition: transform .1s ease; + font-size: 12px; `; @@ -241,6 +272,13 @@ const Item = styled.div<{ $active: boolean }>` ${p => p.$active ? `background-color: ${p.theme.ui.primaryFill};'` : ''} `; +const NoItems = styled.div` + padding: 10px; + cursor: pointer; + color: ${p => p.theme.ui.textOnSurfaceBackground}; + overflow-x: hidden; +`; + const ExtensionContainer = styled.div` display: inline-block; margin-right: 5px; @@ -252,6 +290,10 @@ const Description = styled.div` padding: 5px; min-height: 30px; + + > a { + color: #ffa210; + } `; export default VariableSelector; diff --git a/packages/ui/src/features/variable-input/utils/copying.ts b/packages/ui/src/features/variable-input/utils/copying.ts index 32b42d425..5c4860c3f 100644 --- a/packages/ui/src/features/variable-input/utils/copying.ts +++ b/packages/ui/src/features/variable-input/utils/copying.ts @@ -1,6 +1,6 @@ -import { ValueParts } from '@beak/ui/features/realtime-values/values'; +import { ValueSections } from '@beak/ui/features/variables/values'; -export function detectRelevantCopiedValueParts(valueParts: ValueParts) { +export function detectRelevantCopiedValueSections(ValueSections: ValueSections) { const sel = window.getSelection()!; let startNode = sel.anchorNode!; @@ -62,7 +62,7 @@ export function detectRelevantCopiedValueParts(valueParts: ValueParts) { if (startIndex === -1 || endIndex === -1) return null; - const relevantParts = valueParts.slice(startIndex, endIndex + 1); + const relevantParts = ValueSections.slice(startIndex, endIndex + 1); const samePart = startIndex === endIndex; if (samePart) { diff --git a/packages/ui/src/features/variable-input/utils/sanitation.ts b/packages/ui/src/features/variable-input/utils/sanitation.ts index ca793ed15..43282f4e9 100644 --- a/packages/ui/src/features/variable-input/utils/sanitation.ts +++ b/packages/ui/src/features/variable-input/utils/sanitation.ts @@ -1,11 +1,11 @@ -import { ValueParts } from '@getbeak/types/values'; +import { ValueSections } from '@getbeak/types/values'; -export function sanitiseValueParts(valueParts: ValueParts) { +export function sanitiseValueSections(ValueSections: ValueSections) { // Now we need to slightly sanitise the reconciled state. The outcome of this must: // - Remove leading empty string parts // - Remove trailing empty string parts // - Collapse 2 or more consecutive empty string parts into one - const sanitisedParts: ValueParts = valueParts.reduce((acc, value) => { + const sanitisedParts: ValueSections = ValueSections.reduce((acc, value) => { if (typeof value !== 'string') return [...acc, value]; @@ -17,7 +17,7 @@ export function sanitiseValueParts(valueParts: ValueParts) { acc[acc.length - 1] = `${acc[acc.length - 1]}${value}`; return acc; - }, [] as ValueParts); + }, [] as ValueSections); if (sanitisedParts[0] === '') sanitisedParts.shift(); diff --git a/packages/ui/src/features/variable-input/utils/variables.ts b/packages/ui/src/features/variable-input/utils/variables.ts index cb1ba6693..0c003d0d1 100644 --- a/packages/ui/src/features/variable-input/utils/variables.ts +++ b/packages/ui/src/features/variable-input/utils/variables.ts @@ -1,4 +1,4 @@ -import { ValueParts } from '@beak/ui/features/realtime-values/values'; +import { ValueSections } from '@beak/ui/features/variables/values'; import { NormalizedSelection } from './browser-selection'; @@ -10,7 +10,7 @@ export interface VariableSelectionState { } export function determineInsertionMode( - valueParts: ValueParts, + ValueSections: ValueSections, variableSelectionState: VariableSelectionState, queryLength: number, ): Mode { @@ -21,8 +21,8 @@ export function determineInsertionMode( if (partIndex === 0 && offset === 1) return 'prepend'; - if (partIndex === valueParts.length - 1) { - const part = valueParts[partIndex] as string; + if (partIndex === ValueSections.length - 1) { + const part = ValueSections[partIndex] as string; if (part.length - queryLength === offset + 1) return 'append'; diff --git a/packages/ui/src/features/variable-groups/components/VariableGroupEditor.tsx b/packages/ui/src/features/variable-sets/components/VariableSetEditor.tsx similarity index 67% rename from packages/ui/src/features/variable-groups/components/VariableGroupEditor.tsx rename to packages/ui/src/features/variable-sets/components/VariableSetEditor.tsx index f8dda5064..3da765cf2 100644 --- a/packages/ui/src/features/variable-groups/components/VariableGroupEditor.tsx +++ b/packages/ui/src/features/variable-sets/components/VariableSetEditor.tsx @@ -2,10 +2,10 @@ import React, { useEffect, useRef, useState } from 'react'; import { useDispatch } from 'react-redux'; import { TypedObject } from '@beak/common/helpers/typescript'; import DebouncedInput from '@beak/ui/components/atoms/DebouncedInput'; -import { generateValueIdent } from '@beak/ui/lib/beak-variable-group/utils'; +import { generateValueIdent } from '@beak/ui/lib/beak-variable-set/utils'; import { useAppSelector } from '@beak/ui/store/redux'; -import { actions } from '@beak/ui/store/variable-groups'; -import { insertNewGroup, insertNewItem, removeGroup, removeItem } from '@beak/ui/store/variable-groups/actions'; +import { actions } from '@beak/ui/store/variable-sets'; +import { insertNewGroup, insertNewItem, removeGroup, removeItem } from '@beak/ui/store/variable-sets/actions'; import styled, { css } from 'styled-components'; import VariableInput from '../../variable-input/components/VariableInput'; @@ -14,14 +14,14 @@ import { Body, Header, Row } from './atoms/Structure'; import CellDeletionAction from './molecules/CellDeletionAction'; import CreateNewSplash from './molecules/CreateNewSplash'; -interface VariableGroupEditorProps { - variableGroupName: string; +interface VariableSetEditorProps { + variableSetName: string; } -const VariableGroupEditor: React.FC> = ({ variableGroupName }) => { +const VariableSetEditor: React.FC> = ({ variableSetName }) => { const dispatch = useDispatch(); - const variableGroups = useAppSelector(s => s.global.variableGroups); - const variableGroup = variableGroups.variableGroups[variableGroupName]; + const variableSets = useAppSelector(s => s.global.variableSets); + const variableSet = variableSets.variableSets[variableSetName]; const [newItem, setNewItem] = useState(void 0); const newItemRef = useRef(null); @@ -33,7 +33,7 @@ const VariableGroupEditor: React.FC { if (!newGroup) return; - if (!TypedObject.values(variableGroup.groups).includes(newGroup)) + if (!TypedObject.values(variableSet.sets).includes(newGroup)) return; if (newGroupRef?.current === null) @@ -55,48 +55,48 @@ const VariableGroupEditor: React.FC - {variableGroup && groupKeys.length === 0 && ( - + {variableSet && setKeys.length === 0 && ( + )} - {variableGroup && groupKeys.length > 0 && ( + {variableSet && setKeys.length > 0 && (
- + - {variableGroup && groupKeys.map(k => ( + {variableSet && setKeys.map(k => ( { dispatch(actions.updateGroupName({ - id: variableGroupName, - groupId: k, + id: variableSetName, + setId: k, updatedName: v, })); }} /> dispatch(removeGroup({ - id: variableGroupName, - groupId: k, + id: variableSetName, + setId: k, }))} /> @@ -109,8 +109,8 @@ const VariableGroupEditor: React.FC { setNewGroup(e.target.value); dispatch(insertNewGroup({ - id: variableGroupName, - groupName: e.target.value, + id: variableSetName, + setName: e.target.value, })); }} /> @@ -119,16 +119,16 @@ const VariableGroupEditor: React.FC - {variableGroup && itemKeys.map(ik => ( - + {variableSet && itemKeys.map(ik => ( + { dispatch(actions.updateItemName({ - id: variableGroupName, + id: variableSetName, itemId: ik, updatedName: v, })); @@ -136,17 +136,17 @@ const VariableGroupEditor: React.FC dispatch(removeItem({ - id: variableGroupName, + id: variableSetName, itemId: ik, }))} /> - {groupKeys.map(gk => { + {setKeys.map(gk => { const key = generateValueIdent(gk, ik); - const value = variableGroup.values[key]; + const value = variableSet.values[key]; return ( @@ -154,8 +154,8 @@ const VariableGroupEditor: React.FC { dispatch(actions.updateValue({ - id: variableGroupName, - groupId: gk, + id: variableSetName, + setId: gk, itemId: ik, updated: parts, })); @@ -171,7 +171,7 @@ const VariableGroupEditor: React.FC ))} - + { setNewItem(e.target.value); dispatch(insertNewItem({ - id: variableGroupName, + id: variableSetName, itemName: e.target.value, })); }} /> - {variableGroup && groupKeys.map(k => ( + {variableSet && setKeys.map(k => ( @@ -231,4 +231,4 @@ const inputCss = css<{ $center?: boolean }>` const StyledDebounce = styled(DebouncedInput)<{ $center?: boolean }>`${inputCss}`; const EmptyInput = styled.input<{ $center?: boolean }>`${inputCss}`; -export default VariableGroupEditor; +export default VariableSetEditor; diff --git a/packages/ui/src/features/variable-groups/components/atoms/Cells.ts b/packages/ui/src/features/variable-sets/components/atoms/Cells.ts similarity index 100% rename from packages/ui/src/features/variable-groups/components/atoms/Cells.ts rename to packages/ui/src/features/variable-sets/components/atoms/Cells.ts diff --git a/packages/ui/src/features/variable-groups/components/atoms/Structure.ts b/packages/ui/src/features/variable-sets/components/atoms/Structure.ts similarity index 100% rename from packages/ui/src/features/variable-groups/components/atoms/Structure.ts rename to packages/ui/src/features/variable-sets/components/atoms/Structure.ts diff --git a/packages/ui/src/features/variable-groups/components/molecules/CellDeletionAction.tsx b/packages/ui/src/features/variable-sets/components/molecules/CellDeletionAction.tsx similarity index 100% rename from packages/ui/src/features/variable-groups/components/molecules/CellDeletionAction.tsx rename to packages/ui/src/features/variable-sets/components/molecules/CellDeletionAction.tsx diff --git a/packages/ui/src/features/variable-groups/components/molecules/CreateNewSplash.tsx b/packages/ui/src/features/variable-sets/components/molecules/CreateNewSplash.tsx similarity index 71% rename from packages/ui/src/features/variable-groups/components/molecules/CreateNewSplash.tsx rename to packages/ui/src/features/variable-sets/components/molecules/CreateNewSplash.tsx index 49181187d..7836eda66 100644 --- a/packages/ui/src/features/variable-groups/components/molecules/CreateNewSplash.tsx +++ b/packages/ui/src/features/variable-sets/components/molecules/CreateNewSplash.tsx @@ -1,26 +1,26 @@ import React from 'react'; import { useDispatch } from 'react-redux'; import Button from '@beak/ui/components/atoms/Button'; -import { insertNewGroup } from '@beak/ui/store/variable-groups/actions'; +import { insertNewGroup } from '@beak/ui/store/variable-sets/actions'; import styled from 'styled-components'; interface CreateNewSplashProps { - type: 'group'; - variableGroup: string; + type: 'set'; + variableSet: string; } -const CreateNewSplash: React.FC = ({ type, variableGroup }) => { +const CreateNewSplash: React.FC = ({ type, variableSet }) => { const dispatch = useDispatch(); return (
- {'Looks like you have no groups in here?'} + {'Looks like you have no sets in here?'}
@@ -297,6 +317,10 @@ const Wrapper = styled.div<{ $top: number; $left: number }>` border: 1px solid ${p => p.theme.ui.backgroundBorderSeparator}; background: ${p => p.theme.ui.surface}; z-index: 10000; + + transform-origin: center; + animation: ${scaleIn} .2s ease; + transition: transform .1s ease; `; const ButtonContainer = styled.div` @@ -305,4 +329,4 @@ const ButtonContainer = styled.div` align-items: center; `; -export default RealtimeValueEditor; +export default VariableEditor; diff --git a/packages/ui/src/features/realtime-value-editor/components/atoms/Form.ts b/packages/ui/src/features/variables-editor/components/atoms/Form.ts similarity index 100% rename from packages/ui/src/features/realtime-value-editor/components/atoms/Form.ts rename to packages/ui/src/features/variables-editor/components/atoms/Form.ts diff --git a/packages/ui/src/features/realtime-value-editor/components/molecules/PreviewContainer.tsx b/packages/ui/src/features/variables-editor/components/molecules/PreviewContainer.tsx similarity index 100% rename from packages/ui/src/features/realtime-value-editor/components/molecules/PreviewContainer.tsx rename to packages/ui/src/features/variables-editor/components/molecules/PreviewContainer.tsx diff --git a/packages/ui/src/features/realtime-value-editor/utils/render-request-select-options.tsx b/packages/ui/src/features/variables-editor/utils/render-request-select-options.tsx similarity index 100% rename from packages/ui/src/features/realtime-value-editor/utils/render-request-select-options.tsx rename to packages/ui/src/features/variables-editor/utils/render-request-select-options.tsx diff --git a/packages/ui/src/features/variables/components/VariablesPane.tsx b/packages/ui/src/features/variables-sets/components/VariablesPane.tsx similarity index 65% rename from packages/ui/src/features/variables/components/VariablesPane.tsx rename to packages/ui/src/features/variables-sets/components/VariablesPane.tsx index 3fc08c8ff..2a7336d14 100644 --- a/packages/ui/src/features/variables/components/VariablesPane.tsx +++ b/packages/ui/src/features/variables-sets/components/VariablesPane.tsx @@ -1,12 +1,12 @@ import React from 'react'; import { useDispatch } from 'react-redux'; import ksuid from '@beak/ksuid'; -import { actions } from '@beak/ui/store/variable-groups'; +import { actions } from '@beak/ui/store/variable-sets'; import SidebarPane from '../../sidebar/components/SidebarPane'; import SidebarPaneSection from '../../sidebar/components/SidebarPaneSection'; import { changeTab } from '../../tabs/store/actions'; -import VariableGroups from './organisms/VariableGroups'; +import VariableSets from './organisms/VariableSets'; const VariablesPane: React.FC> = () => { const dispatch = useDispatch(); @@ -14,23 +14,23 @@ const VariablesPane: React.FC> = () => { return ( { - dispatch(actions.createNewVariableGroup({ })); + dispatch(actions.createNewVariableSet({ })); dispatch(changeTab({ - type: 'variable_group_editor', - payload: 'New variable group', + type: 'variable_set_editor', + payload: 'New variable set', temporary: false, })); }, }]} > - + ); diff --git a/packages/ui/src/features/variables/components/organisms/VariableGroups.tsx b/packages/ui/src/features/variables-sets/components/organisms/VariableSets.tsx similarity index 77% rename from packages/ui/src/features/variables/components/organisms/VariableGroups.tsx rename to packages/ui/src/features/variables-sets/components/organisms/VariableSets.tsx index aa4ca9a03..ffe84d6d9 100644 --- a/packages/ui/src/features/variables/components/organisms/VariableGroups.tsx +++ b/packages/ui/src/features/variables-sets/components/organisms/VariableSets.tsx @@ -9,40 +9,40 @@ import { TreeViewItem, TreeViewNodes } from '@beak/ui/features/tree-view/types'; import { ipcExplorerService } from '@beak/ui/lib/ipc'; import { checkShortcut } from '@beak/ui/lib/keyboard-shortcuts'; import { useAppSelector } from '@beak/ui/store/redux'; -import { actions } from '@beak/ui/store/variable-groups'; -import { removeVariableGroupFromDisk } from '@beak/ui/store/variable-groups/actions'; +import { actions } from '@beak/ui/store/variable-sets'; +import { removeVariableSetFromDisk } from '@beak/ui/store/variable-sets/actions'; import { renderAcceleratorDefinition } from '@beak/ui/utils/keyboard-rendering'; import type { MenuItemConstructorOptions } from 'electron'; import styled from 'styled-components'; -const VariableGroups: React.FC> = () => { +const VariableSets: React.FC> = () => { const dispatch = useDispatch(); const selectedTabId = useAppSelector(s => s.features.tabs.selectedTab); - const variableGroups = useAppSelector(s => s.global.variableGroups.variableGroups); - const variableGroupKeys = TypedObject.keys(variableGroups); + const variableSets = useAppSelector(s => s.global.variableSets.variableSets); + const variableSetKeys = TypedObject.keys(variableSets); const windowSession = useContext(WindowSessionContext); const darwin = windowSession.isDarwin(); - const tree = variableGroupKeys.reduce((acc, k) => ({ + const tree = variableSetKeys.reduce((acc, k) => ({ ...acc, [k]: { id: k, - type: 'variable-group', - filePath: `variable-groups/${k}.json`, + type: 'variable-set', + filePath: `variable-sets/${k}.json`, name: k, - parent: 'variable-groups', + parent: 'variable-sets', }, }), {} as TreeViewNodes); - const empty = variableGroupKeys.length === 0; + const empty = variableSetKeys.length === 0; function generateContextMenu(node: TreeViewItem): MenuItemConstructorOptions[] { return [{ id: ksuid.generate('ctxmenuitem').toString(), label: 'New variable group', click: () => { - dispatch(actions.createNewVariableGroup({ })); + dispatch(actions.createNewVariableSet({ })); }, }, { id: ksuid.generate('ctxmenuitem').toString(), @@ -93,7 +93,7 @@ const VariableGroups: React.FC> = () => { accelerator: renderAcceleratorDefinition('tree-view.node.delete'), enabled: node.id !== 'root', click: () => { - dispatch(actions.removeVariableGroupFromDisk({ id: node.id, withConfirmation: true })); + dispatch(actions.removeVariableSetFromDisk({ id: node.id, withConfirmation: true })); }, }]; } @@ -103,7 +103,7 @@ const VariableGroups: React.FC> = () => { return; dispatch(changeTab({ - type: 'variable_group_editor', + type: 'variable_set_editor', payload: node.id, temporary: true, })); @@ -118,12 +118,12 @@ const VariableGroups: React.FC> = () => { function handleNodeKeyDown(event: React.KeyboardEvent, node: TreeViewItem) { switch (true) { - case checkShortcut('variable-groups.variable-group.open', event) && node.type !== 'folder': - dispatch(changeTab({ type: 'variable_group_editor', payload: node.id, temporary: false })); + case checkShortcut('variable-sets.variable-set.open', event) && node.type !== 'folder': + dispatch(changeTab({ type: 'variable_set_editor', payload: node.id, temporary: false })); break; - case checkShortcut('variable-groups.variable-group.delete', event) && node.type !== 'folder': - dispatch(removeVariableGroupFromDisk({ id: node.id, withConfirmation: true })); + case checkShortcut('variable-sets.variable-set.delete', event) && node.type !== 'folder': + dispatch(removeVariableSetFromDisk({ id: node.id, withConfirmation: true })); break; default: return; @@ -141,9 +141,9 @@ const VariableGroups: React.FC> = () => { activeNodeId={selectedTabId} focusedNodeId={selectedTabId} allowRootContextMenu - rootParentName={'variable-groups'} + rootParentName={'variable-sets'} - renameSelector={(_node, state) => state.global.variableGroups.activeRename} + renameSelector={(_node, state) => state.global.variableSets.activeRename} onRenameStarted={node => dispatch(actions.renameStarted({ id: node.id }))} onRenameEnded={node => dispatch(actions.renameCancelled({ id: node.id }))} onRenameUpdated={(node, name) => dispatch(actions.renameUpdated({ id: node.id, name }))} @@ -164,4 +164,4 @@ const EmptyWarning = styled.div` font-size: 13px; `; -export default VariableGroups; +export default VariableSets; diff --git a/packages/ui/src/features/variables/hooks/use-variable-context.ts b/packages/ui/src/features/variables/hooks/use-variable-context.ts new file mode 100644 index 000000000..be618fea0 --- /dev/null +++ b/packages/ui/src/features/variables/hooks/use-variable-context.ts @@ -0,0 +1,11 @@ +import { useAppSelector } from '@beak/ui/store/redux'; +import type { Context } from '@getbeak/types/values'; + +export default function useVariableContext(requestId?: string): Context { + const variableSets = useAppSelector(s => s.global.variableSets.variableSets); + const projectTree = useAppSelector(s => s.global.project.tree); + const flightHistory = useAppSelector(s => s.global.flight.flightHistory); + const selectedSets = useAppSelector(s => s.global.preferences.editor.selectedVariableSets); + + return { variableSets, selectedSets, flightHistory, projectTree, currentRequestId: requestId }; +} diff --git a/packages/ui/src/features/realtime-values/index.ts b/packages/ui/src/features/variables/index.ts similarity index 71% rename from packages/ui/src/features/realtime-values/index.ts rename to packages/ui/src/features/variables/index.ts index 583f093f2..9a7bdf2df 100644 --- a/packages/ui/src/features/realtime-values/index.ts +++ b/packages/ui/src/features/variables/index.ts @@ -1,7 +1,7 @@ import { TypedObject } from '@beak/common/helpers/typescript'; -import { RealtimeValueExtension } from '@beak/common/types/extensions'; +import { VariableExtension } from '@beak/common/types/extensions'; import { ipcExtensionsService } from '@beak/ui/lib/ipc'; -import { EditableRealtimeValue, RealtimeValue } from '@getbeak/types-realtime-value'; +import { EditableVariable, Variable } from '@getbeak/types-variables'; import './ipc'; import base64DecodeRtv from './values/base64-decode'; @@ -23,13 +23,13 @@ import timestampRtv from './values/timestamp'; import urlDecodeRtv from './values/url-decode'; import urlEncodeRtv from './values/url-encode'; import uuidRtv from './values/uuid'; -import variableGroupItemRtv from './values/variable-group-item'; +import variableSetItemRtv from './values/variable-set-item'; -type Rtv = RealtimeValue | EditableRealtimeValue; +type BasicOrEditableVariable = Variable | EditableVariable; -export class RealtimeValueManager { - private static externalRealtimeValues: Record = { }; - private static internalRealtimeValues: Record = { +export class VariableManager { + private static externalVariables: Record = { }; + private static internalVariables: Record = { [base64DecodeRtv.type]: base64DecodeRtv, [base64EncodeRtv.type]: base64EncodeRtv, [characterCarriageReturnRtv.type]: characterCarriageReturnRtv, @@ -53,13 +53,13 @@ export class RealtimeValueManager { [uuidRtv.type]: uuidRtv, // Special case! - [variableGroupItemRtv.type]: variableGroupItemRtv, + [variableSetItemRtv.type]: variableSetItemRtv, }; - static registerExternalRealtimeValue(ext: RealtimeValueExtension) { - const rtv = ext.realtimeValue; + static registerExternalVariable(ext: VariableExtension) { + const rtv = ext.variable; - this.externalRealtimeValues[rtv.type] = { + this.externalVariables[rtv.type] = { type: rtv.type, name: rtv.name, description: rtv.description, @@ -81,7 +81,7 @@ export class RealtimeValueManager { if (!rtv.editable) return; - (this.externalRealtimeValues[rtv.type] as EditableRealtimeValue).editor = { + (this.externalVariables[rtv.type] as EditableVariable).editor = { createUserInterface: ctx => ipcExtensionsService.rtvEditorCreateUserInterface({ type: rtv.type, context: ctx, @@ -100,25 +100,25 @@ export class RealtimeValueManager { }; } - static unregisterExternalRealtimeValues(type: string) { - delete this.externalRealtimeValues[type]; + static unregisterExternalVariable(type: string) { + delete this.externalVariables[type]; } - static getRealtimeValue(type: string) { - return this.internalRealtimeValues[type] ?? this.externalRealtimeValues[type]; + static getVariable(type: string) { + return this.internalVariables[type] ?? this.externalVariables[type]; } - static getRealtimeValues(currentRequestId?: string) { - const allRealtimeValues = { - ...this.externalRealtimeValues, + static getVariables(currentRequestId?: string) { + const allVariables = { + ...this.externalVariables, // Do this second to override any external attempts to override - ...this.internalRealtimeValues, + ...this.internalVariables, }; - return TypedObject.values(allRealtimeValues) - // Remove the variable group item as it's a special case tbh - .filter(v => v.type !== variableGroupItemRtv.type) + return TypedObject.values(allVariables) + // Remove the variable set item as it's a special case tbh + .filter(v => v.type !== variableSetItemRtv.type) .filter(v => { if (!v.attributes.requiresRequestId) return true; diff --git a/packages/ui/src/features/variables/ipc.ts b/packages/ui/src/features/variables/ipc.ts new file mode 100644 index 000000000..cd038aeea --- /dev/null +++ b/packages/ui/src/features/variables/ipc.ts @@ -0,0 +1,18 @@ +import { ExtensionsMessages, RtvParseValueSectionsResponse } from '@beak/common/ipc/extensions'; +import { RequestPayload } from '@beak/common/ipc/ipc'; +import { ipcExtensionsService } from '@beak/ui/lib/ipc'; + +import { parseValueSections } from './parser'; + +ipcExtensionsService.registerRtvParseValueSections(async (event, payload) => { + const parsed = await parseValueSections(payload.context, payload.parts, payload.recursiveDepth); + const message: RequestPayload = { + code: ExtensionsMessages.RtvParseValueSectionsResponse, + payload: { + parsed, + uniqueSessionId: payload.uniqueSessionId, + }, + }; + + event.sender.send(ipcExtensionsService.getChannel(), message); +}); diff --git a/packages/ui/src/features/realtime-values/parser.ts b/packages/ui/src/features/variables/parser.ts similarity index 67% rename from packages/ui/src/features/realtime-values/parser.ts rename to packages/ui/src/features/variables/parser.ts index 0522b146b..5ee030141 100644 --- a/packages/ui/src/features/realtime-values/parser.ts +++ b/packages/ui/src/features/variables/parser.ts @@ -1,12 +1,12 @@ import { TypedObject } from '@beak/common/helpers/typescript'; -import { generateValueIdent } from '@beak/ui/lib/beak-variable-group/utils'; -import type { Context, ValueParts } from '@getbeak/types/values'; +import { generateValueIdent } from '@beak/ui/lib/beak-variable-set/utils'; +import type { Context, ValueSections } from '@getbeak/types/values'; -import { RealtimeValueManager } from '.'; +import { VariableManager } from '.'; -export async function parseValueParts( +export async function parseValueSections( ctx: Context, - parts: ValueParts, + parts: ValueSections, depth = 0, sensitiveMode = false, ): Promise { @@ -17,7 +17,7 @@ export async function parseValueParts( if (typeof p !== 'object') return ''; - const rtv = RealtimeValueManager.getRealtimeValue(p.type); + const rtv = VariableManager.getVariable(p.type); if (!rtv) return ''; @@ -61,15 +61,15 @@ export async function parseValueParts( return out.join(''); } -export function getValueParts(ctx: Context, itemId: string) { +export function getValueSections(ctx: Context, itemId: string) { return getValueObject(ctx, itemId); } export function getValueObject(ctx: Context, itemId: string) { - for (const key of TypedObject.keys(ctx.variableGroups)) { - const variableGroup = ctx.variableGroups[key]; - const selectedGroup = ctx.selectedGroups[key]; - const value = variableGroup.values[generateValueIdent(selectedGroup, itemId)]; + for (const key of TypedObject.keys(ctx.variableSets)) { + const variableSet = ctx.variableSets[key]; + const selectedSet = ctx.selectedSets[key]; + const value = variableSet.values[generateValueIdent(selectedSet, itemId)]; if (value) return value; diff --git a/packages/ui/src/features/realtime-values/preview.ts b/packages/ui/src/features/variables/preview.ts similarity index 56% rename from packages/ui/src/features/realtime-values/preview.ts rename to packages/ui/src/features/variables/preview.ts index d9f50e843..231e4cbb5 100644 --- a/packages/ui/src/features/realtime-values/preview.ts +++ b/packages/ui/src/features/variables/preview.ts @@ -1,12 +1,18 @@ import type { Context } from '@getbeak/types/values'; -import { EditableRealtimeValue } from '@getbeak/types-realtime-value'; +import { EditableVariable } from '@getbeak/types-variables'; export async function previewValue>( ctx: Context, - rtv: EditableRealtimeValue, + rtv: EditableVariable, item: any, state: T, ) { + if (!rtv.editor) + return 'Editor not available'; + + if (!rtv.editor.save) + return await rtv.getValue(ctx, state, 0); + const payload = await rtv.editor.save(ctx, item, state); return await rtv.getValue(ctx, payload, 0); diff --git a/packages/ui/src/features/realtime-values/renderer.tsx b/packages/ui/src/features/variables/renderer.tsx similarity index 69% rename from packages/ui/src/features/realtime-values/renderer.tsx rename to packages/ui/src/features/variables/renderer.tsx index 6b0515871..6284dc556 100644 --- a/packages/ui/src/features/realtime-values/renderer.tsx +++ b/packages/ui/src/features/variables/renderer.tsx @@ -1,13 +1,13 @@ import React from 'react'; import { renderToStaticMarkup } from 'react-dom/server'; -import type { VariableGroups } from '@getbeak/types/variable-groups'; +import type { VariableSets } from '@getbeak/types/variable-sets'; import * as uuid from 'uuid'; -import { RealtimeValueManager } from '.'; -import { ValueParts } from './values'; -import { getVariableGroupItemName } from './values/variable-group-item'; +import { VariableManager } from '.'; +import { ValueSections } from './values'; +import { getVariableSetItemName } from './values/variable-set-item'; -export default function renderValueParts(parts: ValueParts, variableGroups: VariableGroups) { +export default function renderValueSections(parts: ValueSections, variableSets: VariableSets) { let safeParts = parts; if (!Array.isArray(parts)) @@ -25,7 +25,7 @@ export default function renderValueParts(parts: ValueParts, variableGroups: Vari return null; } - const rtv = RealtimeValueManager.getRealtimeValue(p.type); + const rtv = VariableManager.getVariable(p.type); if (!rtv) { return ( @@ -40,7 +40,7 @@ export default function renderValueParts(parts: ValueParts, variableGroups: Vari >  
{'[Extension missing]'} @@ -52,12 +52,15 @@ export default function renderValueParts(parts: ValueParts, variableGroups: Vari const editable = 'editor' in rtv; const name = (() => { - if (p.type === 'variable_group_item') { + if (p.type === 'variable_set_item') { const payload = p.payload as { itemId: string }; - return getVariableGroupItemName(payload, variableGroups); + return getVariableSetItemName(payload, variableSets); } + if (rtv.getContextAwareName !== void 0) + return rtv.getContextAwareName(p.payload); + return rtv.name; })(); diff --git a/packages/ui/src/features/realtime-values/utils/request.ts b/packages/ui/src/features/variables/utils/request.ts similarity index 100% rename from packages/ui/src/features/realtime-values/utils/request.ts rename to packages/ui/src/features/variables/utils/request.ts diff --git a/packages/ui/src/features/realtime-values/utils/response.ts b/packages/ui/src/features/variables/utils/response.ts similarity index 100% rename from packages/ui/src/features/realtime-values/utils/response.ts rename to packages/ui/src/features/variables/utils/response.ts diff --git a/packages/ui/src/features/realtime-values/values.d.ts b/packages/ui/src/features/variables/values.d.ts similarity index 81% rename from packages/ui/src/features/realtime-values/values.d.ts rename to packages/ui/src/features/variables/values.d.ts index 37d0fe23f..c2ddbf242 100644 --- a/packages/ui/src/features/realtime-values/values.d.ts +++ b/packages/ui/src/features/variables/values.d.ts @@ -1,21 +1,21 @@ import type { ValuePart as GenericValuePart } from '@getbeak/types/values'; export type ValuePart = GenericValuePart; -export type ValueParts = ValuePart[]; +export type ValueSections = ValuePart[]; export interface Base64DecodedRtv { - input: ValueParts; + input: ValueSections; characterSet: 'base64' | 'websafe_base64'; } export interface Base64EncodedRtv { - input: ValueParts; + input: ValueSections; characterSet: 'base64' | 'websafe_base64'; removePadding: boolean; } export interface DigestRtv { - input: ValueParts; + input: ValueSections; algorithm: 'SHA-1' | 'SHA-256' | 'SHA-384' | 'SHA-512' | 'MD5'; hmac?: string; } @@ -26,12 +26,12 @@ export interface PrivateRtv { } export interface RequestHeaderRtv { - headerName: ValueParts; + headerName: ValueSections; } export interface ResponseBodyJsonRtv { requestId: string; - dotPath: ValueParts; + dotPath: ValueSections; } export interface ResponseBodyTextRtv { @@ -40,7 +40,7 @@ export interface ResponseBodyTextRtv { export interface ResponseHeaderRtv { requestId: string; - headerName: ValueParts; + headerName: ValueSections; } export interface ResponseStatusCodeRtv { @@ -64,6 +64,6 @@ export interface UuidRtv { version: 'v1' | 'v4'; } -export interface VariableGroupItemRtv { +export interface VariableSetItemRtv { itemId: string; } diff --git a/packages/ui/src/features/realtime-values/values/base64-decode.ts b/packages/ui/src/features/variables/values/base64-decode.ts similarity index 81% rename from packages/ui/src/features/realtime-values/values/base64-decode.ts rename to packages/ui/src/features/variables/values/base64-decode.ts index 8e9009c6f..da241cb43 100644 --- a/packages/ui/src/features/realtime-values/values/base64-decode.ts +++ b/packages/ui/src/features/variables/values/base64-decode.ts @@ -1,16 +1,16 @@ -import { Base64DecodedRtv, ValueParts } from '@beak/ui/features/realtime-values/values'; -import { EditableRealtimeValue } from '@getbeak/types-realtime-value'; +import { Base64DecodedRtv, ValueSections } from '@beak/ui/features/variables/values'; +import { EditableVariable } from '@getbeak/types-variables'; -import { parseValueParts } from '../parser'; +import { parseValueSections } from '../parser'; const invalidBase64Error = 'Failed to execute \'atob\' on \'Window\': The string to be decoded is not correctly encoded.'; interface EditorState { - input: ValueParts; + input: ValueSections; characterSet: Base64DecodedRtv['characterSet']; } -const definition: EditableRealtimeValue = { +const definition: EditableVariable = { type: 'base64_decoded', name: 'Decode (Base64)', description: 'Decodes a base64 encoded string', @@ -26,7 +26,7 @@ const definition: EditableRealtimeValue = { const isArray = Array.isArray(payload.input); const input = isArray ? payload.input : [payload.input as unknown as string]; - let encoded = await parseValueParts(ctx, input, recursiveDepth); + let encoded = await parseValueSections(ctx, input, recursiveDepth); if (payload.characterSet === 'websafe_base64') encoded = encoded.replaceAll('_', '/').replaceAll('-', '+'); diff --git a/packages/ui/src/features/realtime-values/values/base64-encode.ts b/packages/ui/src/features/variables/values/base64-encode.ts similarity index 81% rename from packages/ui/src/features/realtime-values/values/base64-encode.ts rename to packages/ui/src/features/variables/values/base64-encode.ts index 6f916bed5..d25a5bf19 100644 --- a/packages/ui/src/features/realtime-values/values/base64-encode.ts +++ b/packages/ui/src/features/variables/values/base64-encode.ts @@ -1,15 +1,15 @@ -import { Base64EncodedRtv, ValueParts } from '@beak/ui/features/realtime-values/values'; -import { EditableRealtimeValue } from '@getbeak/types-realtime-value'; +import { Base64EncodedRtv, ValueSections } from '@beak/ui/features/variables/values'; +import { EditableVariable } from '@getbeak/types-variables'; -import { parseValueParts } from '../parser'; +import { parseValueSections } from '../parser'; interface EditorState { - input: ValueParts; + input: ValueSections; characterSet: Base64EncodedRtv['characterSet']; removePadding: boolean; } -const definition: EditableRealtimeValue = { +const definition: EditableVariable = { type: 'base64_encoded', name: 'Encode (Base64)', description: 'Generates a base64 encoded string', @@ -26,7 +26,7 @@ const definition: EditableRealtimeValue = { const isArray = Array.isArray(payload.input); const input = isArray ? payload.input : [payload.input as unknown as string]; - const parsed = await parseValueParts(ctx, input, recursiveDepth); + const parsed = await parseValueSections(ctx, input, recursiveDepth); let encoded = btoa(parsed); if (payload.characterSet === 'websafe_base64') diff --git a/packages/ui/src/features/realtime-values/values/digest.ts b/packages/ui/src/features/variables/values/digest.ts similarity index 76% rename from packages/ui/src/features/realtime-values/values/digest.ts rename to packages/ui/src/features/variables/values/digest.ts index 95f7a7967..670dabbcd 100644 --- a/packages/ui/src/features/realtime-values/values/digest.ts +++ b/packages/ui/src/features/variables/values/digest.ts @@ -1,23 +1,25 @@ -import { DigestRtv, ValueParts } from '@beak/ui/features/realtime-values/values'; +import { DigestRtv, ValueSections } from '@beak/ui/features/variables/values'; import { arrayBufferToHexString } from '@beak/ui/utils/encoding'; -import { EditableRealtimeValue } from '@getbeak/types-realtime-value'; +import { EditableVariable } from '@getbeak/types-variables'; import { Md5 as MD5 } from 'ts-md5'; -import { parseValueParts } from '../parser'; +import { parseValueSections } from '../parser'; interface EditorState { - input: ValueParts; + input: ValueSections; algorithm: DigestRtv['algorithm']; } -const definition: EditableRealtimeValue = { +const definition: EditableVariable = { type: 'digest', - name: 'Digest / Hash', - description: 'Generates a digest of a given input. Supports SHA-*, MD5.', + name: 'Hash', + description: 'Generates a digest of a given input, with a specified hash function Supports SHA-*, MD5.', keywords: ['sha', 'md5', 'sha1', 'sha2', 'sha256', 'sha-384', 'sha512'], sensitive: false, external: false, + getContextAwareName: payload => `Hash (${payload.algorithm})`, + createDefaultPayload: async () => ({ algorithm: 'SHA-256', input: [''], @@ -27,7 +29,7 @@ const definition: EditableRealtimeValue = { getValue: async (ctx, payload, recursiveDepth) => { const { algorithm, input, hmac } = payload; const isArray = Array.isArray(input); - const parsed = await parseValueParts(ctx, isArray ? input : [input as unknown as string], recursiveDepth); + const parsed = await parseValueSections(ctx, isArray ? input : [input as unknown as string], recursiveDepth); if (algorithm === 'MD5') return MD5.hashStr(parsed); diff --git a/packages/ui/src/features/realtime-values/values/nonce.ts b/packages/ui/src/features/variables/values/nonce.ts similarity index 79% rename from packages/ui/src/features/realtime-values/values/nonce.ts rename to packages/ui/src/features/variables/values/nonce.ts index 70155bd78..417c040ab 100644 --- a/packages/ui/src/features/realtime-values/values/nonce.ts +++ b/packages/ui/src/features/variables/values/nonce.ts @@ -1,7 +1,7 @@ import { toWebSafeBase64 } from '@beak/ui/lib/base64'; -import type { RealtimeValue } from '@getbeak/types-realtime-value'; +import type { Variable } from '@getbeak/types-variables'; -const definition: RealtimeValue = { +const definition: Variable = { type: 'nonce', name: 'Nonce', description: 'Generates a cryptographically random string', diff --git a/packages/ui/src/features/realtime-values/values/private.ts b/packages/ui/src/features/variables/values/private.ts similarity index 83% rename from packages/ui/src/features/realtime-values/values/private.ts rename to packages/ui/src/features/variables/values/private.ts index 8b006d126..fb920d7b9 100644 --- a/packages/ui/src/features/realtime-values/values/private.ts +++ b/packages/ui/src/features/variables/values/private.ts @@ -1,16 +1,16 @@ import ksuid from '@beak/ksuid'; -import { PrivateRtv, ValueParts } from '@beak/ui/features/realtime-values/values'; +import { PrivateRtv, ValueSections } from '@beak/ui/features/variables/values'; import { ipcEncryptionService, ipcFsService } from '@beak/ui/lib/ipc'; -import { EditableRealtimeValue } from '@getbeak/types-realtime-value'; +import { EditableVariable } from '@getbeak/types-variables'; import path from 'path-browserify'; -import { parseValueParts } from '../parser'; +import { parseValueSections } from '../parser'; interface EditorState { - value: ValueParts; + value: ValueSections; } -const definition: EditableRealtimeValue = { +const definition: EditableVariable = { type: 'private', name: 'Private', description: 'A value only stored locally, and never included in the project (it is also encrypted at rest). Useful for PII fields.', @@ -40,12 +40,12 @@ const definition: EditableRealtimeValue = { if (!cipherText) return ''; - const decrypted = await ipcEncryptionService.decryptObject({ + const decrypted = await ipcEncryptionService.decryptObject({ iv: item.iv, payload: cipherText, }); - return await parseValueParts(ctx, decrypted, recursiveDepth); + return await parseValueSections(ctx, decrypted, recursiveDepth); }, attributes: {}, @@ -66,7 +66,7 @@ const definition: EditableRealtimeValue = { if (!cipherText) return { value: [] }; - const decrypted = await ipcEncryptionService.decryptObject({ + const decrypted = await ipcEncryptionService.decryptObject({ iv: item.iv, payload: cipherText, }); @@ -93,5 +93,5 @@ const definition: EditableRealtimeValue = { export default definition; function createPath(identifier: string) { - return path.join('.beak', 'realtime-values', 'private', `${identifier}`); + return path.join('.beak', 'variables', 'private', `${identifier}`); } diff --git a/packages/ui/src/features/realtime-values/values/request-folder.ts b/packages/ui/src/features/variables/values/request-folder.ts similarity index 85% rename from packages/ui/src/features/realtime-values/values/request-folder.ts rename to packages/ui/src/features/variables/values/request-folder.ts index af5be76f2..47671dfd2 100644 --- a/packages/ui/src/features/realtime-values/values/request-folder.ts +++ b/packages/ui/src/features/variables/values/request-folder.ts @@ -1,6 +1,6 @@ -import { RealtimeValue } from '@getbeak/types-realtime-value'; +import { Variable } from '@getbeak/types-variables'; -const definition: RealtimeValue = { +const definition: Variable = { type: 'request_folder', name: 'Request folder', description: 'Returns the name of the folder the request is inside', diff --git a/packages/ui/src/features/realtime-values/values/request-header.ts b/packages/ui/src/features/variables/values/request-header.ts similarity index 70% rename from packages/ui/src/features/realtime-values/values/request-header.ts rename to packages/ui/src/features/variables/values/request-header.ts index 80a8c1e66..d9d02d685 100644 --- a/packages/ui/src/features/realtime-values/values/request-header.ts +++ b/packages/ui/src/features/variables/values/request-header.ts @@ -1,14 +1,14 @@ import { TypedObject } from '@beak/common/helpers/typescript'; -import { RequestHeaderRtv, ValueParts } from '@beak/ui/features/realtime-values/values'; -import { EditableRealtimeValue } from '@getbeak/types-realtime-value'; +import { RequestHeaderRtv, ValueSections } from '@beak/ui/features/variables/values'; +import { EditableVariable } from '@getbeak/types-variables'; -import { parseValueParts } from '../parser'; +import { parseValueSections } from '../parser'; interface EditorState { - headerName: ValueParts; + headerName: ValueSections; } -const definition: EditableRealtimeValue = { +const definition: EditableVariable = { type: 'request_header', name: 'Request header', description: 'Returns the value of a header from the request', @@ -25,7 +25,7 @@ const definition: EditableRealtimeValue = { if (!node || node.type !== 'request' || node.mode !== 'valid') return ''; - const parsedHeaderName = await parseValueParts(ctx, payload.headerName, recursiveDepth); + const parsedHeaderName = await parseValueSections(ctx, payload.headerName, recursiveDepth); const headerKey = TypedObject.keys(node.info.headers) .find(k => node.info.headers[k].name.toLocaleLowerCase() === parsedHeaderName.toLocaleLowerCase()); @@ -34,7 +34,7 @@ const definition: EditableRealtimeValue = { if (!header || !header.value) return ''; - return await parseValueParts(ctx, header.value, recursiveDepth); + return await parseValueSections(ctx, header.value, recursiveDepth); }, attributes: { diff --git a/packages/ui/src/features/realtime-values/values/request-method.ts b/packages/ui/src/features/variables/values/request-method.ts similarity index 81% rename from packages/ui/src/features/realtime-values/values/request-method.ts rename to packages/ui/src/features/variables/values/request-method.ts index b5576f1a3..e8c842b6b 100644 --- a/packages/ui/src/features/realtime-values/values/request-method.ts +++ b/packages/ui/src/features/variables/values/request-method.ts @@ -1,6 +1,6 @@ -import { RealtimeValue } from '@getbeak/types-realtime-value'; +import { Variable } from '@getbeak/types-variables'; -const definition: RealtimeValue = { +const definition: Variable = { type: 'request_method', name: 'Request method', description: 'Returns the HTTP method of the this request', diff --git a/packages/ui/src/features/realtime-values/values/request-name.ts b/packages/ui/src/features/variables/values/request-name.ts similarity index 80% rename from packages/ui/src/features/realtime-values/values/request-name.ts rename to packages/ui/src/features/variables/values/request-name.ts index fd91d0df9..b261c0c7c 100644 --- a/packages/ui/src/features/realtime-values/values/request-name.ts +++ b/packages/ui/src/features/variables/values/request-name.ts @@ -1,6 +1,6 @@ -import { RealtimeValue } from '@getbeak/types-realtime-value'; +import { Variable } from '@getbeak/types-variables'; -const definition: RealtimeValue = { +const definition: Variable = { type: 'request_name', name: 'Request name', description: 'Returns the name of the this request', diff --git a/packages/ui/src/features/realtime-values/values/response-body-json.ts b/packages/ui/src/features/variables/values/response-body-json.ts similarity index 78% rename from packages/ui/src/features/realtime-values/values/response-body-json.ts rename to packages/ui/src/features/variables/values/response-body-json.ts index da6546a05..f5ac69186 100644 --- a/packages/ui/src/features/realtime-values/values/response-body-json.ts +++ b/packages/ui/src/features/variables/values/response-body-json.ts @@ -1,18 +1,20 @@ -import { ResponseBodyJsonRtv } from '@beak/ui/features/realtime-values/values'; +import { ResponseBodyJsonRtv } from '@beak/ui/features/variables/values'; import binaryStore from '@beak/ui/lib/binary-store'; import { attemptTextToJson } from '@beak/ui/utils/json'; -import { EditableRealtimeValue } from '@getbeak/types-realtime-value'; +import { EditableVariable } from '@getbeak/types-variables'; import get from 'lodash.get'; -import { parseValueParts } from '../parser'; +import { parseValueSections } from '../parser'; import { getRequestNode } from '../utils/request'; import { getLatestFlight } from '../utils/response'; const allowedRawJson = ['string', 'bool', 'number']; -const definition: EditableRealtimeValue = { +const definition: EditableVariable = { type: 'response_body_json', - name: 'Response body (json)', + name: 'Response body (JSON)', + getContextAwareName: payload => `Response body JSON (${payload.dotPath.join('.')})`, + description: 'Returns the body text value of the most recent response for a request', sensitive: false, external: false, @@ -36,7 +38,7 @@ const definition: EditableRealtimeValue = { +const definition: EditableVariable = { type: 'response_body_text', - name: 'Response body (text)', + name: 'Response body Text', description: 'Returns the body text value of the most recent response for a request', sensitive: false, external: false, diff --git a/packages/ui/src/features/realtime-values/values/response-header.ts b/packages/ui/src/features/variables/values/response-header.ts similarity index 79% rename from packages/ui/src/features/realtime-values/values/response-header.ts rename to packages/ui/src/features/variables/values/response-header.ts index db705547f..e20f1843c 100644 --- a/packages/ui/src/features/realtime-values/values/response-header.ts +++ b/packages/ui/src/features/variables/values/response-header.ts @@ -1,12 +1,12 @@ import { TypedObject } from '@beak/common/helpers/typescript'; -import { ResponseHeaderRtv } from '@beak/ui/features/realtime-values/values'; -import { EditableRealtimeValue } from '@getbeak/types-realtime-value'; +import { ResponseHeaderRtv } from '@beak/ui/features/variables/values'; +import { EditableVariable } from '@getbeak/types-variables'; -import { parseValueParts } from '../parser'; +import { parseValueSections } from '../parser'; import { getRequestNode } from '../utils/request'; import { getLatestFlight } from '../utils/response'; -const definition: EditableRealtimeValue = { +const definition: EditableVariable = { type: 'response_header', name: 'Response header', description: 'Returns the header value of the most recent response for a request', @@ -30,7 +30,7 @@ const definition: EditableRealtimeValue = return ''; const headers = latestFlight.response.headers; - const parsedHeaderName = await parseValueParts(ctx, payload.headerName, recursiveDepth); + const parsedHeaderName = await parseValueSections(ctx, payload.headerName, recursiveDepth); const headerKey = TypedObject.keys(headers) .find(k => k.toLocaleLowerCase() === parsedHeaderName.toLocaleLowerCase()); diff --git a/packages/ui/src/features/realtime-values/values/response-status-code.ts b/packages/ui/src/features/variables/values/response-status-code.ts similarity index 80% rename from packages/ui/src/features/realtime-values/values/response-status-code.ts rename to packages/ui/src/features/variables/values/response-status-code.ts index 5b94ddca0..ecd498cec 100644 --- a/packages/ui/src/features/realtime-values/values/response-status-code.ts +++ b/packages/ui/src/features/variables/values/response-status-code.ts @@ -1,10 +1,10 @@ -import { ResponseStatusCodeRtv } from '@beak/ui/features/realtime-values/values'; -import { EditableRealtimeValue } from '@getbeak/types-realtime-value'; +import { ResponseStatusCodeRtv } from '@beak/ui/features/variables/values'; +import { EditableVariable } from '@getbeak/types-variables'; import { getRequestNode } from '../utils/request'; import { getLatestFlight } from '../utils/response'; -const definition: EditableRealtimeValue = { +const definition: EditableVariable = { type: 'response_status_code', name: 'Response status code', description: 'Returns HTTP status code of the most recent response for a request', diff --git a/packages/ui/src/features/realtime-values/values/secure.ts b/packages/ui/src/features/variables/values/secure.ts similarity index 82% rename from packages/ui/src/features/realtime-values/values/secure.ts rename to packages/ui/src/features/variables/values/secure.ts index 578f65016..8d48646cc 100644 --- a/packages/ui/src/features/realtime-values/values/secure.ts +++ b/packages/ui/src/features/variables/values/secure.ts @@ -1,14 +1,14 @@ -import { SecureRtv, ValueParts } from '@beak/ui/features/realtime-values/values'; +import { SecureRtv, ValueSections } from '@beak/ui/features/variables/values'; import { ipcEncryptionService } from '@beak/ui/lib/ipc'; -import { EditableRealtimeValue } from '@getbeak/types-realtime-value'; +import { EditableVariable } from '@getbeak/types-variables'; -import { parseValueParts } from '../parser'; +import { parseValueSections } from '../parser'; interface EditorState { - value: ValueParts; + value: ValueSections; } -const definition: EditableRealtimeValue = { +const definition: EditableVariable = { type: 'secure', name: 'Secure', description: 'A value protected by Beak project encryption', @@ -37,12 +37,12 @@ const definition: EditableRealtimeValue = { }); } - const decrypted = await ipcEncryptionService.decryptObject({ + const decrypted = await ipcEncryptionService.decryptObject({ iv: item.iv, payload: item.cipherText, }); - return await parseValueParts(ctx, decrypted); + return await parseValueSections(ctx, decrypted); }, attributes: {}, @@ -64,7 +64,7 @@ const definition: EditableRealtimeValue = { return { value: [decrypted] }; } - const decrypted = await ipcEncryptionService.decryptObject({ + const decrypted = await ipcEncryptionService.decryptObject({ iv: item.iv, payload: item.cipherText, }); diff --git a/packages/ui/src/features/realtime-values/values/special-character.ts b/packages/ui/src/features/variables/values/special-character.ts similarity index 85% rename from packages/ui/src/features/realtime-values/values/special-character.ts rename to packages/ui/src/features/variables/values/special-character.ts index c28c2fe56..cf17e79f6 100644 --- a/packages/ui/src/features/realtime-values/values/special-character.ts +++ b/packages/ui/src/features/variables/values/special-character.ts @@ -1,4 +1,4 @@ -import { RealtimeValue } from '@getbeak/types-realtime-value'; +import { Variable } from '@getbeak/types-variables'; const characters = { character_carriage_return: { @@ -22,7 +22,7 @@ export const characterCarriageReturnRtv = createCharacter('character_carriage_re export const characterNewlineRtv = createCharacter('character_newline'); export const characterTabRtv = createCharacter('character_tab'); -function createCharacter(type: keyof typeof characters): RealtimeValue { +function createCharacter(type: keyof typeof characters): Variable { const character = characters[type]; return { diff --git a/packages/ui/src/features/realtime-values/values/timestamp.ts b/packages/ui/src/features/variables/values/timestamp.ts similarity index 84% rename from packages/ui/src/features/realtime-values/values/timestamp.ts rename to packages/ui/src/features/variables/values/timestamp.ts index 566cd5924..c9d8d9d0f 100644 --- a/packages/ui/src/features/realtime-values/values/timestamp.ts +++ b/packages/ui/src/features/variables/values/timestamp.ts @@ -1,5 +1,5 @@ -import { TimestampRtv } from '@beak/ui/features/realtime-values/values'; -import { EditableRealtimeValue } from '@getbeak/types-realtime-value'; +import { TimestampRtv } from '@beak/ui/features/variables/values'; +import { EditableVariable } from '@getbeak/types-variables'; import { add } from 'date-fns'; interface EditorState { @@ -7,9 +7,11 @@ interface EditorState { type: string; } -const definition: EditableRealtimeValue = { +const definition: EditableVariable = { type: 'timestamp', name: 'Datetime', + getContextAwareName: payload => `Datetime (${payload.type})`, + description: 'Render a date-time in a specific format, with an optional delta', sensitive: false, external: false, diff --git a/packages/ui/src/features/realtime-values/values/url-decode.ts b/packages/ui/src/features/variables/values/url-decode.ts similarity index 64% rename from packages/ui/src/features/realtime-values/values/url-decode.ts rename to packages/ui/src/features/variables/values/url-decode.ts index 41e6cd2d6..f29a5cdc8 100644 --- a/packages/ui/src/features/realtime-values/values/url-decode.ts +++ b/packages/ui/src/features/variables/values/url-decode.ts @@ -1,13 +1,13 @@ -import { ValueParts } from '@beak/ui/features/realtime-values/values'; -import { EditableRealtimeValue } from '@getbeak/types-realtime-value'; +import { ValueSections } from '@beak/ui/features/variables/values'; +import { EditableVariable } from '@getbeak/types-variables'; -import { parseValueParts } from '../parser'; +import { parseValueSections } from '../parser'; interface EditorState { - input: ValueParts; + input: ValueSections; } -const definition: EditableRealtimeValue = { +const definition: EditableVariable = { type: 'url_decode', name: 'Decode (URL)', description: 'Decodes a url encoded string', @@ -17,7 +17,7 @@ const definition: EditableRealtimeValue = { createDefaultPayload: async () => ({ input: [''] }), getValue: async (ctx, payload, recursiveDepth) => { - const parsed = await parseValueParts(ctx, payload.input, recursiveDepth); + const parsed = await parseValueSections(ctx, payload.input, recursiveDepth); return decodeURIComponent(parsed); }, diff --git a/packages/ui/src/features/realtime-values/values/url-encode.ts b/packages/ui/src/features/variables/values/url-encode.ts similarity index 64% rename from packages/ui/src/features/realtime-values/values/url-encode.ts rename to packages/ui/src/features/variables/values/url-encode.ts index 394955275..516454336 100644 --- a/packages/ui/src/features/realtime-values/values/url-encode.ts +++ b/packages/ui/src/features/variables/values/url-encode.ts @@ -1,13 +1,13 @@ -import { ValueParts } from '@beak/ui/features/realtime-values/values'; -import { EditableRealtimeValue } from '@getbeak/types-realtime-value'; +import { ValueSections } from '@beak/ui/features/variables/values'; +import { EditableVariable } from '@getbeak/types-variables'; -import { parseValueParts } from '../parser'; +import { parseValueSections } from '../parser'; interface EditorState { - input: ValueParts; + input: ValueSections; } -const definition: EditableRealtimeValue = { +const definition: EditableVariable = { type: 'url_encode', name: 'Encode (URL)', description: 'Generates a url encoded string', @@ -19,7 +19,7 @@ const definition: EditableRealtimeValue = { }), getValue: async (ctx, payload, recursiveDepth) => { - const parsed = await parseValueParts(ctx, payload.input, recursiveDepth); + const parsed = await parseValueSections(ctx, payload.input, recursiveDepth); return encodeURIComponent(parsed); }, diff --git a/packages/ui/src/features/realtime-values/values/uuid.ts b/packages/ui/src/features/variables/values/uuid.ts similarity index 80% rename from packages/ui/src/features/realtime-values/values/uuid.ts rename to packages/ui/src/features/variables/values/uuid.ts index f9a366ae6..98a847d0a 100644 --- a/packages/ui/src/features/realtime-values/values/uuid.ts +++ b/packages/ui/src/features/variables/values/uuid.ts @@ -1,12 +1,12 @@ -import { UuidRtv } from '@beak/ui/features/realtime-values/values'; -import { EditableRealtimeValue } from '@getbeak/types-realtime-value'; +import { UuidRtv } from '@beak/ui/features/variables/values'; +import { EditableVariable } from '@getbeak/types-variables'; import * as uuid from 'uuid'; interface EditorState { version: UuidRtv['version']; } -const definition: EditableRealtimeValue = { +const definition: EditableVariable = { type: 'uuid', name: 'UUID', description: 'Generate a UUID', diff --git a/packages/ui/src/features/variables/values/variable-set-item.ts b/packages/ui/src/features/variables/values/variable-set-item.ts new file mode 100644 index 000000000..d8cafaa54 --- /dev/null +++ b/packages/ui/src/features/variables/values/variable-set-item.ts @@ -0,0 +1,69 @@ +import { TypedObject } from '@beak/common/helpers/typescript'; +import { VariableSetItemRtv } from '@beak/ui/features/variables/values'; +import type { VariableSets } from '@getbeak/types/variable-sets'; +import { Variable } from '@getbeak/types-variables'; + +import { getValueSections, parseValueSections } from '../parser'; + +const type = 'variable_set_item'; + +const definition: Variable = { + type, + name: 'Variable set item', + description: 'A variable from a variable set, you can edit it\'s value from the Variable Group editor', + sensitive: false, + external: false, + + createDefaultPayload: () => { + throw new Error('Not supported, this should not happen.'); + }, + + getValue: async (ctx, item, recursiveDepth) => { + const parts = getValueSections(ctx, item.itemId) || []; + + return await parseValueSections(ctx, parts, recursiveDepth); + }, + + attributes: {}, +}; + +export function createFauxValue( + item: VariableSetItemRtv, + variableSets: VariableSets, +): Variable { + return { + type, + name: getVariableSetItemName(item, variableSets), + description: 'A variable from a variable set, you can edit it\'s value from the Variable Group editor', + sensitive: false, + external: false, + + getContextAwareName: void 0, + createDefaultPayload: async () => item, + + getValue: () => { + throw new Error('Not supported, this should not happen.'); + }, + + attributes: {}, + }; +} + +export function getVariableSetItemName(item: VariableSetItemRtv, variableSets: VariableSets) { + if (!variableSets) + return 'Unknown'; + + const keys = TypedObject.keys(variableSets); + + for (const key of keys) { + const vg = variableSets[key]; + const itemValue = vg.items[item.itemId]; + + if (itemValue) + return `${key} (${itemValue})`; + } + + return 'Unknown'; +} + +export default definition; diff --git a/packages/ui/src/lib/beak-hub/schemas/editor-preferences.json b/packages/ui/src/lib/beak-hub/schemas/editor-preferences.json index 87ffcd9d1..2b5c271e7 100644 --- a/packages/ui/src/lib/beak-hub/schemas/editor-preferences.json +++ b/packages/ui/src/lib/beak-hub/schemas/editor-preferences.json @@ -3,7 +3,7 @@ "additionalProperties": false, "properties": { - "selectedVariableGroups": { + "selectedVariableSets": { "type": "object", "patternProperties": { diff --git a/packages/ui/src/lib/beak-hub/schemas/tab-preferences.json b/packages/ui/src/lib/beak-hub/schemas/tab-preferences.json index 39b16ac77..86f06b814 100644 --- a/packages/ui/src/lib/beak-hub/schemas/tab-preferences.json +++ b/packages/ui/src/lib/beak-hub/schemas/tab-preferences.json @@ -27,7 +27,7 @@ } }, - "variableGroupEditorTab": { + "variableSetEditorTab": { "type": "object", "additionalProperties": false, @@ -38,7 +38,7 @@ ], "properties": { - "type": { "const": "variable_group_editor" }, + "type": { "const": "variable_set_editor" }, "payload": { "type": "string", "minLength": 1 @@ -77,7 +77,7 @@ "items": { "oneOf": [ { "$ref": "#/definitions/requestTab" }, - { "$ref": "#/definitions/variableGroupEditorTab" }, + { "$ref": "#/definitions/variableSetEditorTab" }, { "$ref": "#/definitions/newProjectIntroTab" } ] } diff --git a/packages/ui/src/lib/beak-project/project.ts b/packages/ui/src/lib/beak-project/project.ts index 793d8f9a4..cce42d22a 100644 --- a/packages/ui/src/lib/beak-project/project.ts +++ b/packages/ui/src/lib/beak-project/project.ts @@ -5,7 +5,7 @@ import { readJsonAndValidate } from '../fs'; import { ipcFsService } from '../ipc'; import { projectSchema } from './schemas'; -const latestSupported = '0.3.0'; +const latestSupported = '0.4.0'; export async function readProjectFile() { const { file } = await readJsonAndValidate('project.json', projectSchema); diff --git a/packages/ui/src/lib/beak-project/schemas/request.json b/packages/ui/src/lib/beak-project/schemas/request.json index b249daa32..2bbbb9411 100644 --- a/packages/ui/src/lib/beak-project/schemas/request.json +++ b/packages/ui/src/lib/beak-project/schemas/request.json @@ -3,7 +3,7 @@ "additionalProperties": false, "definitions": { - "valueParts": { + "ValueSections": { "type": "array", "items": { "oneOf": [ @@ -96,7 +96,7 @@ }, "then": { "properties": { - "value": { "$ref": "#/definitions/valueParts" } + "value": { "$ref": "#/definitions/ValueSections" } } } }, @@ -109,7 +109,7 @@ }, "then": { "properties": { - "value": { "$ref": "#/definitions/valueParts" } + "value": { "$ref": "#/definitions/ValueSections" } } } }, @@ -153,7 +153,7 @@ "properties": { "name": { "type": "string" }, - "value": { "$ref": "#/definitions/valueParts" }, + "value": { "$ref": "#/definitions/ValueSections" }, "enabled": { "type": "boolean" } } }, @@ -308,7 +308,7 @@ "type": "string" }, - "url": { "$ref": "#/definitions/valueParts" }, + "url": { "$ref": "#/definitions/ValueSections" }, "query": { "type": "object", diff --git a/packages/ui/src/lib/beak-project/variable-groups.ts b/packages/ui/src/lib/beak-project/variable-sets.ts similarity index 63% rename from packages/ui/src/lib/beak-project/variable-groups.ts rename to packages/ui/src/lib/beak-project/variable-sets.ts index 98a0315b0..0d7403cb1 100644 --- a/packages/ui/src/lib/beak-project/variable-groups.ts +++ b/packages/ui/src/lib/beak-project/variable-sets.ts @@ -1,11 +1,11 @@ import ksuid from '@beak/ksuid'; -import type { VariableGroup } from '@getbeak/types/variable-groups'; +import type { VariableSet } from '@getbeak/types/variable-sets'; import path from 'path-browserify'; import { ipcFsService } from '../ipc'; import { generateSafeNewPath } from './utils'; -const variableGroupNameWordlist = [ +const variableSetNameWordlist = [ 'Anhinga', 'Albatross', 'Kingfisher', @@ -61,12 +61,12 @@ const variableGroupNameWordlist = [ 'Wren', ]; -export async function createVariableGroup(directory: string, name?: string) { - const id = name ?? generateVariableGroupName(); +export async function createVariableSet(directory: string, name?: string) { + const id = name ?? generateVariableSetName(); const { fullPath } = await generateSafeNewPath(id, directory, '.json'); - const variableGroup: VariableGroup = { - groups: { - [ksuid.generate('group').toString()]: 'Group', + const variableSet: VariableSet = { + sets: { + [ksuid.generate('set').toString()]: 'Set', }, items: { [ksuid.generate('item').toString()]: 'Item', @@ -74,22 +74,22 @@ export async function createVariableGroup(directory: string, name?: string) { values: {}, }; - await ipcFsService.writeJson(fullPath, variableGroup, { spaces: '\t' }); + await ipcFsService.writeJson(fullPath, variableSet, { spaces: '\t' }); return id; } -export async function renameVariableGroup(oldName: string, newName: string) { - const oldFilePath = path.join('variable-groups', `${oldName}.json`); - const newFilePath = path.join('variable-groups', `${newName}.json`); +export async function renameVariableSet(oldName: string, newName: string) { + const oldFilePath = path.join('variable-sets', `${oldName}.json`); + const newFilePath = path.join('variable-sets', `${newName}.json`); if (await ipcFsService.pathExists(newFilePath)) - throw new Error('Variable group already exists'); + throw new Error('Variable set already exists'); await ipcFsService.move(oldFilePath, newFilePath); } -function generateVariableGroupName() { +function generateVariableSetName() { const firstWord = getWordIndex(); const secondWord = getWordIndex(); @@ -101,8 +101,8 @@ function generateVariableGroupName() { function getWordIndex() { const min = 0; - const max = variableGroupNameWordlist.length; + const max = variableSetNameWordlist.length; const index = Math.floor(Math.random() * (max - min) + min); // The maximum is exclusive and the minimum is inclusive - return variableGroupNameWordlist[index]; + return variableSetNameWordlist[index]; } diff --git a/packages/ui/src/lib/beak-variable-group/index.ts b/packages/ui/src/lib/beak-variable-group/index.ts deleted file mode 100644 index 52e00ab3e..000000000 --- a/packages/ui/src/lib/beak-variable-group/index.ts +++ /dev/null @@ -1,22 +0,0 @@ -import type { VariableGroup } from '@getbeak/types/variable-groups'; -import path from 'path-browserify'; - -import { readJsonAndValidate } from '../fs'; -import { ipcFsService } from '../ipc'; -import { variableGroupSchema } from './schema'; - -export async function readVariableGroup(vgFilePath: string) { - return await readJsonAndValidate(vgFilePath, variableGroupSchema); -} - -export async function writeVariableGroup(name: string, variableGroup: VariableGroup) { - const filePath = path.join('variable-groups', `${name}.json`); - - await ipcFsService.writeJson(filePath, variableGroup, { spaces: '\t' }); -} - -export async function removeVariableGroup(name: string) { - const filePath = path.join('variable-groups', `${name}.json`); - - await ipcFsService.remove(filePath); -} diff --git a/packages/ui/src/lib/beak-variable-group/schema/index.ts b/packages/ui/src/lib/beak-variable-group/schema/index.ts deleted file mode 100644 index a1713cae5..000000000 --- a/packages/ui/src/lib/beak-variable-group/schema/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -import variableGroupSchema from './variable-group.json'; - -export { - variableGroupSchema, -}; diff --git a/packages/ui/src/lib/beak-variable-group/utils.ts b/packages/ui/src/lib/beak-variable-group/utils.ts deleted file mode 100644 index 81d1e379d..000000000 --- a/packages/ui/src/lib/beak-variable-group/utils.ts +++ /dev/null @@ -1,3 +0,0 @@ -export function generateValueIdent(groupId: string, itemId: string) { - return `${groupId}&${itemId}`; -} diff --git a/packages/ui/src/lib/beak-variable-set/index.ts b/packages/ui/src/lib/beak-variable-set/index.ts new file mode 100644 index 000000000..8027d0850 --- /dev/null +++ b/packages/ui/src/lib/beak-variable-set/index.ts @@ -0,0 +1,22 @@ +import type { VariableSet } from '@getbeak/types/variable-sets'; +import path from 'path-browserify'; + +import { readJsonAndValidate } from '../fs'; +import { ipcFsService } from '../ipc'; +import { variableSetSchema } from './schema'; + +export async function readVariableSet(vgFilePath: string) { + return await readJsonAndValidate(vgFilePath, variableSetSchema); +} + +export async function writeVariableSet(name: string, variableSet: VariableSet) { + const filePath = path.join('variable-sets', `${name}.json`); + + await ipcFsService.writeJson(filePath, variableSet, { spaces: '\t' }); +} + +export async function removeVariableSet(name: string) { + const filePath = path.join('variable-sets', `${name}.json`); + + await ipcFsService.remove(filePath); +} diff --git a/packages/ui/src/lib/beak-variable-set/schema/index.ts b/packages/ui/src/lib/beak-variable-set/schema/index.ts new file mode 100644 index 000000000..729408f14 --- /dev/null +++ b/packages/ui/src/lib/beak-variable-set/schema/index.ts @@ -0,0 +1,5 @@ +import variableSetSchema from './variable-set.json'; + +export { + variableSetSchema, +}; diff --git a/packages/ui/src/lib/beak-variable-group/schema/variable-group.json b/packages/ui/src/lib/beak-variable-set/schema/variable-set.json similarity index 87% rename from packages/ui/src/lib/beak-variable-group/schema/variable-group.json rename to packages/ui/src/lib/beak-variable-set/schema/variable-set.json index 1b8e4fbfc..e31f412c9 100644 --- a/packages/ui/src/lib/beak-variable-group/schema/variable-group.json +++ b/packages/ui/src/lib/beak-variable-set/schema/variable-set.json @@ -15,13 +15,13 @@ }, "required": [ - "groups", + "sets", "items", "values" ], "properties": { - "groups": { "$ref": "#/definitions/mapping" }, + "sets": { "$ref": "#/definitions/mapping" }, "items": { "$ref": "#/definitions/mapping" }, "values": { diff --git a/packages/ui/src/lib/beak-variable-set/utils.ts b/packages/ui/src/lib/beak-variable-set/utils.ts new file mode 100644 index 000000000..3f7e52ca7 --- /dev/null +++ b/packages/ui/src/lib/beak-variable-set/utils.ts @@ -0,0 +1,3 @@ +export function generateValueIdent(setId: string, itemId: string) { + return `${setId}&${itemId}`; +} diff --git a/packages/ui/src/lib/keyboard-shortcuts/index.ts b/packages/ui/src/lib/keyboard-shortcuts/index.ts index 93fa9208e..9f2857b78 100644 --- a/packages/ui/src/lib/keyboard-shortcuts/index.ts +++ b/packages/ui/src/lib/keyboard-shortcuts/index.ts @@ -17,8 +17,8 @@ export type Shortcuts = | 'tree-view.node.rename' | 'tree-view.node.delete' - | 'variable-groups.variable-group.open' - | 'variable-groups.variable-group.delete' + | 'variable-sets.variable-set.open' + | 'variable-sets.variable-set.delete' | 'project-explorer.request.open' | 'project-explorer.request.duplicate' @@ -67,14 +67,14 @@ export const shortcutDefinitions: Record { try { const extension = await ipcExtensionsService.registerRtv({ extensionFilePath: dependencyPath }); - RealtimeValueManager.registerExternalRealtimeValue(extension); + VariableManager.registerExternalVariable(extension); return extension; } catch (error) { diff --git a/packages/ui/src/store/extensions/types.ts b/packages/ui/src/store/extensions/types.ts index 26c1ff182..6281185e6 100644 --- a/packages/ui/src/store/extensions/types.ts +++ b/packages/ui/src/store/extensions/types.ts @@ -1,4 +1,4 @@ -import { RealtimeValueExtension } from '@beak/common/types/extensions'; +import { VariableExtension } from '@beak/common/types/extensions'; import Squawk from '@beak/common/utils/squawk'; export const ActionTypes = { @@ -21,7 +21,7 @@ export interface FailedExtension { error: Squawk; } -export type Extension = FailedExtension | RealtimeValueExtension; +export type Extension = FailedExtension | VariableExtension; export interface ExtensionsOpenedPayload { extensions: Extension[]; diff --git a/packages/ui/src/store/flight/sagas/request-flight.ts b/packages/ui/src/store/flight/sagas/request-flight.ts index fe56131bb..3e54b558b 100644 --- a/packages/ui/src/store/flight/sagas/request-flight.ts +++ b/packages/ui/src/store/flight/sagas/request-flight.ts @@ -4,7 +4,7 @@ import ksuid from '@beak/ksuid'; import { instance as windowSessionInstance } from '@beak/ui/contexts/window-session-context'; import { convertKeyValueToString } from '@beak/ui/features/basic-table-editor/parsers'; import { convertToRealJson } from '@beak/ui/features/json-editor/parsers'; -import { parseValueParts } from '@beak/ui/features/realtime-values/parser'; +import { parseValueSections } from '@beak/ui/features/variables/parser'; import { ipcDialogService, ipcFsService } from '@beak/ui/lib/ipc'; import { requestAllowsBody } from '@beak/ui/utils/http'; import { convertRequestToUrl } from '@beak/ui/utils/uri'; @@ -17,7 +17,7 @@ import type { ToggleKeyValue, } from '@getbeak/types/request'; import type { Context } from '@getbeak/types/values'; -import type { VariableGroups } from '@getbeak/types/variable-groups'; +import type { VariableSets } from '@getbeak/types/variable-sets'; import { FetcherParams } from '@graphiql/toolkit'; import { call, put, select } from '@redux-saga/core/effects'; @@ -45,16 +45,16 @@ export default function* requestFlightWorker() { const flightHistory: Record = yield select( (s: ApplicationState) => s.global.flight.flightHistory, ); - const variableGroups: VariableGroups = yield select( - (s: ApplicationState) => s.global.variableGroups.variableGroups, + const variableSets: VariableSets = yield select( + (s: ApplicationState) => s.global.variableSets.variableSets, ); - const selectedGroups: Record = yield select( - (s: ApplicationState) => s.global.preferences.editor.selectedVariableGroups, + const selectedSets: Record = yield select( + (s: ApplicationState) => s.global.preferences.editor.selectedVariableSets, ); const context: Context = { - selectedGroups, - variableGroups, + selectedSets, + variableSets, flightHistory, projectTree, currentRequestId: requestId, @@ -91,7 +91,7 @@ export default function* requestFlightWorker() { async function prepareRequest(overview: RequestOverview, context: Context): Promise { const url = await convertRequestToUrl(context, overview); - const headers = await flattenToggleValueParts(context, overview.headers); + const headers = await flattenToggleValueSections(context, overview.headers); if (!hasHeader('user-agent', headers)) { headers[ksuid.generate('header').toString()] = { @@ -124,14 +124,14 @@ async function prepareRequest(overview: RequestOverview, context: Context): Prom return requestOverview; } -async function flattenToggleValueParts(context: Context, toggleValueParts: Record) { +async function flattenToggleValueSections(context: Context, toggleValueSections: Record) { const out: Record = {}; - await Promise.all(TypedObject.keys(toggleValueParts).map(async k => { + await Promise.all(TypedObject.keys(toggleValueSections).map(async k => { out[k] = { - enabled: toggleValueParts[k].enabled, - name: toggleValueParts[k].name, - value: [await parseValueParts(context, toggleValueParts[k].value)], + enabled: toggleValueSections[k].enabled, + name: toggleValueSections[k].name, + value: [await parseValueSections(context, toggleValueSections[k].value)], }; })); @@ -143,7 +143,7 @@ async function flattenQuery( overview: RequestOverview, ): Promise> { const { body, query, verb } = overview; - const resolvedQuery = await flattenToggleValueParts(context, query); + const resolvedQuery = await flattenToggleValueSections(context, query); // When using GraphQL body-less verbs require the body to be sent via the url if (!requestAllowsBody(verb) && body.type === 'graphql') { diff --git a/packages/ui/src/store/git/sagas/index.ts b/packages/ui/src/store/git/sagas/index.ts index 4c651d04e..99c886c87 100644 --- a/packages/ui/src/store/git/sagas/index.ts +++ b/packages/ui/src/store/git/sagas/index.ts @@ -3,7 +3,7 @@ import { all, fork, takeEvery } from '@redux-saga/core/effects'; import { ActionTypes } from '../types'; import startGit from './start-git'; -export default function* variableGroupsSaga() { +export default function* variableSetsSaga() { yield all([ fork(function* startGitWatcher() { yield takeEvery(ActionTypes.START_GIT, startGit); diff --git a/packages/ui/src/store/index.ts b/packages/ui/src/store/index.ts index 47ed5a070..2354f5911 100644 --- a/packages/ui/src/store/index.ts +++ b/packages/ui/src/store/index.ts @@ -22,8 +22,8 @@ import * as preferencesStore from './preferences'; import { State as PreferencesState } from './preferences/types'; import * as projectStore from './project'; import { State as ProjectState } from './project/types'; -import * as variableGroupsStore from './variable-groups'; -import { State as VariableGroupState } from './variable-groups/types'; +import * as variableSetsStore from './variable-sets'; +import { State as VariableSetState } from './variable-sets/types'; export interface ApplicationState { features: { @@ -38,7 +38,7 @@ export interface ApplicationState { git: GitState; preferences: PreferencesState; project: ProjectState; - variableGroups: VariableGroupState; + variableSets: VariableSetState; }; } @@ -56,7 +56,7 @@ function createRootReducer() { git: gitStore.reducers, preferences: preferencesStore.reducers, project: projectStore.reducers, - variableGroups: variableGroupsStore.reducers, + variableSets: variableSetsStore.reducers, }), }); } @@ -70,7 +70,7 @@ function* rootSaga() { fork(gitStore.sagas), fork(preferencesStore.sagas), fork(projectStore.sagas), - fork(variableGroupsStore.sagas), + fork(variableSetsStore.sagas), ]); } @@ -88,7 +88,7 @@ function createInitialState(): ApplicationState { git: gitStore.types.initialState, preferences: preferencesStore.types.initialState, project: projectStore.types.initialState, - variableGroups: variableGroupsStore.types.initialState, + variableSets: variableSetsStore.types.initialState, }, }; } diff --git a/packages/ui/src/store/preferences/actions.ts b/packages/ui/src/store/preferences/actions.ts index ffdae729a..cac587178 100644 --- a/packages/ui/src/store/preferences/actions.ts +++ b/packages/ui/src/store/preferences/actions.ts @@ -4,7 +4,7 @@ import { createAction } from '@reduxjs/toolkit'; import { ActionTypes as AT, - EditorPreferencesSetSelectedVariableGroupPayload, + EditorPreferencesSetSelectedVariableSetPayload, ProjectPaneCollapsePayload, RequestPreferencePayload, RequestPreferencesLoadedPayload, @@ -26,7 +26,7 @@ export const requestPreferenceSetResPrettyLanguage = createAction(AT.EDITOR_PREFERENCES_LOADED); -export const editorPreferencesSetSelectedVariableGroup = createAction(AT.EDITOR_PREFERENCES_SET_SELECTED_VARIABLE_GROUP); +export const editorPreferencesSetSelectedVariableSet = createAction(AT.EDITOR_PREFERENCES_SET_SELECTED_VARIABLE_GROUP); export const loadSidebarPreferences = createAction(AT.LOAD_SIDEBAR_PREFERENCES); export const sidebarPreferencesLoaded = createAction(AT.SIDEBAR_PREFERENCES_LOADED); @@ -48,7 +48,7 @@ export default { loadEditorPreferences, editorPreferencesLoaded, - editorPreferencesSetSelectedVariableGroup, + editorPreferencesSetSelectedVariableSet, loadSidebarPreferences, sidebarPreferencesLoaded, diff --git a/packages/ui/src/store/preferences/reducers.ts b/packages/ui/src/store/preferences/reducers.ts index 31efea34f..a4dc0c370 100644 --- a/packages/ui/src/store/preferences/reducers.ts +++ b/packages/ui/src/store/preferences/reducers.ts @@ -32,10 +32,10 @@ const reducer = createReducer(initialState, builder => { .addCase(actions.editorPreferencesLoaded, (state, { payload }) => { state.editor = payload; }) - .addCase(actions.editorPreferencesSetSelectedVariableGroup, (state, { payload }) => { - const { variableGroup, groupId } = payload; + .addCase(actions.editorPreferencesSetSelectedVariableSet, (state, { payload }) => { + const { variableSet, setId: setId } = payload; - state.editor.selectedVariableGroups[variableGroup] = groupId; + state.editor.selectedVariableSets[variableSet] = setId; }) .addCase(actions.sidebarPreferencesLoaded, (state, { payload }) => { diff --git a/packages/ui/src/store/preferences/sagas/catch-load-preferences.ts b/packages/ui/src/store/preferences/sagas/catch-load-preferences.ts index 4d540029f..cbfa8a69f 100644 --- a/packages/ui/src/store/preferences/sagas/catch-load-preferences.ts +++ b/packages/ui/src/store/preferences/sagas/catch-load-preferences.ts @@ -94,7 +94,7 @@ async function loadRequestPreferences(id: string) { async function loadEditorPreferences() { const preferencesPath = path.join('.beak', 'preferences', 'editor.json'); const defaultPreferences: EditorPreferences = { - selectedVariableGroups: {}, + selectedVariableSets: {}, }; if (!await ipcFsService.pathExists(preferencesPath)) diff --git a/packages/ui/src/store/preferences/types.ts b/packages/ui/src/store/preferences/types.ts index 61ae4dae1..6dda1dd23 100644 --- a/packages/ui/src/store/preferences/types.ts +++ b/packages/ui/src/store/preferences/types.ts @@ -40,7 +40,7 @@ export interface State { export const initialState: State = { requests: {}, editor: { - selectedVariableGroups: {}, + selectedVariableSets: {}, }, sidebar: { selected: 'project', @@ -68,9 +68,9 @@ export type RequestPreferencesSetResPrettyLanguagePayload = RequestPreferencePay language: string | null; }>; -export interface EditorPreferencesSetSelectedVariableGroupPayload { - variableGroup: string; - groupId: string; +export interface EditorPreferencesSetSelectedVariableSetPayload { + variableSet: string; + setId: string; } export interface SidebarCollapsePayload { diff --git a/packages/ui/src/store/project/sagas/start-project.ts b/packages/ui/src/store/project/sagas/start-project.ts index 85e96a147..2a6c131a3 100644 --- a/packages/ui/src/store/project/sagas/start-project.ts +++ b/packages/ui/src/store/project/sagas/start-project.ts @@ -14,7 +14,7 @@ import { call, put, select, take } from '@redux-saga/core/effects'; import path from 'path-browserify'; import { ApplicationState } from '../..'; -import { startVariableGroups } from '../../variable-groups/actions'; +import { startVariableSets } from '../../variable-sets/actions'; import { LatestWrite } from '../types'; interface Event { @@ -32,7 +32,7 @@ export default function* workerStartProject() { channel = createFsEmitter('tree', { followSymlinks: false }); yield put(actions.insertProjectInfo({ id: project.id, name: project.name })); - yield put(startVariableGroups()); + yield put(startVariableSets()); yield initialImport('tree'); yield put(loadTabState()); } catch (error) { diff --git a/packages/ui/src/store/project/types.ts b/packages/ui/src/store/project/types.ts index 207995647..542579b84 100644 --- a/packages/ui/src/store/project/types.ts +++ b/packages/ui/src/store/project/types.ts @@ -1,7 +1,7 @@ import Squawk from '@beak/common/utils/squawk'; import { ExtractedVariables } from '@beak/ui/features/graphql-editor/types'; -import { ValueParts } from '@beak/ui/features/realtime-values/values'; import { ActiveRename } from '@beak/ui/features/tree-view/types'; +import { ValueSections } from '@beak/ui/features/variables/values'; import type { EntryMap, EntryType } from '@getbeak/types/body-editor-json'; import type { Tree } from '@getbeak/types/nodes'; import type { ToggleKeyValue } from '@getbeak/types/request'; @@ -115,19 +115,19 @@ export interface ProjectOpenedPayload { tree: Tree } export interface RequestIdPayload { requestId: string } export interface RequestUriUpdatedPayload extends RequestIdPayload { - url?: ValueParts; + url?: ValueSections; verb?: string; } export interface ToggleableItemAddedPayload extends RequestIdPayload { name?: string; - value?: ValueParts; + value?: ValueSections; } export interface ToggleableItemUpdatedPayload extends RequestIdPayload { identifier: string; name?: string; - value?: ValueParts; + value?: ValueSections; enabled?: boolean; } @@ -218,7 +218,7 @@ export interface RequestBodyJsonEditorNameChangePayload extends RequestIdPayload export interface RequestBodyJsonEditorValueChangePayload extends RequestIdPayload { id: string; - value: ValueParts | boolean | null; + value: ValueSections | boolean | null; } export interface RequestBodyJsonEditorTypeChangePayload extends RequestIdPayload { @@ -241,7 +241,7 @@ export interface RequestBodyUrlEncodedEditorNameChangePayload extends RequestIdP export interface RequestBodyUrlEncodedEditorValueChangePayload extends RequestIdPayload { id: string; - value: ValueParts; + value: ValueSections; } export interface RequestBodyUrlEncodedEditorEnabledChangePayload extends RequestIdPayload { diff --git a/packages/ui/src/store/variable-groups/actions.ts b/packages/ui/src/store/variable-groups/actions.ts deleted file mode 100644 index 2fcbf9f18..000000000 --- a/packages/ui/src/store/variable-groups/actions.ts +++ /dev/null @@ -1,79 +0,0 @@ -/* eslint-disable max-len */ - -import { createAction } from '@reduxjs/toolkit'; - -import { - ActionTypes as AT, - CreateNewVariableGroupPayload, - InsertNewGroupPayload, - InsertNewItemPayload, - InsertNewVariableGroupPayload, - RemoveGroupPayload, - RemoveItemPayload, - RemoveVariableGroupFromDiskPayload, - UpdateGroupNamePayload, - UpdateItemNamePayload, - UpdateValuePayload, - VariableGroupRenameCancelled, - VariableGroupRenameResolved, - VariableGroupRenameStarted, - VariableGroupRenameSubmitted, - VariableGroupRenameUpdated, - VariableGroupsOpenedPayload, -} from './types'; - -export const startVariableGroups = createAction(AT.START_VARIABLE_GROUPS); -export const variableGroupsOpened = createAction(AT.VARIABLE_GROUPS_OPENED); - -export const createNewVariableGroup = createAction(AT.CREATE_NEW_VARIABLE_GROUP); -export const insertNewVariableGroup = createAction(AT.INSERT_NEW_VARIABLE_GROUP); -export const insertNewGroup = createAction(AT.INSERT_NEW_GROUP); -export const insertNewItem = createAction(AT.INSERT_NEW_ITEM); - -export const updateGroupName = createAction(AT.UPDATE_GROUP_NAME); -export const updateItemName = createAction(AT.UPDATE_ITEM_NAME); -export const updateValue = createAction(AT.UPDATE_VALUE); - -export const removeVariableGroupFromStore = createAction(AT.REMOVE_VARIABLE_GROUP_FROM_STORE); -export const removeVariableGroupFromDisk = createAction(AT.REMOVE_VARIABLE_GROUP_FROM_DISK); - -export const removeGroup = createAction(AT.REMOVE_GROUP); -export const removeItem = createAction(AT.REMOVE_ITEM); - -export const renameStarted = createAction(AT.RENAME_STARTED); -export const renameUpdated = createAction(AT.RENAME_UPDATED); -export const renameCancelled = createAction(AT.RENAME_CANCELLED); -export const renameSubmitted = createAction(AT.RENAME_SUBMITTED); -export const renameResolved = createAction(AT.RENAME_RESOLVED); - -export const setLatestWrite = createAction(AT.SET_LATEST_WRITE); -export const setWriteDebounce = createAction(AT.SET_WRITE_DEBOUNCE); - -export default { - startVariableGroups, - variableGroupsOpened, - - createNewVariableGroup, - insertNewVariableGroup, - insertNewGroup, - insertNewItem, - - updateGroupName, - updateItemName, - updateValue, - - removeVariableGroupFromStore, - removeVariableGroupFromDisk, - - removeGroup, - removeItem, - - renameStarted, - renameUpdated, - renameCancelled, - renameSubmitted, - renameResolved, - - setLatestWrite, - setWriteDebounce, -}; diff --git a/packages/ui/src/store/variable-groups/sagas/create-variable-group.ts b/packages/ui/src/store/variable-groups/sagas/create-variable-group.ts deleted file mode 100644 index 2a6cbd2ee..000000000 --- a/packages/ui/src/store/variable-groups/sagas/create-variable-group.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { changeTab } from '@beak/ui/features/tabs/store/actions'; -import { createVariableGroup } from '@beak/ui/lib/beak-project/variable-groups'; -import { call, delay, put, race, take } from '@redux-saga/core/effects'; -import { PayloadAction } from '@reduxjs/toolkit'; - -import { renameStarted } from '../actions'; -import { ActionTypes, CreateNewVariableGroupPayload } from '../types'; - -export default function* workerCreateNewVariableGroup({ payload }: PayloadAction) { - const id: string = yield call(createVariableGroup, 'variable-groups', payload.name); - - yield put(changeTab({ type: 'variable_group_editor', payload: id, temporary: true })); - yield race([ - take(ActionTypes.INSERT_NEW_VARIABLE_GROUP), - delay(250), - ]); - yield put(renameStarted({ id })); -} diff --git a/packages/ui/src/store/variable-groups/types.ts b/packages/ui/src/store/variable-groups/types.ts deleted file mode 100644 index 08fb7db77..000000000 --- a/packages/ui/src/store/variable-groups/types.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { ValueParts } from '@beak/ui/features/realtime-values/values'; -import { ActiveRename } from '@beak/ui/features/tree-view/types'; -import type { VariableGroup, VariableGroups } from '@getbeak/types/variable-groups'; - -export const ActionTypes = { - START_VARIABLE_GROUPS: '@beak/global/variable-groups/START_VARIABLE_GROUPS', - VARIABLE_GROUPS_OPENED: '@beak/global/variable-groups/VARIABLE_GROUPS_OPENED', - - CREATE_NEW_VARIABLE_GROUP: '@beak/global/variable-groups/CREATE_NEW_VARIABLE_GROUP', - INSERT_NEW_VARIABLE_GROUP: '@beak/global/variable-groups/INSERT_NEW_VARIABLE_GROUP', - INSERT_NEW_GROUP: '@beak/global/variable-groups/INSERT_NEW_GROUP', - INSERT_NEW_ITEM: '@beak/global/variable-groups/INSERT_NEW_ITEM', - - UPDATE_GROUP_NAME: '@beak/global/variable-groups/UPDATE_GROUP_NAME', - UPDATE_ITEM_NAME: '@beak/global/variable-groups/UPDATE_ITEM_NAME', - UPDATE_VALUE: '@beak/global/variable-groups/UPDATE_VALUE', - - REMOVE_VARIABLE_GROUP_FROM_STORE: '@beak/global/variable-groups/REMOVE_VARIABLE_GROUP_FROM_STORE', - REMOVE_VARIABLE_GROUP_FROM_DISK: '@beak/global/variable-groups/REMOVE_VARIABLE_GROUP_FROM_DISK', - - REMOVE_GROUP: '@beak/global/variable-groups/REMOVE_GROUP', - REMOVE_ITEM: '@beak/global/variable-groups/REMOVE_ITEM', - - RENAME_STARTED: '@beak/global/variable-groups/RENAME_STARTED', - RENAME_UPDATED: '@beak/global/variable-groups/RENAME_UPDATED', - RENAME_CANCELLED: '@beak/global/variable-groups/RENAME_CANCELLED', - RENAME_SUBMITTED: '@beak/global/variable-groups/RENAME_SUBMITTED', - RENAME_RESOLVED: '@beak/global/variable-groups/RENAME_RESOLVED', - - SET_LATEST_WRITE: '@beak/global/variable-groups/SET_LATEST_WRITE', - SET_WRITE_DEBOUNCE: '@beak/global/variable-groups/SET_WRITE_DEBOUNCE', -}; - -export interface State { - loaded: boolean; - - variableGroups: VariableGroups; - - activeRename?: ActiveRename; - latestWrite?: number; - writeDebouncer: string; -} - -export const initialState: State = { - loaded: false, - - variableGroups: {}, - - latestWrite: 0, - writeDebouncer: '', -}; - -export interface VariableGroupId { id: string } - -export interface VariableGroupsOpenedPayload { variableGroups: VariableGroups } - -export interface CreateNewVariableGroupPayload { name?: string } -export interface InsertNewVariableGroupPayload { id: string; variableGroup: VariableGroup } -export interface InsertNewGroupPayload extends VariableGroupId { groupName: string } -export interface InsertNewItemPayload extends VariableGroupId { itemName: string } - -export interface UpdateGroupNamePayload extends VariableGroupId { - groupId: string; - updatedName: string; -} -export interface UpdateItemNamePayload extends VariableGroupId { - itemId: string; - updatedName: string; -} -export interface UpdateValuePayload extends VariableGroupId { - groupId: string; - itemId: string; - updated: ValueParts; -} - -export interface RemoveVariableGroupFromDiskPayload { - id: string; - withConfirmation: boolean; -} - -export interface RemoveGroupPayload extends VariableGroupId { groupId: string } -export interface RemoveItemPayload extends VariableGroupId { itemId: string } - -export interface VariableGroupRenameStarted extends VariableGroupId { } -export interface VariableGroupRenameCancelled extends VariableGroupId { } -export interface VariableGroupRenameSubmitted extends VariableGroupId { } -export interface VariableGroupRenameResolved extends VariableGroupId { } -export interface VariableGroupRenameUpdated extends VariableGroupId { name: string } - -export default { - ActionTypes, - initialState, -}; diff --git a/packages/ui/src/store/variable-sets/actions.ts b/packages/ui/src/store/variable-sets/actions.ts new file mode 100644 index 000000000..fc7dfe921 --- /dev/null +++ b/packages/ui/src/store/variable-sets/actions.ts @@ -0,0 +1,79 @@ +/* eslint-disable max-len */ + +import { createAction } from '@reduxjs/toolkit'; + +import { + ActionTypes as AT, + CreateNewVariableSetPayload, + InsertNewGroupPayload, + InsertNewItemPayload, + InsertNewVariableSetPayload, + RemoveGroupPayload, + RemoveItemPayload, + RemoveVariableSetFromDiskPayload, + UpdateGroupNamePayload, + UpdateItemNamePayload, + UpdateValuePayload, + VariableSetRenameCancelled, + VariableSetRenameResolved, + VariableSetRenameStarted, + VariableSetRenameSubmitted, + VariableSetRenameUpdated, + VariableSetsOpenedPayload, +} from './types'; + +export const startVariableSets = createAction(AT.START_VARIABLE_GROUPS); +export const variableSetsOpened = createAction(AT.VARIABLE_GROUPS_OPENED); + +export const createNewVariableSet = createAction(AT.CREATE_NEW_VARIABLE_GROUP); +export const insertNewVariableSet = createAction(AT.INSERT_NEW_VARIABLE_GROUP); +export const insertNewGroup = createAction(AT.INSERT_NEW_GROUP); +export const insertNewItem = createAction(AT.INSERT_NEW_ITEM); + +export const updateGroupName = createAction(AT.UPDATE_GROUP_NAME); +export const updateItemName = createAction(AT.UPDATE_ITEM_NAME); +export const updateValue = createAction(AT.UPDATE_VALUE); + +export const removeVariableSetFromStore = createAction(AT.REMOVE_VARIABLE_GROUP_FROM_STORE); +export const removeVariableSetFromDisk = createAction(AT.REMOVE_VARIABLE_GROUP_FROM_DISK); + +export const removeGroup = createAction(AT.REMOVE_GROUP); +export const removeItem = createAction(AT.REMOVE_ITEM); + +export const renameStarted = createAction(AT.RENAME_STARTED); +export const renameUpdated = createAction(AT.RENAME_UPDATED); +export const renameCancelled = createAction(AT.RENAME_CANCELLED); +export const renameSubmitted = createAction(AT.RENAME_SUBMITTED); +export const renameResolved = createAction(AT.RENAME_RESOLVED); + +export const setLatestWrite = createAction(AT.SET_LATEST_WRITE); +export const setWriteDebounce = createAction(AT.SET_WRITE_DEBOUNCE); + +export default { + startVariableSets, + variableSetsOpened, + + createNewVariableSet, + insertNewVariableSet, + insertNewGroup, + insertNewItem, + + updateGroupName, + updateItemName, + updateValue, + + removeVariableSetFromStore, + removeVariableSetFromDisk, + + removeGroup, + removeItem, + + renameStarted, + renameUpdated, + renameCancelled, + renameSubmitted, + renameResolved, + + setLatestWrite, + setWriteDebounce, +}; diff --git a/packages/ui/src/store/variable-groups/index.ts b/packages/ui/src/store/variable-sets/index.ts similarity index 100% rename from packages/ui/src/store/variable-groups/index.ts rename to packages/ui/src/store/variable-sets/index.ts diff --git a/packages/ui/src/store/variable-groups/reducers.ts b/packages/ui/src/store/variable-sets/reducers.ts similarity index 51% rename from packages/ui/src/store/variable-groups/reducers.ts rename to packages/ui/src/store/variable-sets/reducers.ts index 7babd31e6..ae1df39f7 100644 --- a/packages/ui/src/store/variable-groups/reducers.ts +++ b/packages/ui/src/store/variable-sets/reducers.ts @@ -1,76 +1,76 @@ import { TypedObject } from '@beak/common/helpers/typescript'; import ksuid from '@beak/ksuid'; -import { generateValueIdent } from '@beak/ui/lib/beak-variable-group/utils'; +import { generateValueIdent } from '@beak/ui/lib/beak-variable-set/utils'; import { createReducer } from '@reduxjs/toolkit'; import * as actions from './actions'; import { initialState } from './types'; -const variableGroupsReducer = createReducer(initialState, builder => { +const variableSetsReducer = createReducer(initialState, builder => { builder - .addCase(actions.startVariableGroups, state => { + .addCase(actions.startVariableSets, state => { state.loaded = false; }) - .addCase(actions.variableGroupsOpened, (state, { payload }) => { - state.variableGroups = payload.variableGroups; + .addCase(actions.variableSetsOpened, (state, { payload }) => { + state.variableSets = payload.variableSets; state.loaded = true; }) - .addCase(actions.insertNewVariableGroup, (state, { payload }) => { - state.variableGroups[payload.id] = payload.variableGroup; + .addCase(actions.insertNewVariableSet, (state, { payload }) => { + state.variableSets[payload.id] = payload.variableSet; }) .addCase(actions.insertNewGroup, (state, { payload }) => { - state.variableGroups![payload.id].groups[ksuid.generate('group').toString()] = payload.groupName; + state.variableSets![payload.id].sets[ksuid.generate('set').toString()] = payload.setName; }) .addCase(actions.insertNewItem, (state, { payload }) => { - state.variableGroups![payload.id].items[ksuid.generate('item').toString()] = payload.itemName; + state.variableSets![payload.id].items[ksuid.generate('item').toString()] = payload.itemName; }) .addCase(actions.updateGroupName, (state, { payload }) => { - state.variableGroups![payload.id].groups[payload.groupId] = payload.updatedName; + state.variableSets![payload.id].sets[payload.setId] = payload.updatedName; }) .addCase(actions.updateItemName, (state, { payload }) => { - state.variableGroups![payload.id].items[payload.itemId] = payload.updatedName; + state.variableSets![payload.id].items[payload.itemId] = payload.updatedName; }) .addCase(actions.updateValue, (state, { payload }) => { - const { id, groupId, itemId, updated } = payload; - const valueIdentifier = generateValueIdent(groupId, itemId); - const variableGroup = state.variableGroups[id]; - const exists = variableGroup.values[valueIdentifier]; + const { id, setId: setId, itemId, updated } = payload; + const valueIdentifier = generateValueIdent(setId, itemId); + const variableSet = state.variableSets[id]; + const exists = variableSet.values[valueIdentifier]; const empty = updated.length === 0 || (updated.length === 1 && updated[0] === ''); if (exists) { if (empty) { - delete variableGroup.values[valueIdentifier]; + delete variableSet.values[valueIdentifier]; return; } - variableGroup.values[valueIdentifier] = updated; + variableSet.values[valueIdentifier] = updated; } else { - variableGroup.values[valueIdentifier] = updated; + variableSet.values[valueIdentifier] = updated; } }) - .addCase(actions.removeVariableGroupFromStore, (state, { payload }) => { - delete state.variableGroups[payload]; + .addCase(actions.removeVariableSetFromStore, (state, { payload }) => { + delete state.variableSets[payload]; }) .addCase(actions.removeGroup, (state, { payload }) => { - delete state.variableGroups[payload.id].groups[payload.groupId]; + delete state.variableSets[payload.id].sets[payload.setId]; TypedObject - .keys(state.variableGroups[payload.id].values) - .filter(k => k.startsWith(`${payload.groupId}&`)) - .forEach(k => delete state.variableGroups[payload.id].values[k]); + .keys(state.variableSets[payload.id].values) + .filter(k => k.startsWith(`${payload.setId}&`)) + .forEach(k => delete state.variableSets[payload.id].values[k]); }) .addCase(actions.removeItem, (state, { payload }) => { - delete state.variableGroups[payload.id].items[payload.itemId]; + delete state.variableSets[payload.id].items[payload.itemId]; TypedObject - .keys(state.variableGroups[payload.id].values) + .keys(state.variableSets[payload.id].values) .filter(k => k.endsWith(`&${payload.itemId}`)) - .forEach(k => delete state.variableGroups[payload.id].values[k]); + .forEach(k => delete state.variableSets[payload.id].values[k]); }) .addCase(actions.renameStarted, (state, action) => { @@ -106,4 +106,4 @@ const variableGroupsReducer = createReducer(initialState, builder => { }); }); -export default variableGroupsReducer; +export default variableSetsReducer; diff --git a/packages/ui/src/store/variable-groups/sagas/catch-updates.ts b/packages/ui/src/store/variable-sets/sagas/catch-updates.ts similarity index 59% rename from packages/ui/src/store/variable-groups/sagas/catch-updates.ts rename to packages/ui/src/store/variable-sets/sagas/catch-updates.ts index 7ebd4925e..ccec638f1 100644 --- a/packages/ui/src/store/variable-groups/sagas/catch-updates.ts +++ b/packages/ui/src/store/variable-sets/sagas/catch-updates.ts @@ -1,21 +1,21 @@ -import { writeVariableGroup } from '@beak/ui/lib/beak-variable-group'; -import type { VariableGroup } from '@getbeak/types/variable-groups'; +import { writeVariableSet } from '@beak/ui/lib/beak-variable-set'; +import type { VariableSet } from '@getbeak/types/variable-sets'; import { call, delay, put, select } from '@redux-saga/core/effects'; import { PayloadAction } from '@reduxjs/toolkit'; import * as uuid from 'uuid'; import { ApplicationState } from '../..'; import { actions } from '..'; -import { VariableGroupId } from '../types'; +import { VariableSetId } from '../types'; -export default function* workerCatchUpdates({ payload }: PayloadAction) { +export default function* workerCatchUpdates({ payload }: PayloadAction) { const { id } = payload; - const variableGroup: VariableGroup = yield select( - (s: ApplicationState) => s.global.variableGroups.variableGroups[id], + const variableSet: VariableSet = yield select( + (s: ApplicationState) => s.global.variableSets.variableSets[id], ); - if (!variableGroup) + if (!variableSet) return; const nonce = uuid.v4(); @@ -23,12 +23,12 @@ export default function* workerCatchUpdates({ payload }: PayloadAction s.global.variableGroups.writeDebouncer); + const debounce: string = yield select((s: ApplicationState) => s.global.variableSets.writeDebouncer); // This prevents us writing the file too often while data is changing if (debounce !== nonce) return; yield put(actions.setLatestWrite(Date.now())); - yield call(writeVariableGroup, id, variableGroup); + yield call(writeVariableSet, id, variableSet); } diff --git a/packages/ui/src/store/variable-sets/sagas/create-variable-set.ts b/packages/ui/src/store/variable-sets/sagas/create-variable-set.ts new file mode 100644 index 000000000..bd92487c7 --- /dev/null +++ b/packages/ui/src/store/variable-sets/sagas/create-variable-set.ts @@ -0,0 +1,18 @@ +import { changeTab } from '@beak/ui/features/tabs/store/actions'; +import { createVariableSet } from '@beak/ui/lib/beak-project/variable-sets'; +import { call, delay, put, race, take } from '@redux-saga/core/effects'; +import { PayloadAction } from '@reduxjs/toolkit'; + +import { renameStarted } from '../actions'; +import { ActionTypes, CreateNewVariableSetPayload } from '../types'; + +export default function* workerCreateNewVariableSet({ payload }: PayloadAction) { + const id: string = yield call(createVariableSet, 'variable-sets', payload.name); + + yield put(changeTab({ type: 'variable_set_editor', payload: id, temporary: true })); + yield race([ + take(ActionTypes.INSERT_NEW_VARIABLE_GROUP), + delay(250), + ]); + yield put(renameStarted({ id })); +} diff --git a/packages/ui/src/store/variable-groups/sagas/index.ts b/packages/ui/src/store/variable-sets/sagas/index.ts similarity index 55% rename from packages/ui/src/store/variable-groups/sagas/index.ts rename to packages/ui/src/store/variable-sets/sagas/index.ts index 68d68c47e..81cde50eb 100644 --- a/packages/ui/src/store/variable-groups/sagas/index.ts +++ b/packages/ui/src/store/variable-sets/sagas/index.ts @@ -2,10 +2,10 @@ import { all, fork, takeEvery, takeLatest } from '@redux-saga/core/effects'; import { ActionTypes } from '../types'; import catchUpdates from './catch-updates'; -import createNewVariableGroup from './create-variable-group'; -import removeVariableGroupFromDisk from './remove-node-from-disk'; -import startVariableGroups from './start-variable-groups'; -import variableGroupRename from './variable-group-rename'; +import createNewVariableSet from './create-variable-set'; +import removeVariableSetFromDisk from './remove-node-from-disk'; +import startVariableSets from './start-variable-sets'; +import variableSetRename from './variable-set-rename'; const updateWatcherActions = [ ActionTypes.INSERT_NEW_VARIABLE_GROUP, @@ -18,22 +18,22 @@ const updateWatcherActions = [ ActionTypes.REMOVE_ITEM, ]; -export default function* variableGroupsSaga() { +export default function* variableSetsSaga() { yield all([ - fork(function* startVariableGroupsWatcher() { - yield takeEvery(ActionTypes.START_VARIABLE_GROUPS, startVariableGroups); + fork(function* startVariableSetsWatcher() { + yield takeEvery(ActionTypes.START_VARIABLE_GROUPS, startVariableSets); }), fork(function* catchNodeUpdatesWatcher() { yield takeEvery(updateWatcherActions, catchUpdates); }), - fork(function* createVariableGroupWatcher() { - yield takeEvery(ActionTypes.CREATE_NEW_VARIABLE_GROUP, createNewVariableGroup); + fork(function* createVariableSetWatcher() { + yield takeEvery(ActionTypes.CREATE_NEW_VARIABLE_GROUP, createNewVariableSet); }), - fork(function* variableGroupRenameWatcher() { - yield takeLatest(ActionTypes.RENAME_SUBMITTED, variableGroupRename); + fork(function* variableSetRenameWatcher() { + yield takeLatest(ActionTypes.RENAME_SUBMITTED, variableSetRename); }), - fork(function* removeVariableGroupFromDiskWatcher() { - yield takeEvery(ActionTypes.REMOVE_VARIABLE_GROUP_FROM_DISK, removeVariableGroupFromDisk); + fork(function* removeVariableSetFromDiskWatcher() { + yield takeEvery(ActionTypes.REMOVE_VARIABLE_GROUP_FROM_DISK, removeVariableSetFromDisk); }), ]); } diff --git a/packages/ui/src/store/variable-groups/sagas/remove-node-from-disk.ts b/packages/ui/src/store/variable-sets/sagas/remove-node-from-disk.ts similarity index 66% rename from packages/ui/src/store/variable-groups/sagas/remove-node-from-disk.ts rename to packages/ui/src/store/variable-sets/sagas/remove-node-from-disk.ts index 625bc911e..da404fae7 100644 --- a/packages/ui/src/store/variable-groups/sagas/remove-node-from-disk.ts +++ b/packages/ui/src/store/variable-sets/sagas/remove-node-from-disk.ts @@ -1,21 +1,19 @@ -/* eslint-disable max-len */ - import { ShowMessageBoxRes } from '@beak/common/ipc/dialog'; import { attemptReconciliation } from '@beak/ui/features/tabs/store/actions'; -import { removeVariableGroup } from '@beak/ui/lib/beak-variable-group'; +import { removeVariableSet } from '@beak/ui/lib/beak-variable-set'; import { ipcDialogService } from '@beak/ui/lib/ipc'; import { call, put } from '@redux-saga/core/effects'; import { PayloadAction } from '@reduxjs/toolkit'; import actions from '../actions'; -import { RemoveVariableGroupFromDiskPayload } from '../types'; +import { RemoveVariableSetFromDiskPayload } from '../types'; -export default function* workerRemoveVariableGroupFromDisk({ payload }: PayloadAction) { +export default function* workerRemoveVariableSetFromDisk({ payload }: PayloadAction) { const { id, withConfirmation } = payload; if (withConfirmation) { const response: ShowMessageBoxRes = yield call([ipcDialogService, ipcDialogService.showMessageBox], { - title: 'Deleting variable group', + title: 'Deleting variable set', message: `You are about to delete '${id}' from your machine. Are you sure you want to continue?`, detail: 'This action is irreversible inside Beak!', type: 'warning', @@ -27,7 +25,7 @@ export default function* workerRemoveVariableGroupFromDisk({ payload }: PayloadA return; } - yield call(removeVariableGroup, id); - yield put(actions.removeVariableGroupFromStore(id)); + yield call(removeVariableSet, id); + yield put(actions.removeVariableSetFromStore(id)); yield put(attemptReconciliation()); } diff --git a/packages/ui/src/store/variable-groups/sagas/start-variable-groups.ts b/packages/ui/src/store/variable-sets/sagas/start-variable-sets.ts similarity index 62% rename from packages/ui/src/store/variable-groups/sagas/start-variable-groups.ts rename to packages/ui/src/store/variable-sets/sagas/start-variable-sets.ts index e330b5a0b..d2faf5341 100644 --- a/packages/ui/src/store/variable-groups/sagas/start-variable-groups.ts +++ b/packages/ui/src/store/variable-sets/sagas/start-variable-sets.ts @@ -1,15 +1,15 @@ import { TypedObject } from '@beak/common/helpers/typescript'; import { EditorPreferences } from '@beak/common/types/beak-hub'; import { attemptReconciliation } from '@beak/ui/features/tabs/store/actions'; -import { readVariableGroup } from '@beak/ui/lib/beak-variable-group'; +import { readVariableSet } from '@beak/ui/lib/beak-variable-set'; import createFsEmitter, { scanDirectoryRecursively, ScanResult } from '@beak/ui/lib/fs-emitter'; import { ipcDialogService, ipcFsService } from '@beak/ui/lib/ipc'; -import type { VariableGroups } from '@getbeak/types/variable-groups'; +import type { VariableSets } from '@getbeak/types/variable-sets'; import { call, put, select, take } from '@redux-saga/core/effects'; import path from 'path-browserify'; import { ApplicationState } from '../..'; -import { editorPreferencesSetSelectedVariableGroup } from '../../preferences/actions'; +import { editorPreferencesSetSelectedVariableSet } from '../../preferences/actions'; import * as actions from '../actions'; interface Emitter { @@ -17,10 +17,10 @@ interface Emitter { path: string; } -export default function* workerStartVariableGroups() { - const channel = createFsEmitter('variable-groups', { depth: 0, followSymlinks: false }); +export default function* workerStartVariableSets() { + const channel = createFsEmitter('variable-sets', { depth: 0, followSymlinks: false }); - yield initialImport('variable-groups'); + yield initialImport('variable-sets'); while (true) { const result: Emitter = yield take(channel); @@ -38,7 +38,7 @@ export default function* workerStartVariableGroups() { // Protection to only read changes if they haven't been recently written by Beak if (result.type === 'change') { - const lastWrite: number = yield select((s: ApplicationState) => s.global.variableGroups.latestWrite); + const lastWrite: number = yield select((s: ApplicationState) => s.global.variableSets.latestWrite); if (lastWrite) { const now = Date.now(); @@ -51,9 +51,9 @@ export default function* workerStartVariableGroups() { if (['add', 'change'].includes(result.type)) { try { - const { file, name } = yield call(readVariableGroup, result.path); + const { file, name } = yield call(readVariableSet, result.path); - yield put(actions.insertNewVariableGroup({ id: name, variableGroup: file })); + yield put(actions.insertNewVariableSet({ id: name, variableSet: file })); } catch (error) { if (!(error instanceof Error)) return; @@ -61,7 +61,7 @@ export default function* workerStartVariableGroups() { yield call([ipcDialogService, ipcDialogService.showMessageBox], { type: 'error', title: 'Project data error', - message: 'There was a problem reading a variable group file in your project', + message: 'There was a problem reading a variable set file in your project', detail: [ error.message, error.stack, @@ -70,9 +70,9 @@ export default function* workerStartVariableGroups() { } } else if (result.type === 'unlink') { try { - const variableGroupName = path.basename(result.path, path.extname(result.path)); + const variableSetName = path.basename(result.path, path.extname(result.path)); - yield put(actions.removeVariableGroupFromStore(variableGroupName)); + yield put(actions.removeVariableSetFromStore(variableSetName)); yield put(attemptReconciliation()); } catch (error) { if (!(error instanceof Error)) @@ -81,7 +81,7 @@ export default function* workerStartVariableGroups() { yield call([ipcDialogService, ipcDialogService.showMessageBox], { type: 'error', title: 'Project data error', - message: 'There was a problem deleting a variable group from your project', + message: 'There was a problem deleting a variable set from your project', detail: [ error.message, error.stack, @@ -93,35 +93,35 @@ export default function* workerStartVariableGroups() { } function* initialImport(vgPath: string) { - const folderExists: boolean = yield call([ipcFsService, ipcFsService.pathExists], 'variable-groups'); + const folderExists: boolean = yield call([ipcFsService, ipcFsService.pathExists], 'variable-sets'); if (!folderExists) { - yield put(actions.variableGroupsOpened({ variableGroups: {} })); + yield put(actions.variableSetsOpened({ variableSets: {} })); return; } const items: ScanResult[] = yield scanDirectoryRecursively(vgPath); const files = items.filter(i => !i.isDirectory).map(i => i.path); - const variableGroups: VariableGroups = yield call(readVariableGroups, files); + const variableSets: VariableSets = yield call(readVariableSets, files); const editorPreferences: EditorPreferences = yield select((s: ApplicationState) => s.global.preferences.editor); - for (const vgk of TypedObject.keys(variableGroups)) { - const vg = variableGroups[vgk]; + for (const vgk of TypedObject.keys(variableSets)) { + const vg = variableSets[vgk]; - if (editorPreferences.selectedVariableGroups[vgk] === void 0) { - yield put(editorPreferencesSetSelectedVariableGroup({ - variableGroup: vgk, - groupId: TypedObject.keys(vg.groups)[0], + if (editorPreferences.selectedVariableSets[vgk] === void 0) { + yield put(editorPreferencesSetSelectedVariableSet({ + variableSet: vgk, + setId: TypedObject.keys(vg.sets)[0], })); } } - yield put(actions.variableGroupsOpened({ variableGroups })); + yield put(actions.variableSetsOpened({ variableSets })); } -async function readVariableGroups(filePaths: string[]) { - const results = await Promise.all(filePaths.map(f => readVariableGroup(f))); +async function readVariableSets(filePaths: string[]) { + const results = await Promise.all(filePaths.map(f => readVariableSet(f))); return results.reduce((acc, { name, file }) => ({ ...acc, diff --git a/packages/ui/src/store/variable-groups/sagas/variable-group-rename.ts b/packages/ui/src/store/variable-sets/sagas/variable-set-rename.ts similarity index 70% rename from packages/ui/src/store/variable-groups/sagas/variable-group-rename.ts rename to packages/ui/src/store/variable-sets/sagas/variable-set-rename.ts index c2b7b2c65..f8e827939 100644 --- a/packages/ui/src/store/variable-groups/sagas/variable-group-rename.ts +++ b/packages/ui/src/store/variable-sets/sagas/variable-set-rename.ts @@ -1,16 +1,16 @@ import { changeTab } from '@beak/ui/features/tabs/store/actions'; import { ActiveRename } from '@beak/ui/features/tree-view/types'; -import { renameVariableGroup } from '@beak/ui/lib/beak-project/variable-groups'; +import { renameVariableSet } from '@beak/ui/lib/beak-project/variable-sets'; import { ipcDialogService } from '@beak/ui/lib/ipc'; import { call, delay, put, select } from '@redux-saga/core/effects'; import { PayloadAction } from '@reduxjs/toolkit'; import { ApplicationState } from '../..'; import actions from '../actions'; -import { VariableGroupRenameSubmitted } from '../types'; +import { VariableSetRenameSubmitted } from '../types'; -export default function* workerRequestRename({ payload }: PayloadAction) { - const activeRename: ActiveRename = yield select((s: ApplicationState) => s.global.variableGroups.activeRename); +export default function* workerRequestRename({ payload }: PayloadAction) { + const activeRename: ActiveRename = yield select((s: ApplicationState) => s.global.variableSets.activeRename); const { id } = payload; if (!activeRename || activeRename.id !== id) @@ -23,15 +23,15 @@ export default function* workerRequestRename({ payload }: PayloadAction, ) { - const value = await parseValueParts(context, info.url); + const value = await parseValueSections(context, info.url); const url = new URL(value, true); const options = { includeQuery: true, @@ -34,7 +34,7 @@ export async function convertRequestToUrl( for (const query of TypedObject.values(info.query).filter(q => q.enabled)) { // eslint-disable-next-line no-await-in-loop - outQuery[query.name] = await parseValueParts(context, query.value); + outQuery[query.name] = await parseValueSections(context, query.value); } url.set('query', outQuery); diff --git a/tsconfig.json b/tsconfig.json index 429f80200..8a6de3626 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -62,8 +62,8 @@ "@getbeak/types": ["packages/types/src"], "@getbeak/types/*": ["packages/types/src/*"], - "@getbeak/types-realtime-value": ["packages/types-realtime-value/src"], - "@getbeak/types-realtime-value/*": ["packages/types-realtime-value/src/*"] + "@getbeak/types-variables": ["packages/types-variables/src"], + "@getbeak/types-variables/*": ["packages/types-variables/src/*"] } }, "exclude": [ diff --git a/yarn.lock b/yarn.lock index 3a86e868d..29a599883 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1941,101 +1941,51 @@ tslib "^2.3.0" yargs-parser "21.1.1" -"@nx/nx-darwin-arm64@20.1.1": - version "20.1.1" - resolved "https://registry.yarnpkg.com/@nx/nx-darwin-arm64/-/nx-darwin-arm64-20.1.1.tgz#6a18f97b03f5dd9057a3864ade0e069b18c34ca4" - integrity sha512-Ah0ShPQaMfvzVfhsyuI6hNB0bmwLHJqqrWldZeF97SFPhv6vfKdcdlZmSnask+V4N5z9TOCUmCMu2asMQa7+kw== - "@nx/nx-darwin-arm64@20.1.2": version "20.1.2" resolved "https://registry.yarnpkg.com/@nx/nx-darwin-arm64/-/nx-darwin-arm64-20.1.2.tgz#880dc02d2256c3f6ec98e9ab51e7c88ceedf3610" integrity sha512-PJ91TQhd28kitDBubKUOXMYvrtSDrG+rr8MsIe9cHo1CvU9smcGVBwuHBxniq0DXsyOX/5GL6ngq7hjN2nQ3XQ== -"@nx/nx-darwin-x64@20.1.1": - version "20.1.1" - resolved "https://registry.yarnpkg.com/@nx/nx-darwin-x64/-/nx-darwin-x64-20.1.1.tgz#676cdb657db8560057d1e8d9da2842d20d7f117a" - integrity sha512-TmdX6pbzclvPGsttTTaZhdF46HV1vfvYSHJaSMsYJX68l3gcQnAJ1ZRDksEgkYeAy+O9KrPimD84NM5W/JvqcQ== - "@nx/nx-darwin-x64@20.1.2": version "20.1.2" resolved "https://registry.yarnpkg.com/@nx/nx-darwin-x64/-/nx-darwin-x64-20.1.2.tgz#e9dc306affcb18a9900efbdbcadd514ecd5fbda5" integrity sha512-1fopau7nxIhTF26vDTIzMxl15AtW4FvUSdy+r1mNRKrKyjjpqnlu00SQBW7JzGV0agDD1B/61yYei5Q2aMOt7Q== -"@nx/nx-freebsd-x64@20.1.1": - version "20.1.1" - resolved "https://registry.yarnpkg.com/@nx/nx-freebsd-x64/-/nx-freebsd-x64-20.1.1.tgz#2dfd02d1432f4279a09aecf5281b194f580e6066" - integrity sha512-7/7f3GbUbdvtTFOb/8wcaSQYkhVIxcC4UzFJM5yEyXPJmIrglk+RX3SLuOFRBFJnO+Z7D6jLUnLOBHKCGfqLVw== - "@nx/nx-freebsd-x64@20.1.2": version "20.1.2" resolved "https://registry.yarnpkg.com/@nx/nx-freebsd-x64/-/nx-freebsd-x64-20.1.2.tgz#ca967f9da06f93e0039b92c0c072d0c9a93b7776" integrity sha512-55YgIp3v4zz7xMzJO93dtglbOTER2XdS6jrCt8GbKaWGFl5drRrBoNGONtiGNU7C3hLx1VsorbynCkJT18PjKQ== -"@nx/nx-linux-arm-gnueabihf@20.1.1": - version "20.1.1" - resolved "https://registry.yarnpkg.com/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-20.1.1.tgz#5a9f5ef294e9f0c7db3b7e94b2da33ef33dccb16" - integrity sha512-VxpMz5jCZ5gnk1gP2jDBCheYs7qOwQoJmzGbEB8hNy0CwRH/G8pL4RRo4Sz+4aiF6Z+9eax5RM2/Syh+bS0uJw== - "@nx/nx-linux-arm-gnueabihf@20.1.2": version "20.1.2" resolved "https://registry.yarnpkg.com/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-20.1.2.tgz#c9bad02ecbf0c47e1cf1e49bc348e962665074bd" integrity sha512-sMhNA8uAV43UYVEXEa8TZ8Fjpom4CGq1umTptEGOF4TTtdNn2AUBreg+0bVODM8MMSzRWGI1VbkZzHESnAPwqw== -"@nx/nx-linux-arm64-gnu@20.1.1": - version "20.1.1" - resolved "https://registry.yarnpkg.com/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-20.1.1.tgz#dbaad0e10afb1201b2f44f51860190d770c667f0" - integrity sha512-8T2+j4KvsWb6ljW1Y2s/uCSt4Drtlsr3GSrGdvcETW0IKaTfKZAJlxTLAWQHEF88hP6GAJRGxNrgmUHMr8HwUA== - "@nx/nx-linux-arm64-gnu@20.1.2": version "20.1.2" resolved "https://registry.yarnpkg.com/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-20.1.2.tgz#713e83f11a20bb1dc3832faf9b08c938b2cf4c31" integrity sha512-bsevarNHglaYLmIvPNQOdHrBnBgaW3EOUM0flwaXdWuZbL1bWx8GoVwHp9yJpZOAOfIF/Nhq5iTpaZB2nYFrAA== -"@nx/nx-linux-arm64-musl@20.1.1": - version "20.1.1" - resolved "https://registry.yarnpkg.com/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-20.1.1.tgz#df883505388069ddf91226db39c51c594c10a1d6" - integrity sha512-TI964w+HFUqG6elriKwQPRX7QRxVRMz5YKdNPgf4+ab4epQ379kwJQEHlyOHR72ir8Tl46z3BoPjvmaLylrT4Q== - "@nx/nx-linux-arm64-musl@20.1.2": version "20.1.2" resolved "https://registry.yarnpkg.com/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-20.1.2.tgz#5091e70d20603b7cd70b0bd6022b07c0a9779d79" integrity sha512-GFZTptkhZPL/iZ3tYDmspIcPEaXyy/L/o59gyp33GoFAAyDhiXIF7J1Lz81Xn8VKrX6TvEY8/9qSh86pb7qzDQ== -"@nx/nx-linux-x64-gnu@20.1.1": - version "20.1.1" - resolved "https://registry.yarnpkg.com/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-20.1.1.tgz#97bee1fffca92218104da87a8112b3554834fa41" - integrity sha512-Sg2tQ0v3KP9cAqQST16YR+dT/NbirPts6by+A4vhOtaBrZFVqm9P89K9UdcJf4Aj1CaGbs84lotp2aM4E4bQPA== - "@nx/nx-linux-x64-gnu@20.1.2": version "20.1.2" resolved "https://registry.yarnpkg.com/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-20.1.2.tgz#8c0089fd7e797950bbe6e6898c0762bbfa55716d" integrity sha512-yqEW/iglKT4d9lgfnwSNhmDzPxCkRhtdmZqOYpGDM0eZFwYwJF+WRGjW8xIqMj8PA1yrGItzXZOmyFjJqHAF2w== -"@nx/nx-linux-x64-musl@20.1.1": - version "20.1.1" - resolved "https://registry.yarnpkg.com/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-20.1.1.tgz#f4337d21bf3c913255842d1f704ba8e725b10fec" - integrity sha512-ekKvuIMRJRhZnkWIWEr4TRVEAyKVDgEMwqk83ilB0Mqpj2RoOKbw7jZFvWcxJWI4kSeZjTea3xCWGNPa1GfCww== - "@nx/nx-linux-x64-musl@20.1.2": version "20.1.2" resolved "https://registry.yarnpkg.com/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-20.1.2.tgz#121d6c276b97017f62168c0a018e709ef679ca01" integrity sha512-SP6PpWT4cQVrC4WJQdpfADrYJQzkbhgmcGleWbpr7II1HJgOsAcvoDwQGpPQX+3Wo+VBiNecvUAOzacMQkXPGw== -"@nx/nx-win32-arm64-msvc@20.1.1": - version "20.1.1" - resolved "https://registry.yarnpkg.com/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-20.1.1.tgz#f48cbefb3abe08762e5ecaefce9aab787a5350b4" - integrity sha512-JRycFkk6U8A1sXaDmSFA2HMKT2js3HK/+nI+auyITRqVbV79/r6ir/oFSgIjKth8j/vVbGDL8I4E3nEQ7leZYw== - "@nx/nx-win32-arm64-msvc@20.1.2": version "20.1.2" resolved "https://registry.yarnpkg.com/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-20.1.2.tgz#37a57b4c21e23bb377a5ddffa034939f2e465211" integrity sha512-JZQx9gr39LY3D7uleiXlpxUsavuOrOQNBocwKHkAMnykaT/e1VCxTnm/hk+2b4foWwfURTqoRiFEba70iiCdYg== -"@nx/nx-win32-x64-msvc@20.1.1": - version "20.1.1" - resolved "https://registry.yarnpkg.com/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-20.1.1.tgz#17e0277f4a31a044f2bcee90d605e9d77c8d6fcc" - integrity sha512-VwxmJU7o8KqTZ+KYk7atoWOUykKd8D4hdgKqqltdq/UBfsAWD/JCFt5OB/VFvrGDbK6I6iKpMvXWlHy4gkXQiw== - "@nx/nx-win32-x64-msvc@20.1.2": version "20.1.2" resolved "https://registry.yarnpkg.com/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-20.1.2.tgz#8b24ea16d06e5ebf97b9b9438bae5e3c2f57a0d3"