diff --git a/.github/workflows/npm-bru-cli.yml b/.github/workflows/npm-bru-cli.yml index 62511558ca..ad964a1818 100644 --- a/.github/workflows/npm-bru-cli.yml +++ b/.github/workflows/npm-bru-cli.yml @@ -2,11 +2,6 @@ name: Bru CLI Tests (npm) on: workflow_dispatch: - inputs: - build: - description: 'Test Bru CLI (npm)' - required: true - default: 'true' # Assign permissions for unit tests to be reported. # See https://github.com/dorny/test-reporter/issues/168 diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 30fe01bb4e..aec3d68a0e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -5,6 +5,9 @@ on: pull_request: branches: [main] +permissions: + contents: read + jobs: unit-test: name: Unit Tests diff --git a/.nvmrc b/.nvmrc index 805b5a4e00..bb8c76c68e 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -v20.9.0 +v22.11.0 diff --git a/package-lock.json b/package-lock.json index 8bd25f8d3c..0bc6b89f7c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9515,7 +9515,6 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -13912,6 +13911,12 @@ "uc.micro": "^1.0.1" } }, + "node_modules/load-script": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/load-script/-/load-script-1.0.0.tgz", + "integrity": "sha512-kPEjMFtZvwL9TaZo0uZ2ml+Ye9HUMmPwbYRJ324qF9tqMejwykJ5ggTyvzmrbBeapCAbk98BSbTeovHEEP1uCA==", + "license": "MIT" + }, "node_modules/loader-runner": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", @@ -14426,6 +14431,12 @@ "node": ">= 0.6" } }, + "node_modules/memoize-one": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", + "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==", + "license": "MIT" + }, "node_modules/merge-descriptors": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", @@ -17154,6 +17165,28 @@ "node": ">=6" } }, + "node_modules/react-player": { + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/react-player/-/react-player-2.16.0.tgz", + "integrity": "sha512-mAIPHfioD7yxO0GNYVFD1303QFtI3lyyQZLY229UEAp/a10cSW+hPcakg0Keq8uWJxT2OiT/4Gt+Lc9bD6bJmQ==", + "license": "MIT", + "dependencies": { + "deepmerge": "^4.0.0", + "load-script": "^1.0.0", + "memoize-one": "^5.1.1", + "prop-types": "^15.7.2", + "react-fast-compare": "^3.0.1" + }, + "peerDependencies": { + "react": ">=16.6.0" + } + }, + "node_modules/react-player/node_modules/react-fast-compare": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", + "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==", + "license": "MIT" + }, "node_modules/react-redux": { "version": "7.2.9", "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.9.tgz", @@ -20575,6 +20608,7 @@ "react-i18next": "^15.0.1", "react-inspector": "^6.0.2", "react-pdf": "9.1.1", + "react-player": "^2.16.0", "react-redux": "^7.2.6", "react-tooltip": "^5.5.2", "sass": "^1.46.0", @@ -20688,7 +20722,7 @@ }, "packages/bruno-electron": { "name": "bruno", - "version": "v1.34.0", + "version": "v1.34.2", "dependencies": { "@aws-sdk/credential-providers": "3.658.1", "@usebruno/common": "0.1.0", diff --git a/packages/bruno-app/.gitignore b/packages/bruno-app/.gitignore index 1afc1f3a65..26d2023a39 100644 --- a/packages/bruno-app/.gitignore +++ b/packages/bruno-app/.gitignore @@ -32,3 +32,5 @@ yarn-error.log* # next.js .next/ out/ + +.env \ No newline at end of file diff --git a/packages/bruno-app/jest.config.js b/packages/bruno-app/jest.config.js new file mode 100644 index 0000000000..5d94a67b78 --- /dev/null +++ b/packages/bruno-app/jest.config.js @@ -0,0 +1,16 @@ +module.exports = { + rootDir: '.', + moduleNameMapper: { + '^assets/(.*)$': '/src/assets/$1', + '^components/(.*)$': '/src/components/$1', + '^hooks/(.*)$': '/src/hooks/$1', + '^themes/(.*)$': '/src/themes/$1', + '^api/(.*)$': '/src/api/$1', + '^pageComponents/(.*)$': '/src/pageComponents/$1', + '^providers/(.*)$': '/src/providers/$1', + '^utils/(.*)$': '/src/utils/$1' + }, + clearMocks: true, + moduleDirectories: ['node_modules', 'src'], + testEnvironment: 'node' +}; diff --git a/packages/bruno-app/package.json b/packages/bruno-app/package.json index f4d5fd0f82..52553b002e 100644 --- a/packages/bruno-app/package.json +++ b/packages/bruno-app/package.json @@ -66,6 +66,7 @@ "react-i18next": "^15.0.1", "react-inspector": "^6.0.2", "react-pdf": "9.1.1", + "react-player": "^2.16.0", "react-redux": "^7.2.6", "react-tooltip": "^5.5.2", "sass": "^1.46.0", diff --git a/packages/bruno-app/src/components/CodeEditor/StyledWrapper.js b/packages/bruno-app/src/components/CodeEditor/StyledWrapper.js index 7eba2bc1ff..edcee4cd9f 100644 --- a/packages/bruno-app/src/components/CodeEditor/StyledWrapper.js +++ b/packages/bruno-app/src/components/CodeEditor/StyledWrapper.js @@ -26,6 +26,12 @@ const StyledWrapper = styled.div` .CodeMirror-dialog { overflow: visible; + input { + background: transparent; + border: 1px solid #d3d6db; + outline: none; + border-radius: 0px; + } } #search-results-count { @@ -82,6 +88,14 @@ const StyledWrapper = styled.div` .CodeMirror-search-hint { display: inline; } + + .cm-s-default span.cm-property { + color: #1f61a0 !important; + } + + .cm-s-default span.cm-variable { + color: #397d13 !important; + } `; export default StyledWrapper; diff --git a/packages/bruno-app/src/components/CodeEditor/index.js b/packages/bruno-app/src/components/CodeEditor/index.js index 8ec68bdf89..aa0238ef0d 100644 --- a/packages/bruno-app/src/components/CodeEditor/index.js +++ b/packages/bruno-app/src/components/CodeEditor/index.js @@ -15,7 +15,7 @@ import { JSHINT } from 'jshint'; import stripJsonComments from 'strip-json-comments'; let CodeMirror; -const SERVER_RENDERED = typeof navigator === 'undefined' || global['PREVENT_CODEMIRROR_RENDER'] === true; +const SERVER_RENDERED = typeof window === 'undefined' || global['PREVENT_CODEMIRROR_RENDER'] === true; const TAB_SIZE = 2; if (!SERVER_RENDERED) { @@ -58,13 +58,14 @@ if (!SERVER_RENDERED) { 'req.getExecutionMode()', 'bru', 'bru.cwd()', - 'bru.getEnvName(key)', + 'bru.getEnvName()', 'bru.getProcessEnv(key)', 'bru.hasEnvVar(key)', 'bru.getEnvVar(key)', 'bru.getFolderVar(key)', 'bru.getCollectionVar(key)', 'bru.setEnvVar(key,value)', + 'bru.deleteEnvVar(key)', 'bru.hasVar(key)', 'bru.getVar(key)', 'bru.setVar(key,value)', @@ -189,32 +190,8 @@ export default class CodeEditor extends React.Component { 'Cmd-Y': 'foldAll', 'Ctrl-I': 'unfoldAll', 'Cmd-I': 'unfoldAll', - 'Cmd-/': (cm) => { - // comment/uncomment every selected line(s) - const selections = cm.listSelections(); - selections.forEach((range) => { - for (let i = range.from().line; i <= range.to().line; i++) { - const selectedLine = cm.getLine(i); - // if commented line, remove comment - if (selectedLine.trim().startsWith('//')) { - cm.replaceRange( - selectedLine.replace(/^(\s*)\/\/\s?/, '$1'), - { line: i, ch: 0 }, - { line: i, ch: selectedLine.length } - ); - continue; - } - // otherwise add comment - cm.replaceRange( - selectedLine.search(/\S|$/) >= TAB_SIZE - ? ' '.repeat(TAB_SIZE) + '// ' + selectedLine.trim() - : '// ' + selectedLine, - { line: i, ch: 0 }, - { line: i, ch: selectedLine.length } - ); - } - }); - } + 'Ctrl-/': 'toggleComment', + 'Cmd-/': 'toggleComment' }, foldOptions: { widget: (from, to) => { @@ -281,9 +258,9 @@ export default class CodeEditor extends React.Component { while (end < currentLine.length && /[^{}();\s\[\]\,]/.test(currentLine.charAt(end))) ++end; while (start && /[^{}();\s\[\]\,]/.test(currentLine.charAt(start - 1))) --start; let curWord = start != end && currentLine.slice(start, end); - //Qualify if autocomplete will be shown + // Qualify if autocomplete will be shown if ( - /^(?!Shift|Tab|Enter|Escape|ArrowUp|ArrowDown|ArrowLeft|ArrowRight|\s)\w*/.test(event.key) && + /^(?!Shift|Tab|Enter|Escape|ArrowUp|ArrowDown|ArrowLeft|ArrowRight|Meta|Alt|Home|End\s)\w*/.test(event.key) && curWord.length > 0 && !/\/\/|\/\*|.*{{|`[^$]*{|`[^{]*$/.test(currentLine.slice(0, end)) && /(? { + const [videoUrl, setVideoUrl] = useState(null); + + useEffect(() => { + const videoType = contentType.split(';')[0]; + const byteArray = Buffer.from(dataBuffer, 'base64'); + const blob = new Blob([byteArray], { type: videoType }); + const url = URL.createObjectURL(blob); + setVideoUrl(url); + return () => URL.revokeObjectURL(url); + }, [contentType, dataBuffer]); + + if (!videoUrl) return
Loading video...
; + + return ( + console.error('Error loading video:', e)} + /> + ); +}); const QueryResultPreview = ({ previewTab, @@ -73,9 +100,7 @@ const QueryResultPreview = ({ ); } case 'preview-video': { - return ( -