From 086d0d98ef0262d435e1ae1254d9ea5720dd0f93 Mon Sep 17 00:00:00 2001 From: srikary12 <121927567+srikary12@users.noreply.github.com> Date: Wed, 26 Nov 2025 12:17:52 +0530 Subject: [PATCH 1/3] feature/autoSave (#582) --- .../components/RequestPane/QueryUrl/index.js | 7 +++-- .../src/components/SingleLineEditor/index.js | 24 ++++++++++++++++ .../ReduxStore/slices/collections/actions.js | 28 +++++++++++-------- 3 files changed, 45 insertions(+), 14 deletions(-) diff --git a/packages/bruno-app/src/components/RequestPane/QueryUrl/index.js b/packages/bruno-app/src/components/RequestPane/QueryUrl/index.js index a1d7dd86a..69963f45f 100644 --- a/packages/bruno-app/src/components/RequestPane/QueryUrl/index.js +++ b/packages/bruno-app/src/components/RequestPane/QueryUrl/index.js @@ -10,12 +10,14 @@ import SingleLineEditor from 'components/SingleLineEditor'; import { isMacOS } from 'utils/common/platform'; import { hasRequestChanges } from 'utils/collections'; import StyledWrapper from './StyledWrapper'; +import { usePreferences } from 'providers/Preferences/index'; import GenerateCodeItem from 'components/Sidebar/Collections/Collection/CollectionItem/GenerateCodeItem/index'; import toast from 'react-hot-toast'; const QueryUrl = ({ item, collection, handleRun }) => { const { theme, storedTheme } = useTheme(); const dispatch = useDispatch(); + const autoSavePreference = usePreferences().preferences.request.autoSave; const method = item.draft ? get(item, 'draft.request.method') : get(item, 'request.method'); const url = item.draft ? get(item, 'draft.request.url', '') : get(item, 'request.url', ''); const isMac = isMacOS(); @@ -33,8 +35,8 @@ const QueryUrl = ({ item, collection, handleRun }) => { setMethodSelectorWidth(el.offsetWidth); }, [method]); - const onSave = (finalValue) => { - dispatch(saveRequest(item.uid, collection.uid)); + const onSave = (notify = 1) => { + dispatch(saveRequest(item.uid, collection.uid, notify)); }; const onUrlChange = (value) => { @@ -118,6 +120,7 @@ const QueryUrl = ({ item, collection, handleRun }) => { highlightPathParams={true} item={item} showNewlineArrow={true} + autoSave={autoSavePreference} />
{ + if (this.props.autoSave && this.props.onSave) { + this.autoSaveInterval = setInterval(this.saveEditorContent, this.props.autoSaveInterval || 15000); // Default to 15 sec + } + }; + + clearAutosave = () => { + if (this.autoSaveInterval) { + clearInterval(this.autoSaveInterval); + } + }; + + saveEditorContent = () => { + if (this.props.onSave) { + const content = this.editor.getValue(); + console.log(content); + this.props.onSave(content, 0); + } + }; + _onPaste = (_, event) => this.props.onPaste?.(event); componentDidUpdate(prevProps) { @@ -190,6 +213,7 @@ class SingleLineEditor extends Component { } componentWillUnmount() { + this.clearAutosave(); if (this.editor) { if (this.editor?._destroyLinkAware) { this.editor._destroyLinkAware(); diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js b/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js index 27a068d05..0639e046e 100644 --- a/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js +++ b/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js @@ -94,28 +94,32 @@ export const renameCollection = (newName, collectionUid) => (dispatch, getState) }); }; -export const saveRequest = (itemUid, collectionUid, saveSilently) => (dispatch, getState) => { + +export const saveRequest = (itemUid, collectionUid, saveSilently, notify = 1) => (dispatch, getState) => { const state = getState(); const collection = findCollectionByUid(state.collections.collections, collectionUid); - return new Promise((resolve, reject) => { - if (!collection) { - return reject(new Error('Collection not found')); - } + return new Promise((resolve, reject) => { + if (!collection) { + return reject(new Error('Collection not found')); + } - const collectionCopy = cloneDeep(collection); - const item = findItemInCollection(collectionCopy, itemUid); - if (!item) { - return reject(new Error('Not able to locate item')); - } + const collectionCopy = cloneDeep(collection); + const item = findItemInCollection(collectionCopy, itemUid); + if (!item) { + return reject(new Error('Not able to locate item')); + } - const itemToSave = transformRequestToSaveToFilesystem(item); - const { ipcRenderer } = window; + const itemToSave = transformRequestToSaveToFilesystem(item); + const { ipcRenderer } = window; itemSchema .validate(itemToSave) .then(() => ipcRenderer.invoke('renderer:save-request', item.pathname, itemToSave)) .then(() => { + if (notify === 1) { + toast.success('Request saved successfully'); + } if (!saveSilently) { toast.success('Request saved successfully'); } From 4ce5debc4c9484493f911aa1111528a11ace2a56 Mon Sep 17 00:00:00 2001 From: Pooja Date: Tue, 2 Dec 2025 13:46:06 +0530 Subject: [PATCH 2/3] feature/autoSave (#582) (#6225) --- .../actions/common/setup-node-deps/action.yml | 1 + .github/workflows/tests.yml | 3 + contributing.md | 1 + package-lock.json | 258 ++++---- package.json | 2 + .../CollectionSettings/Presets/index.js | 5 +- .../CollectionSettings/Vars/index.js | 4 + .../DeprecationWarning/StyledWrapper.js | 33 ++ .../components/DeprecationWarning/index.js | 16 + .../components/FolderSettings/Vars/index.js | 4 + .../Icons/IconAlertTriangleFilled/index.js | 14 + .../components/Preferences/General/index.js | 64 +- .../components/RequestPane/GrpcBody/index.js | 4 +- .../RequestPane/GrpcQueryUrl/index.js | 14 +- .../components/RequestPane/QueryUrl/index.js | 7 +- .../src/components/RequestPane/Vars/index.js | 3 + .../Sidebar/CreateCollection/StyledWrapper.js | 12 + .../Sidebar/CreateCollection/index.js | 340 +++++++---- .../components/Sidebar/NewRequest/index.js | 18 +- .../src/components/SingleLineEditor/index.js | 24 - .../src/providers/ReduxStore/index.js | 3 +- .../middlewares/autosave/middleware.js | 161 +++++ .../src/providers/ReduxStore/slices/app.js | 4 + .../ReduxStore/slices/collections/actions.js | 211 +++++-- .../ReduxStore/slices/collections/index.js | 9 + packages/bruno-app/src/themes/dark.js | 13 + packages/bruno-app/src/themes/light.js | 13 + .../bruno-app/src/utils/common/platform.js | 4 +- .../src/postman/postman-translations.js | 12 + .../src/utils/jscode-shift-translator.js | 9 +- .../postman-request.spec.js | 16 + .../transpiler-tests/request.test.js | 16 + .../src/app/collection-watcher.js | 292 +++++---- .../bruno-electron/src/app/collections.js | 26 +- packages/bruno-electron/src/ipc/collection.js | 456 ++++++++++----- .../bruno-electron/src/ipc/network/index.js | 16 +- .../bruno-electron/src/store/preferences.js | 8 + .../src/utils/collection-import.js | 32 +- .../bruno-electron/src/utils/collection.js | 62 ++ .../bruno-electron/src/utils/filesystem.js | 52 +- packages/bruno-filestore/package.json | 15 +- packages/bruno-filestore/rollup.config.js | 59 +- .../bruno-filestore/src/formats/bru/index.ts | 14 +- .../tests/oauth2-additional-params.spec.js | 2 +- .../src/formats/yml/common/assertions.ts | 146 +++++ .../src/formats/yml/common/auth-oauth2.ts | 553 ++++++++++++++++++ .../src/formats/yml/common/auth.ts | 245 ++++++++ .../src/formats/yml/common/body.ts | 234 ++++++++ .../src/formats/yml/common/headers.ts | 45 ++ .../src/formats/yml/common/params.ts | 57 ++ .../src/formats/yml/common/scripts.ts | 51 ++ .../src/formats/yml/common/variables.ts | 80 +++ .../bruno-filestore/src/formats/yml/index.ts | 20 + .../formats/yml/items/parseGraphQLRequest.ts | 128 ++++ .../src/formats/yml/items/parseGrpcRequest.ts | 112 ++++ .../src/formats/yml/items/parseHttpRequest.ts | 186 ++++++ .../src/formats/yml/items/parseScript.ts | 25 + .../yml/items/parseWebsocketRequest.ts | 87 +++ .../yml/items/stringifyGraphQLRequest.ts | 150 +++++ .../formats/yml/items/stringifyGrpcRequest.ts | 123 ++++ .../formats/yml/items/stringifyHttpRequest.ts | 201 +++++++ .../src/formats/yml/items/stringifyScript.ts | 22 + .../yml/items/stringifyWebsocketRequest.ts | 91 +++ .../src/formats/yml/parseCollection.ts | 177 ++++++ .../src/formats/yml/parseEnvironment.ts | 42 ++ .../src/formats/yml/parseFolder.ts | 82 +++ .../src/formats/yml/parseItem.ts | 46 ++ .../src/formats/yml/stringifyCollection.ts | 190 ++++++ .../src/formats/yml/stringifyEnvironment.ts | 57 ++ .../src/formats/yml/stringifyFolder.ts | 92 +++ .../src/formats/yml/stringifyItem.ts | 37 ++ .../bruno-filestore/src/formats/yml/utils.ts | 14 + packages/bruno-filestore/src/index.ts | 81 ++- packages/bruno-filestore/src/types.ts | 127 +--- packages/bruno-filestore/src/utils/index.ts | 15 + packages/bruno-filestore/src/workers/index.ts | 14 +- .../src/workers/worker-script.ts | 24 +- packages/bruno-filestore/tsconfig.json | 11 +- .../bruno-js/src/sandbox/node-vm/index.js | 7 +- packages/bruno-lang/v2/src/bruToJson.js | 16 - .../bruno-lang/v2/tests/bruToJson.spec.js | 54 ++ packages/bruno-schema-types/.gitignore | 18 + packages/bruno-schema-types/package.json | 52 ++ .../src/collection/collection.ts | 23 + .../src/collection/environment.ts | 19 + .../src/collection/examples.ts | 35 ++ .../src/collection/folder.ts | 24 + .../src/collection/index.ts | 22 + .../bruno-schema-types/src/collection/item.ts | 45 ++ .../bruno-schema-types/src/common/auth.ts | 106 ++++ .../bruno-schema-types/src/common/file.ts | 11 + .../bruno-schema-types/src/common/graphql.ts | 5 + .../bruno-schema-types/src/common/index.ts | 23 + .../src/common/key-value.ts | 13 + .../src/common/multipart-form.ts | 14 + .../bruno-schema-types/src/common/scripts.ts | 5 + packages/bruno-schema-types/src/common/uid.ts | 5 + .../src/common/variables.ts | 16 + packages/bruno-schema-types/src/index.ts | 11 + .../bruno-schema-types/src/requests/grpc.ts | 37 ++ .../bruno-schema-types/src/requests/http.ts | 56 ++ .../bruno-schema-types/src/requests/index.ts | 27 + .../src/requests/websocket.ts | 28 + packages/bruno-schema-types/tsconfig.json | 20 + scripts/setup.js | 3 +- .../draft/draft-values-in-requests.spec.ts | 1 + .../open/open-multiple-collections.spec.ts | 2 +- tests/preferences/autosave/autosave.spec.ts | 198 +++++++ 108 files changed, 5943 insertions(+), 850 deletions(-) create mode 100644 packages/bruno-app/src/components/DeprecationWarning/StyledWrapper.js create mode 100644 packages/bruno-app/src/components/DeprecationWarning/index.js create mode 100644 packages/bruno-app/src/components/Icons/IconAlertTriangleFilled/index.js create mode 100644 packages/bruno-app/src/components/Sidebar/CreateCollection/StyledWrapper.js create mode 100644 packages/bruno-app/src/providers/ReduxStore/middlewares/autosave/middleware.js create mode 100644 packages/bruno-filestore/src/formats/yml/common/assertions.ts create mode 100644 packages/bruno-filestore/src/formats/yml/common/auth-oauth2.ts create mode 100644 packages/bruno-filestore/src/formats/yml/common/auth.ts create mode 100644 packages/bruno-filestore/src/formats/yml/common/body.ts create mode 100644 packages/bruno-filestore/src/formats/yml/common/headers.ts create mode 100644 packages/bruno-filestore/src/formats/yml/common/params.ts create mode 100644 packages/bruno-filestore/src/formats/yml/common/scripts.ts create mode 100644 packages/bruno-filestore/src/formats/yml/common/variables.ts create mode 100644 packages/bruno-filestore/src/formats/yml/index.ts create mode 100644 packages/bruno-filestore/src/formats/yml/items/parseGraphQLRequest.ts create mode 100644 packages/bruno-filestore/src/formats/yml/items/parseGrpcRequest.ts create mode 100644 packages/bruno-filestore/src/formats/yml/items/parseHttpRequest.ts create mode 100644 packages/bruno-filestore/src/formats/yml/items/parseScript.ts create mode 100644 packages/bruno-filestore/src/formats/yml/items/parseWebsocketRequest.ts create mode 100644 packages/bruno-filestore/src/formats/yml/items/stringifyGraphQLRequest.ts create mode 100644 packages/bruno-filestore/src/formats/yml/items/stringifyGrpcRequest.ts create mode 100644 packages/bruno-filestore/src/formats/yml/items/stringifyHttpRequest.ts create mode 100644 packages/bruno-filestore/src/formats/yml/items/stringifyScript.ts create mode 100644 packages/bruno-filestore/src/formats/yml/items/stringifyWebsocketRequest.ts create mode 100644 packages/bruno-filestore/src/formats/yml/parseCollection.ts create mode 100644 packages/bruno-filestore/src/formats/yml/parseEnvironment.ts create mode 100644 packages/bruno-filestore/src/formats/yml/parseFolder.ts create mode 100644 packages/bruno-filestore/src/formats/yml/parseItem.ts create mode 100644 packages/bruno-filestore/src/formats/yml/stringifyCollection.ts create mode 100644 packages/bruno-filestore/src/formats/yml/stringifyEnvironment.ts create mode 100644 packages/bruno-filestore/src/formats/yml/stringifyFolder.ts create mode 100644 packages/bruno-filestore/src/formats/yml/stringifyItem.ts create mode 100644 packages/bruno-filestore/src/formats/yml/utils.ts create mode 100644 packages/bruno-filestore/src/utils/index.ts create mode 100644 packages/bruno-schema-types/.gitignore create mode 100644 packages/bruno-schema-types/package.json create mode 100644 packages/bruno-schema-types/src/collection/collection.ts create mode 100644 packages/bruno-schema-types/src/collection/environment.ts create mode 100644 packages/bruno-schema-types/src/collection/examples.ts create mode 100644 packages/bruno-schema-types/src/collection/folder.ts create mode 100644 packages/bruno-schema-types/src/collection/index.ts create mode 100644 packages/bruno-schema-types/src/collection/item.ts create mode 100644 packages/bruno-schema-types/src/common/auth.ts create mode 100644 packages/bruno-schema-types/src/common/file.ts create mode 100644 packages/bruno-schema-types/src/common/graphql.ts create mode 100644 packages/bruno-schema-types/src/common/index.ts create mode 100644 packages/bruno-schema-types/src/common/key-value.ts create mode 100644 packages/bruno-schema-types/src/common/multipart-form.ts create mode 100644 packages/bruno-schema-types/src/common/scripts.ts create mode 100644 packages/bruno-schema-types/src/common/uid.ts create mode 100644 packages/bruno-schema-types/src/common/variables.ts create mode 100644 packages/bruno-schema-types/src/index.ts create mode 100644 packages/bruno-schema-types/src/requests/grpc.ts create mode 100644 packages/bruno-schema-types/src/requests/http.ts create mode 100644 packages/bruno-schema-types/src/requests/index.ts create mode 100644 packages/bruno-schema-types/src/requests/websocket.ts create mode 100644 packages/bruno-schema-types/tsconfig.json create mode 100644 tests/preferences/autosave/autosave.spec.ts diff --git a/.github/actions/common/setup-node-deps/action.yml b/.github/actions/common/setup-node-deps/action.yml index f99758768..66c32f298 100644 --- a/.github/actions/common/setup-node-deps/action.yml +++ b/.github/actions/common/setup-node-deps/action.yml @@ -23,4 +23,5 @@ runs: npm run sandbox:bundle-libraries --workspace=packages/bruno-js npm run build:bruno-converters npm run build:bruno-requests + npm run build:schema-types npm run build:bruno-filestore diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index ffbe6df2f..60dd85f77 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -30,6 +30,7 @@ jobs: npm run sandbox:bundle-libraries --workspace=packages/bruno-js npm run build --workspace=packages/bruno-converters npm run build --workspace=packages/bruno-requests + npm run build --workspace=packages/bruno-schema-types npm run build --workspace=packages/bruno-filestore - name: Lint Check @@ -83,6 +84,7 @@ jobs: npm run sandbox:bundle-libraries --workspace=packages/bruno-js npm run build --workspace=packages/bruno-converters npm run build --workspace=packages/bruno-requests + npm run build --workspace=packages/bruno-schema-types npm run build --workspace=packages/bruno-filestore - name: Run Local Testbench @@ -134,6 +136,7 @@ jobs: npm run sandbox:bundle-libraries --workspace=packages/bruno-js npm run build:bruno-converters npm run build:bruno-requests + npm run build:schema-types npm run build:bruno-filestore - name: Run Playwright tests diff --git a/contributing.md b/contributing.md index 6206d59f5..988dcf36d 100644 --- a/contributing.md +++ b/contributing.md @@ -70,6 +70,7 @@ npm run build:bruno-query npm run build:bruno-common npm run build:bruno-converters npm run build:bruno-requests +npm run build:schema-types npm run build:bruno-filestore # bundle js sandbox libraries diff --git a/package-lock.json b/package-lock.json index ad4fd8d9b..6adf47774 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "packages/bruno-common", "packages/bruno-converters", "packages/bruno-schema", + "packages/bruno-schema-types", "packages/bruno-query", "packages/bruno-js", "packages/bruno-lang", @@ -3554,6 +3555,16 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/@develar/schema-utils/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, "node_modules/@develar/schema-utils/node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -5566,6 +5577,13 @@ "node": ">= 8" } }, + "node_modules/@opencollection/types": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@opencollection/types/-/types-0.1.0.tgz", + "integrity": "sha512-/v64ShE+KyDUAfAlO6Qd5wBwPArd603VC44eife/CdmrtPUSIiFBYcZ9gxAD7LlW99J36wb5IkMpKFDvViINiA==", + "dev": true, + "license": "MIT" + }, "node_modules/@parcel/watcher": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.0.tgz", @@ -6964,25 +6982,6 @@ "@rsbuild/core": "1.x" } }, - "node_modules/@rsbuild/plugin-sass/node_modules/nanoid": { - "version": "3.3.8", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", - "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, "node_modules/@rsbuild/plugin-sass/node_modules/postcss": { "version": "8.4.49", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", @@ -8407,6 +8406,15 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/nanoid": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/nanoid/-/nanoid-2.1.0.tgz", + "integrity": "sha512-xdkn/oRTA0GSNPLIKZgHWqDTWZsVrieKomxJBOQUK9YDD+zfSgmwD5t4WJYra5S7XyhTw7tfvwznW+pFexaepQ==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/node": { "version": "22.15.17", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.17.tgz", @@ -8843,6 +8851,10 @@ "resolved": "packages/bruno-schema", "link": true }, + "node_modules/@usebruno/schema-types": { + "resolved": "packages/bruno-schema-types", + "link": true + }, "node_modules/@usebruno/tests": { "resolved": "packages/bruno-tests", "link": true @@ -9306,16 +9318,6 @@ } } }, - "node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "ajv": "^6.9.1" - } - }, "node_modules/amdefine": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-0.0.8.tgz", @@ -19413,6 +19415,24 @@ "integrity": "sha512-wynEP02LmIbLpcYw8uBKpcfF6dmg2vcpKqxeH5UcoKEYdExslsdUA4ugFauuaeYdTB76ez6gJW8XAZ6CgkXYxA==", "license": "MIT" }, + "node_modules/nanoid": { + "version": "3.3.8", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", + "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, "node_modules/native-reg": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/native-reg/-/native-reg-1.1.1.tgz", @@ -21241,25 +21261,6 @@ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", "license": "MIT" }, - "node_modules/postcss/node_modules/nanoid": { - "version": "3.3.8", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", - "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, "node_modules/posthog-node": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/posthog-node/-/posthog-node-4.2.1.tgz", @@ -23735,6 +23736,16 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/schema-utils/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, "node_modules/schema-utils/node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -28437,24 +28448,6 @@ "dev": true, "license": "MIT" }, - "packages/bruno-app/node_modules/nanoid": { - "version": "3.3.8", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", - "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, "packages/bruno-app/node_modules/semver": { "version": "7.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", @@ -30233,24 +30226,6 @@ "node": ">=16 || 14 >=14.17" } }, - "packages/bruno-converters/node_modules/nanoid": { - "version": "3.3.8", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", - "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, "packages/bruno-converters/node_modules/rimraf": { "version": "5.0.10", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz", @@ -31805,24 +31780,6 @@ "dev": true, "license": "MIT" }, - "packages/bruno-electron/node_modules/nanoid": { - "version": "3.3.8", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", - "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, "packages/bruno-electron/node_modules/semver": { "version": "7.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", @@ -31852,20 +31809,27 @@ "version": "0.1.0", "license": "MIT", "dependencies": { + "@types/nanoid": "^2.1.0", "@usebruno/lang": "0.12.0", - "lodash": "^4.17.21" + "ajv": "^8.17.1", + "lodash": "^4.17.21", + "yaml": "^2.3.4" }, "devDependencies": { "@babel/preset-env": "^7.22.0", "@babel/preset-typescript": "^7.22.0", + "@opencollection/types": "0.1.0", "@rollup/plugin-commonjs": "^23.0.2", + "@rollup/plugin-json": "^6.1.0", "@rollup/plugin-node-resolve": "^15.0.1", - "@rollup/plugin-typescript": "^9.0.2", + "@rollup/plugin-typescript": "^12.1.2", "@types/jest": "^29.5.11", "@types/lodash": "^4.14.191", "@types/node": "^24.1.0", + "@usebruno/schema-types": "0.0.1", "babel-jest": "^29.7.0", "jest": "^29.2.0", + "nanoid": "3.3.8", "rimraf": "^3.0.2", "rollup": "3.29.5", "rollup-plugin-dts": "^5.0.0", @@ -31874,6 +31838,33 @@ "typescript": "^4.8.4" } }, + "packages/bruno-filestore/node_modules/@rollup/plugin-typescript": { + "version": "12.3.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-12.3.0.tgz", + "integrity": "sha512-7DP0/p7y3t67+NabT9f8oTBFE6gGkto4SA6Np2oudYmZE/m1dt8RB0SjL1msMxFpLo631qjRCcBlAbq1ml/Big==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.1.0", + "resolve": "^1.22.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.14.0||^3.0.0||^4.0.0", + "tslib": "*", + "typescript": ">=3.7.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + }, + "tslib": { + "optional": true + } + } + }, "packages/bruno-filestore/node_modules/@types/node": { "version": "24.1.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-24.1.0.tgz", @@ -31954,6 +31945,18 @@ "dev": true, "license": "MIT" }, + "packages/bruno-filestore/node_modules/yaml": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz", + "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + } + }, "packages/bruno-graphql-docs": { "name": "@usebruno/graphql-docs", "version": "0.1.0", @@ -32056,24 +32059,6 @@ "proxy-from-env": "^1.1.0" } }, - "packages/bruno-js/node_modules/nanoid": { - "version": "3.3.8", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", - "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, "packages/bruno-js/node_modules/xml-formatter": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/xml-formatter/-/xml-formatter-3.5.0.tgz", @@ -32242,21 +32227,26 @@ "yup": "^0.32.11" } }, - "packages/bruno-schema/node_modules/nanoid": { - "version": "3.3.8", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", - "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], + "packages/bruno-schema-types": { + "name": "@usebruno/schema-types", + "version": "0.0.1", + "license": "MIT", + "devDependencies": { + "typescript": "^5.0.0" + } + }, + "packages/bruno-schema-types/node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", "bin": { - "nanoid": "bin/nanoid.cjs" + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" }, "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + "node": ">=14.17" } }, "packages/bruno-tests": { diff --git a/package.json b/package.json index 520eaad33..c13afb087 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "packages/bruno-common", "packages/bruno-converters", "packages/bruno-schema", + "packages/bruno-schema-types", "packages/bruno-query", "packages/bruno-js", "packages/bruno-lang", @@ -61,6 +62,7 @@ "build:bruno-converters": "npm run build --workspace=packages/bruno-converters", "build:bruno-query": "npm run build --workspace=packages/bruno-query", "build:graphql-docs": "npm run build --workspace=packages/bruno-graphql-docs", + "build:schema-types": "npm run build --workspace=packages/bruno-schema-types", "build:electron": "node ./scripts/build-electron.js", "build:electron:mac": "./scripts/build-electron.sh mac", "build:electron:win": "./scripts/build-electron.sh win", diff --git a/packages/bruno-app/src/components/CollectionSettings/Presets/index.js b/packages/bruno-app/src/components/CollectionSettings/Presets/index.js index 30fd44081..ca467b547 100644 --- a/packages/bruno-app/src/components/CollectionSettings/Presets/index.js +++ b/packages/bruno-app/src/components/CollectionSettings/Presets/index.js @@ -4,10 +4,12 @@ import StyledWrapper from './StyledWrapper'; import { updateCollectionPresets } from 'providers/ReduxStore/slices/collections'; import { saveCollectionSettings } from 'providers/ReduxStore/slices/collections/actions'; import { get } from 'lodash'; +import DeprecationWarning from 'components/DeprecationWarning'; const PresetsSettings = ({ collection }) => { const dispatch = useDispatch(); const initialPresets = { requestType: 'http', requestUrl: '' }; + const deprecationWarningMessage = 'Presets is deprecated and will be removed in v3.0.0'; // Get presets from draft.brunoConfig if it exists, otherwise from brunoConfig const currentPresets = collection.draft?.brunoConfig @@ -35,7 +37,8 @@ const PresetsSettings = ({ collection }) => { return ( -
+ +
These presets will be used as the default values for new requests in this collection.
diff --git a/packages/bruno-app/src/components/CollectionSettings/Vars/index.js b/packages/bruno-app/src/components/CollectionSettings/Vars/index.js index 02375f19a..7e0142520 100644 --- a/packages/bruno-app/src/components/CollectionSettings/Vars/index.js +++ b/packages/bruno-app/src/components/CollectionSettings/Vars/index.js @@ -4,12 +4,15 @@ import VarsTable from './VarsTable'; import StyledWrapper from './StyledWrapper'; import { saveCollectionSettings } from 'providers/ReduxStore/slices/collections/actions'; import { useDispatch } from 'react-redux'; +import DeprecationWarning from 'components/DeprecationWarning'; const Vars = ({ collection }) => { const dispatch = useDispatch(); const requestVars = collection.draft?.root ? get(collection, 'draft.root.request.vars.req', []) : get(collection, 'root.request.vars.req', []); const responseVars = collection.draft?.root ? get(collection, 'draft.root.request.vars.res', []) : get(collection, 'root.request.vars.res', []); const handleSave = () => dispatch(saveCollectionSettings(collection.uid)); + const deprecationWarningMessage = 'Post response vars is deprecated and will be removed in v3.0.0'; + return (
@@ -18,6 +21,7 @@ const Vars = ({ collection }) => {
Post Response
+
diff --git a/packages/bruno-app/src/components/DeprecationWarning/StyledWrapper.js b/packages/bruno-app/src/components/DeprecationWarning/StyledWrapper.js new file mode 100644 index 000000000..71e681879 --- /dev/null +++ b/packages/bruno-app/src/components/DeprecationWarning/StyledWrapper.js @@ -0,0 +1,33 @@ +import styled from 'styled-components'; + +const StyledWrapper = styled.div` + .deprecation-warning { + box-sizing: border-box; + display: flex; + flex-direction: row; + align-items: center; + padding: 8px; + gap: 4px; + margin-bottom: 8px; + background: ${(props) => props.theme.deprecationWarning.bg}; + border: 1px solid ${(props) => props.theme.deprecationWarning.border}; + border-radius: 6px; + + .warning-icon { + color: ${(props) => props.theme.deprecationWarning.icon}; + flex-shrink: 0; + width: 16px; + height: 16px; + } + + .warning-text { + font-family: 'Inter', sans-serif; + font-style: normal; + font-size: 14px; + line-height: 17px; + color: ${(props) => props.theme.deprecationWarning.text}; + } + } +`; + +export default StyledWrapper; diff --git a/packages/bruno-app/src/components/DeprecationWarning/index.js b/packages/bruno-app/src/components/DeprecationWarning/index.js new file mode 100644 index 000000000..387475814 --- /dev/null +++ b/packages/bruno-app/src/components/DeprecationWarning/index.js @@ -0,0 +1,16 @@ +import React from 'react'; +import IconAlertTriangleFilled from '../Icons/IconAlertTriangleFilled'; +import StyledWrapper from './StyledWrapper'; + +const DeprecationWarning = ({ message }) => { + return ( + +
+ + {message} +
+
+ ); +}; + +export default DeprecationWarning; diff --git a/packages/bruno-app/src/components/FolderSettings/Vars/index.js b/packages/bruno-app/src/components/FolderSettings/Vars/index.js index 69f901fab..34c72cd25 100644 --- a/packages/bruno-app/src/components/FolderSettings/Vars/index.js +++ b/packages/bruno-app/src/components/FolderSettings/Vars/index.js @@ -4,12 +4,15 @@ import VarsTable from './VarsTable'; import StyledWrapper from './StyledWrapper'; import { saveFolderRoot } from 'providers/ReduxStore/slices/collections/actions'; import { useDispatch } from 'react-redux'; +import DeprecationWarning from 'components/DeprecationWarning'; const Vars = ({ collection, folder }) => { const dispatch = useDispatch(); const requestVars = folder.draft ? get(folder, 'draft.request.vars.req', []) : get(folder, 'root.request.vars.req', []); const responseVars = folder.draft ? get(folder, 'draft.request.vars.res', []) : get(folder, 'root.request.vars.res', []); const handleSave = () => dispatch(saveFolderRoot(collection.uid, folder.uid)); + const deprecationWarningMessage = 'Post response vars is deprecated and will be removed in v3.0.0'; + return (
@@ -18,6 +21,7 @@ const Vars = ({ collection, folder }) => {
Post Response
+
diff --git a/packages/bruno-app/src/components/Icons/IconAlertTriangleFilled/index.js b/packages/bruno-app/src/components/Icons/IconAlertTriangleFilled/index.js new file mode 100644 index 000000000..508a608b1 --- /dev/null +++ b/packages/bruno-app/src/components/Icons/IconAlertTriangleFilled/index.js @@ -0,0 +1,14 @@ +import React from 'react'; + +const IconAlertTriangleFilled = ({ size = 16, ...props }) => { + return ( + + + + ); +}; + +export default IconAlertTriangleFilled; diff --git a/packages/bruno-app/src/components/Preferences/General/index.js b/packages/bruno-app/src/components/Preferences/General/index.js index 14eff0709..fa7bf0dea 100644 --- a/packages/bruno-app/src/components/Preferences/General/index.js +++ b/packages/bruno-app/src/components/Preferences/General/index.js @@ -37,6 +37,25 @@ const General = ({ close }) => { .test('isValidTimeout', 'Request Timeout must be equal or greater than 0', (value) => { return value === undefined || Number(value) >= 0; }), + autoSave: Yup.object({ + enabled: Yup.boolean(), + interval: Yup.mixed() + .transform((value, originalValue) => { + return originalValue === '' ? undefined : value; + }) + .test('isNumber', 'Save Delay must be a number', (value) => { + return value === undefined || !isNaN(value); + }) + .test('isValidInterval', 'Save Delay must be at least 500ms', (value) => { + return value === undefined || Number(value) >= 500; + }) + }).test('intervalRequired', 'Save Delay is required when Auto Save is enabled', (value) => { + // If autosave is enabled, interval must be provided + if (value.enabled && (value.interval === undefined || value.interval === '')) { + return false; + } + return true; + }), defaultCollectionLocation: Yup.string().max(1024) }); @@ -53,6 +72,10 @@ const General = ({ close }) => { timeout: preferences.request.timeout, storeCookies: get(preferences, 'request.storeCookies', true), sendCookies: get(preferences, 'request.sendCookies', true), + autoSave: { + enabled: get(preferences, 'autoSave.enabled', false), + interval: get(preferences, 'autoSave.interval', 1000) + }, defaultCollectionLocation: get(preferences, 'general.defaultCollectionLocation', '') }, validationSchema: preferencesSchema, @@ -83,12 +106,16 @@ const General = ({ close }) => { storeCookies: newPreferences.storeCookies, sendCookies: newPreferences.sendCookies }, + autoSave: { + enabled: newPreferences.autoSave.enabled, + interval: newPreferences.autoSave.interval + }, general: { defaultCollectionLocation: newPreferences.defaultCollectionLocation } })) .then(() => { - toast.success('Preferences saved successfully') + toast.success('Preferences saved successfully'); close(); }) .catch((err) => console.log(err) && toast.error('Failed to update preferences')); @@ -250,6 +277,40 @@ const General = ({ close }) => { {formik.touched.timeout && formik.errors.timeout ? (
{formik.errors.timeout}
) : null} +
+ + +
+
+ + +
+ {formik.touched.autoSave?.interval && formik.errors.autoSave?.interval && ( +
{formik.errors.autoSave.interval}
+ )}