diff --git a/package-lock.json b/package-lock.json index 095bdc2ea..332917b37 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1826,37 +1826,6 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, - "node_modules/@codemirror/language": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-0.20.2.tgz", - "integrity": "sha512-WB3Bnuusw0xhVvhBocieYKwJm04SOk5bPoOEYksVHKHcGHFOaYaw+eZVxR4gIqMMcGzOIUil0FsCmFk8yrhHpw==", - "peer": true, - "dependencies": { - "@codemirror/state": "^0.20.0", - "@codemirror/view": "^0.20.0", - "@lezer/common": "^0.16.0", - "@lezer/highlight": "^0.16.0", - "@lezer/lr": "^0.16.0", - "style-mod": "^4.0.0" - } - }, - "node_modules/@codemirror/state": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-0.20.1.tgz", - "integrity": "sha512-ms0tlV5A02OK0pFvTtSUGMLkoarzh1F8mr6jy1cD7ucSC2X/VLHtQCxfhdSEGqTYlQF2hoZtmLv+amqhdgbwjQ==", - "peer": true - }, - "node_modules/@codemirror/view": { - "version": "0.20.7", - "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-0.20.7.tgz", - "integrity": "sha512-pqEPCb9QFTOtHgAH5XU/oVy9UR/Anj6r+tG5CRmkNVcqSKEPmBU05WtN/jxJCFZBXf6HumzWC9ydE4qstO3TxQ==", - "peer": true, - "dependencies": { - "@codemirror/state": "^0.20.0", - "style-mod": "^4.0.0", - "w3c-keyname": "^2.2.4" - } - }, "node_modules/@develar/schema-utils": { "version": "2.6.5", "resolved": "https://registry.npmjs.org/@develar/schema-utils/-/schema-utils-2.6.5.tgz", @@ -2961,30 +2930,6 @@ "@jridgewell/sourcemap-codec": "1.4.14" } }, - "node_modules/@lezer/common": { - "version": "0.16.1", - "resolved": "https://registry.npmjs.org/@lezer/common/-/common-0.16.1.tgz", - "integrity": "sha512-qPmG7YTZ6lATyTOAWf8vXE+iRrt1NJd4cm2nJHK+v7X9TsOF6+HtuU/ctaZy2RCrluxDb89hI6KWQ5LfQGQWuA==", - "peer": true - }, - "node_modules/@lezer/highlight": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-0.16.0.tgz", - "integrity": "sha512-iE5f4flHlJ1g1clOStvXNLbORJoiW4Kytso6ubfYzHnaNo/eo5SKhxs4wv/rtvwZQeZrK3we8S9SyA7OGOoRKQ==", - "peer": true, - "dependencies": { - "@lezer/common": "^0.16.0" - } - }, - "node_modules/@lezer/lr": { - "version": "0.16.3", - "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-0.16.3.tgz", - "integrity": "sha512-pau7um4eAw94BEuuShUIeQDTf3k4Wt6oIUOYxMmkZgDHdqtIcxWND4LRxi8nI9KuT4I1bXQv67BCapkxt7Ywqw==", - "peer": true, - "dependencies": { - "@lezer/common": "^0.16.0" - } - }, "node_modules/@malept/cross-spawn-promise": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-1.1.1.tgz", @@ -4839,39 +4784,6 @@ "node": ">=10.12.0" } }, - "node_modules/autoprefixer": { - "version": "10.4.13", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.13.tgz", - "integrity": "sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/autoprefixer" - } - ], - "peer": true, - "dependencies": { - "browserslist": "^4.21.4", - "caniuse-lite": "^1.0.30001426", - "fraction.js": "^4.2.0", - "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", - "postcss-value-parser": "^4.2.0" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" - }, - "engines": { - "node": "^10 || ^12 || >=14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, "node_modules/aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", @@ -5300,6 +5212,7 @@ "version": "4.21.4", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", + "dev": true, "funding": [ { "type": "opencollective", @@ -7338,7 +7251,8 @@ "node_modules/electron-to-chromium": { "version": "1.4.284", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", - "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==" + "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==", + "dev": true }, "node_modules/electron-util": { "version": "0.17.2", @@ -8140,19 +8054,6 @@ "node": ">= 0.6" } }, - "node_modules/fraction.js": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", - "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==", - "peer": true, - "engines": { - "node": "*" - }, - "funding": { - "type": "patreon", - "url": "https://www.patreon.com/infusion" - } - }, "node_modules/fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", @@ -8643,18 +8544,6 @@ "node": ">= 6" } }, - "node_modules/graphql-ws": { - "version": "5.11.2", - "resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-5.11.2.tgz", - "integrity": "sha512-4EiZ3/UXYcjm+xFGP544/yW1+DVI8ZpKASFbzrV5EDTFWJp0ZvLl4Dy2fSZAzz9imKp5pZMIcjB0x/H69Pv/6w==", - "peer": true, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "graphql": ">=0.11 <=16" - } - }, "node_modules/handlebars": { "version": "4.7.8", "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", @@ -11641,7 +11530,8 @@ "node_modules/node-releases": { "version": "2.0.8", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.8.tgz", - "integrity": "sha512-dFSmB8fFHEH/s81Xi+Y/15DQY6VHW81nXRj86EMSL3lmuTmK1e+aT4wrFCkTbm+gSwkw4KpX+rT/pMM2c1mF+A==" + "integrity": "sha512-dFSmB8fFHEH/s81Xi+Y/15DQY6VHW81nXRj86EMSL3lmuTmK1e+aT4wrFCkTbm+gSwkw4KpX+rT/pMM2c1mF+A==", + "dev": true }, "node_modules/normalize-package-data": { "version": "2.5.0", @@ -11678,15 +11568,6 @@ "node": ">=0.10.0" } }, - "node_modules/normalize-range": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/normalize-url": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", @@ -13626,7 +13507,8 @@ "node_modules/react-is": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true }, "node_modules/react-redux": { "version": "7.2.9", @@ -15018,12 +14900,6 @@ "webpack": "^5.0.0" } }, - "node_modules/style-mod": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.0.0.tgz", - "integrity": "sha512-OPhtyEjyyN9x3nhPsu76f52yUGXiZcgvsrFVtvTkyGRQJ0XK+GPc6ov1z+lRpbeabka+MYEQxOYRnt5nF30aMw==", - "peer": true - }, "node_modules/styled-components": { "version": "5.3.6", "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-5.3.6.tgz", @@ -15954,6 +15830,7 @@ "version": "1.0.10", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "dev": true, "funding": [ { "type": "opencollective", @@ -16236,12 +16113,6 @@ "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2.tgz", "integrity": "sha512-zHhCWatviizPIq9B7Vh9uvrH6x3sK8itC84HkamnBWoDFJtzBf7SWlpLCZUit72b3os45h6RWQNC9xHRDF8dRA==" }, - "node_modules/w3c-keyname": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.6.tgz", - "integrity": "sha512-f+fciywl1SJEniZHD6H+kUO8gOnwIr7f4ijKA6+ZvJFjeGi1r4PDLl53Ayud9O/rk64RqgoQine0feoeOU0kXg==", - "peer": true - }, "node_modules/walker": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", @@ -18428,37 +18299,6 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, - "@codemirror/language": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-0.20.2.tgz", - "integrity": "sha512-WB3Bnuusw0xhVvhBocieYKwJm04SOk5bPoOEYksVHKHcGHFOaYaw+eZVxR4gIqMMcGzOIUil0FsCmFk8yrhHpw==", - "peer": true, - "requires": { - "@codemirror/state": "^0.20.0", - "@codemirror/view": "^0.20.0", - "@lezer/common": "^0.16.0", - "@lezer/highlight": "^0.16.0", - "@lezer/lr": "^0.16.0", - "style-mod": "^4.0.0" - } - }, - "@codemirror/state": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-0.20.1.tgz", - "integrity": "sha512-ms0tlV5A02OK0pFvTtSUGMLkoarzh1F8mr6jy1cD7ucSC2X/VLHtQCxfhdSEGqTYlQF2hoZtmLv+amqhdgbwjQ==", - "peer": true - }, - "@codemirror/view": { - "version": "0.20.7", - "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-0.20.7.tgz", - "integrity": "sha512-pqEPCb9QFTOtHgAH5XU/oVy9UR/Anj6r+tG5CRmkNVcqSKEPmBU05WtN/jxJCFZBXf6HumzWC9ydE4qstO3TxQ==", - "peer": true, - "requires": { - "@codemirror/state": "^0.20.0", - "style-mod": "^4.0.0", - "w3c-keyname": "^2.2.4" - } - }, "@develar/schema-utils": { "version": "2.6.5", "resolved": "https://registry.npmjs.org/@develar/schema-utils/-/schema-utils-2.6.5.tgz", @@ -19330,30 +19170,6 @@ "@jridgewell/sourcemap-codec": "1.4.14" } }, - "@lezer/common": { - "version": "0.16.1", - "resolved": "https://registry.npmjs.org/@lezer/common/-/common-0.16.1.tgz", - "integrity": "sha512-qPmG7YTZ6lATyTOAWf8vXE+iRrt1NJd4cm2nJHK+v7X9TsOF6+HtuU/ctaZy2RCrluxDb89hI6KWQ5LfQGQWuA==", - "peer": true - }, - "@lezer/highlight": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-0.16.0.tgz", - "integrity": "sha512-iE5f4flHlJ1g1clOStvXNLbORJoiW4Kytso6ubfYzHnaNo/eo5SKhxs4wv/rtvwZQeZrK3we8S9SyA7OGOoRKQ==", - "peer": true, - "requires": { - "@lezer/common": "^0.16.0" - } - }, - "@lezer/lr": { - "version": "0.16.3", - "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-0.16.3.tgz", - "integrity": "sha512-pau7um4eAw94BEuuShUIeQDTf3k4Wt6oIUOYxMmkZgDHdqtIcxWND4LRxi8nI9KuT4I1bXQv67BCapkxt7Ywqw==", - "peer": true, - "requires": { - "@lezer/common": "^0.16.0" - } - }, "@malept/cross-spawn-promise": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-1.1.1.tgz", @@ -19680,8 +19496,7 @@ "@tabler/icons": { "version": "1.119.0", "resolved": "https://registry.npmjs.org/@tabler/icons/-/icons-1.119.0.tgz", - "integrity": "sha512-Fk3Qq4w2SXcTjc/n1cuL5bccPkylrOMo7cYpQIf/yw6zP76LQV9dtLcHQUjFiUnaYuswR645CnURIhlafyAh9g==", - "requires": {} + "integrity": "sha512-Fk3Qq4w2SXcTjc/n1cuL5bccPkylrOMo7cYpQIf/yw6zP76LQV9dtLcHQUjFiUnaYuswR645CnURIhlafyAh9g==" }, "@tauri-apps/cli": { "version": "1.2.2", @@ -20302,8 +20117,7 @@ } }, "@usebruno/schema": { - "version": "file:packages/bruno-schema", - "requires": {} + "version": "file:packages/bruno-schema" }, "@usebruno/testbench": { "version": "file:packages/bruno-testbench", @@ -20479,8 +20293,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz", "integrity": "sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==", - "dev": true, - "requires": {} + "dev": true }, "@webpack-cli/info": { "version": "1.5.0", @@ -20495,8 +20308,7 @@ "version": "1.7.0", "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.7.0.tgz", "integrity": "sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==", - "dev": true, - "requires": {} + "dev": true }, "@xtuc/ieee754": { "version": "1.2.0", @@ -20601,8 +20413,7 @@ "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "requires": {} + "dev": true }, "amdefine": { "version": "0.0.8", @@ -20935,20 +20746,6 @@ "resolved": "https://registry.npmjs.org/atomically/-/atomically-1.7.0.tgz", "integrity": "sha512-Xcz9l0z7y9yQ9rdDaxlmaI4uJHf/T8g9hOEzJcsEqX2SjCj4J20uK7+ldkDHMbpJDK76wF7xEIgxc/vSlsfw5w==" }, - "autoprefixer": { - "version": "10.4.13", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.13.tgz", - "integrity": "sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg==", - "peer": true, - "requires": { - "browserslist": "^4.21.4", - "caniuse-lite": "^1.0.30001426", - "fraction.js": "^4.2.0", - "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", - "postcss-value-parser": "^4.2.0" - } - }, "aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", @@ -21278,6 +21075,7 @@ "version": "4.21.4", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", + "dev": true, "requires": { "caniuse-lite": "^1.0.30001400", "electron-to-chromium": "^1.4.251", @@ -22213,8 +22011,7 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.3.1.tgz", "integrity": "sha512-fBffmak0bPAnyqc/HO8C3n2sHrp9wcqQz6ES9koRF2/mLOVAx9zIQ3Y7R29sYCteTPqMCwns4WYQoCX91Xl3+w==", - "dev": true, - "requires": {} + "dev": true }, "css-loader": { "version": "6.7.3", @@ -22359,8 +22156,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-3.1.0.tgz", "integrity": "sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==", - "dev": true, - "requires": {} + "dev": true }, "csso": { "version": "4.2.0", @@ -22933,7 +22729,8 @@ "electron-to-chromium": { "version": "1.4.284", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", - "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==" + "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==", + "dev": true }, "electron-util": { "version": "0.17.2", @@ -23558,12 +23355,6 @@ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" }, - "fraction.js": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", - "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==", - "peer": true - }, "fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", @@ -23826,8 +23617,7 @@ "goober": { "version": "2.1.11", "resolved": "https://registry.npmjs.org/goober/-/goober-2.1.11.tgz", - "integrity": "sha512-5SS2lmxbhqH0u9ABEWq7WPU69a4i2pYcHeCxqaNq6Cw3mnrF0ghWNM4tEGid4dKy8XNIAUbuThuozDHHKJVh3A==", - "requires": {} + "integrity": "sha512-5SS2lmxbhqH0u9ABEWq7WPU69a4i2pYcHeCxqaNq6Cw3mnrF0ghWNM4tEGid4dKy8XNIAUbuThuozDHHKJVh3A==" }, "got": { "version": "9.6.0", @@ -23950,13 +23740,6 @@ } } }, - "graphql-ws": { - "version": "5.11.2", - "resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-5.11.2.tgz", - "integrity": "sha512-4EiZ3/UXYcjm+xFGP544/yW1+DVI8ZpKASFbzrV5EDTFWJp0ZvLl4Dy2fSZAzz9imKp5pZMIcjB0x/H69Pv/6w==", - "peer": true, - "requires": {} - }, "handlebars": { "version": "4.7.8", "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", @@ -24307,8 +24090,7 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", - "dev": true, - "requires": {} + "dev": true }, "idb": { "version": "7.1.1", @@ -25087,8 +24869,7 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", - "dev": true, - "requires": {} + "dev": true }, "jest-regex-util": { "version": "29.2.0", @@ -25850,8 +25631,7 @@ "meros": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/meros/-/meros-1.2.1.tgz", - "integrity": "sha512-R2f/jxYqCAGI19KhAvaxSOxALBMkaXWH2a7rOyqQw+ZmizX5bKkEYWLzdhC+U82ZVVPVp6MCXe3EkVligh+12g==", - "requires": {} + "integrity": "sha512-R2f/jxYqCAGI19KhAvaxSOxALBMkaXWH2a7rOyqQw+ZmizX5bKkEYWLzdhC+U82ZVVPVp6MCXe3EkVligh+12g==" }, "methods": { "version": "1.1.2", @@ -26185,7 +25965,8 @@ "node-releases": { "version": "2.0.8", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.8.tgz", - "integrity": "sha512-dFSmB8fFHEH/s81Xi+Y/15DQY6VHW81nXRj86EMSL3lmuTmK1e+aT4wrFCkTbm+gSwkw4KpX+rT/pMM2c1mF+A==" + "integrity": "sha512-dFSmB8fFHEH/s81Xi+Y/15DQY6VHW81nXRj86EMSL3lmuTmK1e+aT4wrFCkTbm+gSwkw4KpX+rT/pMM2c1mF+A==", + "dev": true }, "normalize-package-data": { "version": "2.5.0", @@ -26218,12 +25999,6 @@ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" }, - "normalize-range": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", - "peer": true - }, "normalize-url": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", @@ -26886,29 +26661,25 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.1.2.tgz", "integrity": "sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==", - "dev": true, - "requires": {} + "dev": true }, "postcss-discard-duplicates": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz", "integrity": "sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==", - "dev": true, - "requires": {} + "dev": true }, "postcss-discard-empty": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz", "integrity": "sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==", - "dev": true, - "requires": {} + "dev": true }, "postcss-discard-overridden": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz", "integrity": "sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==", - "dev": true, - "requires": {} + "dev": true }, "postcss-js": { "version": "3.0.3", @@ -27010,8 +26781,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", - "dev": true, - "requires": {} + "dev": true }, "postcss-modules-local-by-default": { "version": "4.0.0", @@ -27054,8 +26824,7 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz", "integrity": "sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==", - "dev": true, - "requires": {} + "dev": true }, "postcss-normalize-display-values": { "version": "5.1.0", @@ -27576,13 +27345,13 @@ "react-inspector": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/react-inspector/-/react-inspector-6.0.2.tgz", - "integrity": "sha512-x+b7LxhmHXjHoU/VrFAzw5iutsILRoYyDq97EDYdFpPLcvqtEzk4ZSZSQjnFPbr5T57tLXnHcqFYoN1pI6u8uQ==", - "requires": {} + "integrity": "sha512-x+b7LxhmHXjHoU/VrFAzw5iutsILRoYyDq97EDYdFpPLcvqtEzk4ZSZSQjnFPbr5T57tLXnHcqFYoN1pI6u8uQ==" }, "react-is": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true }, "react-redux": { "version": "7.2.9", @@ -27769,8 +27538,7 @@ "redux-thunk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz", - "integrity": "sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==", - "requires": {} + "integrity": "sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==" }, "regenerate": { "version": "1.4.2", @@ -28072,8 +27840,7 @@ "version": "2.2.4", "resolved": "https://registry.npmjs.org/rollup-plugin-peer-deps-external/-/rollup-plugin-peer-deps-external-2.2.4.tgz", "integrity": "sha512-AWdukIM1+k5JDdAqV/Cxd+nejvno2FVLVeZ74NKggm3Q5s9cbbcOgUPGdbxPi4BXu7xGaZ8HG12F+thImYu/0g==", - "dev": true, - "requires": {} + "dev": true }, "rollup-plugin-postcss": { "version": "4.0.2", @@ -28686,14 +28453,7 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.1.tgz", "integrity": "sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ==", - "dev": true, - "requires": {} - }, - "style-mod": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.0.0.tgz", - "integrity": "sha512-OPhtyEjyyN9x3nhPsu76f52yUGXiZcgvsrFVtvTkyGRQJ0XK+GPc6ov1z+lRpbeabka+MYEQxOYRnt5nF30aMw==", - "peer": true + "dev": true }, "styled-components": { "version": "5.3.6", @@ -28730,8 +28490,7 @@ "styled-jsx": { "version": "5.0.7", "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.0.7.tgz", - "integrity": "sha512-b3sUzamS086YLRuvnaDigdAewz1/EFYlHpYBP5mZovKEdQQOIIYq8lApylub3HHZ6xFjV051kkGU7cudJmrXEA==", - "requires": {} + "integrity": "sha512-b3sUzamS086YLRuvnaDigdAewz1/EFYlHpYBP5mZovKEdQQOIIYq8lApylub3HHZ6xFjV051kkGU7cudJmrXEA==" }, "stylehacks": { "version": "5.1.1", @@ -29380,6 +29139,7 @@ "version": "1.0.10", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "dev": true, "requires": { "escalade": "^3.1.1", "picocolors": "^1.0.0" @@ -29468,8 +29228,7 @@ "use-sync-external-store": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", - "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", - "requires": {} + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==" }, "utf8-byte-length": { "version": "1.0.4", @@ -29602,12 +29361,6 @@ "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2.tgz", "integrity": "sha512-zHhCWatviizPIq9B7Vh9uvrH6x3sK8itC84HkamnBWoDFJtzBf7SWlpLCZUit72b3os45h6RWQNC9xHRDF8dRA==" }, - "w3c-keyname": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.6.tgz", - "integrity": "sha512-f+fciywl1SJEniZHD6H+kUO8gOnwIr7f4ijKA6+ZvJFjeGi1r4PDLl53Ayud9O/rk64RqgoQine0feoeOU0kXg==", - "peer": true - }, "walker": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", @@ -29688,8 +29441,7 @@ "version": "1.8.0", "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", - "dev": true, - "requires": {} + "dev": true }, "schema-utils": { "version": "3.1.1", diff --git a/packages/bruno-app/src/components/Environments/EnvironmentSettings/CopyEnvironment/index.js b/packages/bruno-app/src/components/Environments/EnvironmentSettings/CopyEnvironment/index.js index 87b833e40..a9fdf3b4a 100644 --- a/packages/bruno-app/src/components/Environments/EnvironmentSettings/CopyEnvironment/index.js +++ b/packages/bruno-app/src/components/Environments/EnvironmentSettings/CopyEnvironment/index.js @@ -17,7 +17,7 @@ const CopyEnvironment = ({ collection, environment, onClose }) => { }, validationSchema: Yup.object({ name: Yup.string() - .min(1, 'must be atleast 1 characters') + .min(1, 'must be at least 1 character') .max(50, 'must be 50 characters or less') .required('name is required') }), diff --git a/packages/bruno-app/src/components/Environments/EnvironmentSettings/CreateEnvironment/index.js b/packages/bruno-app/src/components/Environments/EnvironmentSettings/CreateEnvironment/index.js index d412687e2..c0ca7f5ec 100644 --- a/packages/bruno-app/src/components/Environments/EnvironmentSettings/CreateEnvironment/index.js +++ b/packages/bruno-app/src/components/Environments/EnvironmentSettings/CreateEnvironment/index.js @@ -17,7 +17,7 @@ const CreateEnvironment = ({ collection, onClose }) => { }, validationSchema: Yup.object({ name: Yup.string() - .min(1, 'must be atleast 1 characters') + .min(1, 'must be at least 1 character') .max(50, 'must be 50 characters or less') .required('name is required') }), diff --git a/packages/bruno-app/src/components/Environments/EnvironmentSettings/RenameEnvironment/index.js b/packages/bruno-app/src/components/Environments/EnvironmentSettings/RenameEnvironment/index.js index dc928d4c6..84572db90 100644 --- a/packages/bruno-app/src/components/Environments/EnvironmentSettings/RenameEnvironment/index.js +++ b/packages/bruno-app/src/components/Environments/EnvironmentSettings/RenameEnvironment/index.js @@ -17,7 +17,7 @@ const RenameEnvironment = ({ onClose, environment, collection }) => { }, validationSchema: Yup.object({ name: Yup.string() - .min(1, 'must be atleast 1 characters') + .min(1, 'must be at least 1 character') .max(50, 'must be 50 characters or less') .required('name is required') }), diff --git a/packages/bruno-app/src/components/Modal/StyledWrapper.js b/packages/bruno-app/src/components/Modal/StyledWrapper.js index 4ec5d4a25..eb32c9655 100644 --- a/packages/bruno-app/src/components/Modal/StyledWrapper.js +++ b/packages/bruno-app/src/components/Modal/StyledWrapper.js @@ -22,6 +22,7 @@ const Wrapper = styled.div` justify-content: center; overflow-y: auto; z-index: 10; + background-color: rgba(0, 0, 0, 0.5); } .bruno-modal-card { diff --git a/packages/bruno-app/src/components/Modal/index.js b/packages/bruno-app/src/components/Modal/index.js index 213c62efe..ec715a03d 100644 --- a/packages/bruno-app/src/components/Modal/index.js +++ b/packages/bruno-app/src/components/Modal/index.js @@ -61,19 +61,20 @@ const Modal = ({ children, confirmDisabled, hideCancel, - hideFooter + hideFooter, + closeModalFadeTimeout = 500 }) => { const [isClosing, setIsClosing] = useState(false); const escFunction = (event) => { const escKeyCode = 27; if (event.keyCode === escKeyCode) { - closeModal(); + closeModal({ type: 'esc' }); } }; - const closeModal = () => { + const closeModal = (args) => { setIsClosing(true); - setTimeout(() => handleCancel(), 500); + setTimeout(() => handleCancel(args), closeModalFadeTimeout); }; useEffect(() => { @@ -94,12 +95,12 @@ const Modal = ({ return (
- closeModal()} /> + closeModal({ type: 'icon' })} /> {children} closeModal()} + handleCancel={() => closeModal({ type: 'button' })} handleSubmit={handleConfirm} confirmDisabled={confirmDisabled} hideCancel={hideCancel} @@ -108,7 +109,12 @@ const Modal = ({
{/* Clicking on backdrop closes the modal */} -
closeModal()} /> +
{ + closeModal({ type: 'backdrop' }); + }} + /> ); }; diff --git a/packages/bruno-app/src/components/RequestPane/Auth/index.js b/packages/bruno-app/src/components/RequestPane/Auth/index.js index f07b80f95..314bbb212 100644 --- a/packages/bruno-app/src/components/RequestPane/Auth/index.js +++ b/packages/bruno-app/src/components/RequestPane/Auth/index.js @@ -20,7 +20,7 @@ const Auth = ({ item, collection }) => { }; return ( - +
diff --git a/packages/bruno-app/src/components/RequestPane/GraphQLRequestPane/index.js b/packages/bruno-app/src/components/RequestPane/GraphQLRequestPane/index.js index 45a345a6a..6d4eba2a6 100644 --- a/packages/bruno-app/src/components/RequestPane/GraphQLRequestPane/index.js +++ b/packages/bruno-app/src/components/RequestPane/GraphQLRequestPane/index.js @@ -40,7 +40,7 @@ const GraphQLRequestPane = ({ item, collection, leftPaneWidth, onSchemaLoad, tog loadSchema, isLoading: isSchemaLoading, error: schemaError - } = useGraphqlSchema(url, environment, request, collection.collectionVariables); + } = useGraphqlSchema(url, environment, request, collection); const loadGqlSchema = () => { if (!isSchemaLoading) { diff --git a/packages/bruno-app/src/components/RequestPane/GraphQLRequestPane/useGraphqlSchema.js b/packages/bruno-app/src/components/RequestPane/GraphQLRequestPane/useGraphqlSchema.js index e59127717..e28ea5bc4 100644 --- a/packages/bruno-app/src/components/RequestPane/GraphQLRequestPane/useGraphqlSchema.js +++ b/packages/bruno-app/src/components/RequestPane/GraphQLRequestPane/useGraphqlSchema.js @@ -6,7 +6,7 @@ import { simpleHash } from 'utils/common'; const schemaHashPrefix = 'bruno.graphqlSchema'; -const useGraphqlSchema = (endpoint, environment, request, collectionVariables) => { +const useGraphqlSchema = (endpoint, environment, request, collection) => { const localStorageKey = `${schemaHashPrefix}.${simpleHash(endpoint)}`; const [error, setError] = useState(null); const [isLoading, setIsLoading] = useState(false); @@ -25,7 +25,7 @@ const useGraphqlSchema = (endpoint, environment, request, collectionVariables) = const loadSchema = () => { setIsLoading(true); - fetchGqlSchema(endpoint, environment, request, collectionVariables) + fetchGqlSchema(endpoint, environment, request, collection) .then((res) => res.data) .then((s) => { if (s && s.data) { diff --git a/packages/bruno-app/src/components/RequestPane/QueryUrl/StyledWrapper.js b/packages/bruno-app/src/components/RequestPane/QueryUrl/StyledWrapper.js index 7ec35f33e..2308dec4f 100644 --- a/packages/bruno-app/src/components/RequestPane/QueryUrl/StyledWrapper.js +++ b/packages/bruno-app/src/components/RequestPane/QueryUrl/StyledWrapper.js @@ -32,6 +32,50 @@ const Wrapper = styled.div` position: relative; top: 1px; } + + .tooltip { + position: relative; + display: inline-block; + cursor: pointer; + } + + .tooltip:hover .tooltiptext { + visibility: visible; + opacity: 1; + } + + .tooltiptext { + visibility: hidden; + width: auto; + background-color: ${(props) => props.theme.requestTabs.active.bg}; + color: ${(props) => props.theme.text}; + text-align: center; + border-radius: 4px; + padding: 4px 8px; + position: absolute; + z-index: 1; + bottom: 34px; + left: 50%; + transform: translateX(-50%); + opacity: 0; + transition: opacity 0.3s; + white-space: nowrap; + } + + .tooltiptext::after { + content: ''; + position: absolute; + top: 100%; + left: 50%; + margin-left: -4px; + border-width: 4px; + border-style: solid; + border-color: ${(props) => props.theme.requestTabs.active.bg} transparent transparent transparent; + } + + .shortcut { + font-size: 0.625rem; + } `; export default Wrapper; diff --git a/packages/bruno-app/src/components/RequestPane/QueryUrl/index.js b/packages/bruno-app/src/components/RequestPane/QueryUrl/index.js index f783bb9d5..0a45f1a7d 100644 --- a/packages/bruno-app/src/components/RequestPane/QueryUrl/index.js +++ b/packages/bruno-app/src/components/RequestPane/QueryUrl/index.js @@ -5,8 +5,9 @@ import { requestUrlChanged, updateRequestMethod } from 'providers/ReduxStore/sli import { saveRequest } from 'providers/ReduxStore/slices/collections/actions'; import HttpMethodSelector from './HttpMethodSelector'; import { useTheme } from 'providers/Theme'; -import SendIcon from 'components/Icons/Send'; +import { IconDeviceFloppy, IconArrowRight } from '@tabler/icons'; import SingleLineEditor from 'components/SingleLineEditor'; +import { isMacOS } from 'utils/common/platform'; import StyledWrapper from './StyledWrapper'; const QueryUrl = ({ item, collection, handleRun }) => { @@ -14,6 +15,8 @@ const QueryUrl = ({ item, collection, handleRun }) => { const dispatch = useDispatch(); 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(); + const saveShortcut = isMac ? 'Cmd + S' : 'Ctrl + S'; const [methodSelectorWidth, setMethodSelectorWidth] = useState(90); @@ -22,7 +25,10 @@ const QueryUrl = ({ item, collection, handleRun }) => { setMethodSelectorWidth(el.offsetWidth); }, [method]); - const onSave = () => dispatch(saveRequest(item.uid, collection.uid)); + const onSave = () => { + dispatch(saveRequest(item.uid, collection.uid)); + }; + const onUrlChange = (value) => { dispatch( requestUrlChanged({ @@ -65,7 +71,25 @@ const QueryUrl = ({ item, collection, handleRun }) => { collection={collection} />
- +
{ + e.stopPropagation(); + if (!item.draft) return; + onSave(); + }} + > + + + Save ({saveShortcut}) + +
+
diff --git a/packages/bruno-app/src/components/RequestTabs/RequestTab/ConfirmRequestClose/index.js b/packages/bruno-app/src/components/RequestTabs/RequestTab/ConfirmRequestClose/index.js new file mode 100644 index 000000000..94460cf48 --- /dev/null +++ b/packages/bruno-app/src/components/RequestTabs/RequestTab/ConfirmRequestClose/index.js @@ -0,0 +1,30 @@ +import React from 'react'; +import Modal from 'components/Modal'; + +const ConfirmRequestClose = ({ onCancel, onCloseWithoutSave, onSaveAndClose }) => { + const _handleCancel = ({ type }) => { + if (type === 'button') { + return onCloseWithoutSave(); + } + + return onCancel(); + }; + + return ( + +
You have unsaved changes in you request.
+
+ ); +}; + +export default ConfirmRequestClose; diff --git a/packages/bruno-app/src/components/RequestTabs/RequestTab/index.js b/packages/bruno-app/src/components/RequestTabs/RequestTab/index.js index 9b7b59a30..8fc27e90c 100644 --- a/packages/bruno-app/src/components/RequestTabs/RequestTab/index.js +++ b/packages/bruno-app/src/components/RequestTabs/RequestTab/index.js @@ -1,10 +1,13 @@ -import React from 'react'; +import React, { useState } from 'react'; import get from 'lodash/get'; import { closeTabs } from 'providers/ReduxStore/slices/tabs'; +import { saveRequest } from 'providers/ReduxStore/slices/collections/actions'; +import { deleteRequestDraft } from 'providers/ReduxStore/slices/collections'; import { useDispatch } from 'react-redux'; import { findItemInCollection } from 'utils/collections'; import StyledWrapper from './StyledWrapper'; import RequestTabNotFound from './RequestTabNotFound'; +import ConfirmRequestClose from './ConfirmRequestClose'; import SpecialTab from './SpecialTab'; import { useTheme } from 'providers/Theme'; import darkTheme from 'themes/dark'; @@ -13,6 +16,7 @@ import lightTheme from 'themes/light'; const RequestTab = ({ tab, collection }) => { const dispatch = useDispatch(); const { storedTheme } = useTheme(); + const [showConfirmClose, setShowConfirmClose] = useState(false); const handleCloseClick = (event) => { event.stopPropagation(); @@ -86,6 +90,39 @@ const RequestTab = ({ tab, collection }) => { return ( + {showConfirmClose && ( + setShowConfirmClose(false)} + onCloseWithoutSave={() => { + dispatch( + deleteRequestDraft({ + itemUid: item.uid, + collectionUid: collection.uid + }) + ); + dispatch( + closeTabs({ + tabUids: [tab.uid] + }) + ); + setShowConfirmClose(false); + }} + onSaveAndClose={() => { + dispatch(saveRequest(item.uid, collection.uid)) + .then(() => { + dispatch( + closeTabs({ + tabUids: [tab.uid] + }) + ); + setShowConfirmClose(false); + }) + .catch((err) => { + console.log('err', err); + }); + }} + /> + )}
{method} @@ -94,7 +131,14 @@ const RequestTab = ({ tab, collection }) => { {item.name}
-
handleCloseClick(e)}> +
{ + if (!item.draft) return handleCloseClick(e); + + setShowConfirmClose(true); + }} + > {!item.draft ? ( props.theme.requestTabPanel.responseOverlayBg}; + div.overlay { position: absolute; top: 0; @@ -14,6 +19,11 @@ const StyledWrapper = styled.div` padding-top: 20%; overflow: hidden; text-align: center; + + .loading-icon { + transform: scaleY(-1); + animation: rotateCounterClockwise 1s linear infinite; + } } `; diff --git a/packages/bruno-app/src/components/ResponsePane/Overlay/index.js b/packages/bruno-app/src/components/ResponsePane/Overlay/index.js index 8145a2b50..e5f659862 100644 --- a/packages/bruno-app/src/components/ResponsePane/Overlay/index.js +++ b/packages/bruno-app/src/components/ResponsePane/Overlay/index.js @@ -13,17 +13,17 @@ const ResponseLoadingOverlay = ({ item, collection }) => { }; return ( - +
-
+
- +
-
{getTabPanel(focusedTab.responsePaneTab)}
+
+ {isLoading ? : null} + {getTabPanel(focusedTab.responsePaneTab)} +
); }; diff --git a/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/CloneCollectionItem/index.js b/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/CloneCollectionItem/index.js index 96a1da61d..55c2b86dd 100644 --- a/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/CloneCollectionItem/index.js +++ b/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/CloneCollectionItem/index.js @@ -18,7 +18,7 @@ const CloneCollectionItem = ({ collection, item, onClose }) => { }, validationSchema: Yup.object({ name: Yup.string() - .min(1, 'must be atleast 1 characters') + .min(1, 'must be at least 1 character') .max(50, 'must be 50 characters or less') .required('name is required') }), diff --git a/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/RenameCollectionItem/index.js b/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/RenameCollectionItem/index.js index 9b485e992..97c3399ae 100644 --- a/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/RenameCollectionItem/index.js +++ b/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/RenameCollectionItem/index.js @@ -17,7 +17,7 @@ const RenameCollectionItem = ({ collection, item, onClose }) => { }, validationSchema: Yup.object({ name: Yup.string() - .min(1, 'must be atleast 1 characters') + .min(1, 'must be at least 1 character') .max(50, 'must be 50 characters or less') .required('name is required') }), diff --git a/packages/bruno-app/src/components/Sidebar/Collections/Collection/RenameCollection/index.js b/packages/bruno-app/src/components/Sidebar/Collections/Collection/RenameCollection/index.js index 70311bd75..07a927415 100644 --- a/packages/bruno-app/src/components/Sidebar/Collections/Collection/RenameCollection/index.js +++ b/packages/bruno-app/src/components/Sidebar/Collections/Collection/RenameCollection/index.js @@ -16,7 +16,7 @@ const RenameCollection = ({ collection, onClose }) => { }, validationSchema: Yup.object({ name: Yup.string() - .min(1, 'must be atleast 1 characters') + .min(1, 'must be at least 1 character') .max(50, 'must be 50 characters or less') .required('name is required') }), diff --git a/packages/bruno-app/src/components/Sidebar/CreateCollection/index.js b/packages/bruno-app/src/components/Sidebar/CreateCollection/index.js index bfe59ae86..9f9097637 100644 --- a/packages/bruno-app/src/components/Sidebar/CreateCollection/index.js +++ b/packages/bruno-app/src/components/Sidebar/CreateCollection/index.js @@ -21,11 +21,11 @@ const CreateCollection = ({ onClose }) => { }, validationSchema: Yup.object({ collectionName: Yup.string() - .min(1, 'must be atleast 1 characters') + .min(1, 'must be at least 1 character') .max(50, 'must be 50 characters or less') .required('collection name is required'), collectionFolderName: Yup.string() - .min(1, 'must be atleast 1 characters') + .min(1, 'must be at least 1 character') .max(50, 'must be 50 characters or less') .matches(/^[\w\-. ]+$/, 'Folder name contains invalid characters') .required('folder name is required'), diff --git a/packages/bruno-app/src/components/Sidebar/ImportCollectionLocation/index.js b/packages/bruno-app/src/components/Sidebar/ImportCollectionLocation/index.js index 779c8dfa3..dc75a910b 100644 --- a/packages/bruno-app/src/components/Sidebar/ImportCollectionLocation/index.js +++ b/packages/bruno-app/src/components/Sidebar/ImportCollectionLocation/index.js @@ -16,7 +16,7 @@ const ImportCollectionLocation = ({ onClose, handleSubmit, collectionName }) => }, validationSchema: Yup.object({ collectionLocation: Yup.string() - .min(1, 'must be atleast 1 characters') + .min(1, 'must be at least 1 character') .max(500, 'must be 500 characters or less') .required('name is required') }), diff --git a/packages/bruno-app/src/components/Sidebar/NewFolder/index.js b/packages/bruno-app/src/components/Sidebar/NewFolder/index.js index 9245d7abc..bc13f50df 100644 --- a/packages/bruno-app/src/components/Sidebar/NewFolder/index.js +++ b/packages/bruno-app/src/components/Sidebar/NewFolder/index.js @@ -16,7 +16,7 @@ const NewFolder = ({ collection, item, onClose }) => { }, validationSchema: Yup.object({ folderName: Yup.string() - .min(1, 'must be atleast 1 characters') + .min(1, 'must be at least 1 character') .required('name is required') .test({ name: 'folderName', diff --git a/packages/bruno-app/src/components/Sidebar/NewRequest/index.js b/packages/bruno-app/src/components/Sidebar/NewRequest/index.js index f5753aced..6a753fd97 100644 --- a/packages/bruno-app/src/components/Sidebar/NewRequest/index.js +++ b/packages/bruno-app/src/components/Sidebar/NewRequest/index.js @@ -25,7 +25,7 @@ const NewRequest = ({ collection, item, isEphemeral, onClose }) => { }, validationSchema: Yup.object({ requestName: Yup.string() - .min(1, 'must be atleast 1 characters') + .min(1, 'must be at least 1 character') .required('name is required') .test({ name: 'requestName', diff --git a/packages/bruno-app/src/components/Sidebar/TitleBar/index.js b/packages/bruno-app/src/components/Sidebar/TitleBar/index.js index daaf1f452..ebf8c608d 100644 --- a/packages/bruno-app/src/components/Sidebar/TitleBar/index.js +++ b/packages/bruno-app/src/components/Sidebar/TitleBar/index.js @@ -18,6 +18,7 @@ const TitleBar = () => { const [importCollectionModalOpen, setImportCollectionModalOpen] = useState(false); const [importCollectionLocationModalOpen, setImportCollectionLocationModalOpen] = useState(false); const dispatch = useDispatch(); + const { ipcRenderer } = window; const handleImportCollection = (collection) => { setImportedCollection(collection); @@ -50,6 +51,10 @@ const TitleBar = () => { ); }; + const openDevTools = () => { + ipcRenderer.invoke('renderer:open-devtools'); + }; + return ( {createCollectionModalOpen ? setCreateCollectionModalOpen(false)} /> : null} @@ -104,6 +109,15 @@ const TitleBar = () => { > Import Collection
+
{ + menuDropdownTippyRef.current.hide(); + openDevTools(); + }} + > + Devtools +
diff --git a/packages/bruno-app/src/components/Sidebar/index.js b/packages/bruno-app/src/components/Sidebar/index.js index 25156be84..0766908cd 100644 --- a/packages/bruno-app/src/components/Sidebar/index.js +++ b/packages/bruno-app/src/components/Sidebar/index.js @@ -105,7 +105,7 @@ const Sidebar = () => { Star
-
v0.21.0
+
v0.21.1
diff --git a/packages/bruno-app/src/globalStyles.js b/packages/bruno-app/src/globalStyles.js index 7cf517bdf..34e5e70aa 100644 --- a/packages/bruno-app/src/globalStyles.js +++ b/packages/bruno-app/src/globalStyles.js @@ -129,6 +129,24 @@ const GlobalStyle = createGlobalStyle` } } + @keyframes rotateClockwise { + 0% { + transform: scaleY(-1) rotate(0deg); + } + 100% { + transform: scaleY(-1) rotate(360deg); + } + } + + @keyframes rotateCounterClockwise { + 0% { + transform: scaleY(-1) rotate(360deg); + } + 100% { + transform: scaleY(-1) rotate(0deg); + } + } + // codemirror .CodeMirror { .cm-variable-valid { 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 c1ec2ff3b..42b8318ac 100644 --- a/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js +++ b/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js @@ -82,8 +82,12 @@ export const saveRequest = (itemUid, collectionUid) => (dispatch, getState) => { itemSchema .validate(itemToSave) .then(() => ipcRenderer.invoke('renderer:save-request', item.pathname, itemToSave)) + .then(() => toast.success('Request saved successfully')) .then(resolve) - .catch(reject); + .catch((err) => { + toast.error('Failed to save request!'); + reject(err); + }); }); }; diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js b/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js index 31cf6d6ca..f4eebec66 100644 --- a/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js +++ b/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js @@ -258,6 +258,17 @@ export const collectionsSlice = createSlice({ } } }, + deleteRequestDraft: (state, action) => { + const collection = findCollectionByUid(state.collections, action.payload.collectionUid); + + if (collection) { + const item = findItemInCollection(collection, action.payload.itemUid); + + if (item && item.draft) { + item.draft = null; + } + } + }, newEphemeralHttpRequest: (state, action) => { const collection = findCollectionByUid(state.collections, action.payload.collectionUid); @@ -1103,7 +1114,6 @@ export const collectionsSlice = createSlice({ const { cancelTokenUid } = action.payload; item.requestUid = requestUid; item.requestState = 'queued'; - item.response = null; item.cancelTokenUid = cancelTokenUid; } @@ -1224,6 +1234,7 @@ export const { requestCancelled, responseReceived, saveRequest, + deleteRequestDraft, newEphemeralHttpRequest, collectionClicked, collectionFolderClicked, diff --git a/packages/bruno-app/src/styles/globals.css b/packages/bruno-app/src/styles/globals.css index fb8eb5b5f..ee784ff1f 100644 --- a/packages/bruno-app/src/styles/globals.css +++ b/packages/bruno-app/src/styles/globals.css @@ -53,3 +53,9 @@ body::-webkit-scrollbar-thumb, background-color: #cdcdcd; border-radius: 5rem; } + +/* making all the checkboxes and radios bigger */ +input[type='checkbox'], +input[type='radio'] { + transform: scale(1.25); +} diff --git a/packages/bruno-app/src/themes/dark.js b/packages/bruno-app/src/themes/dark.js index f93fc646a..3dda2505d 100644 --- a/packages/bruno-app/src/themes/dark.js +++ b/packages/bruno-app/src/themes/dark.js @@ -109,7 +109,8 @@ const darkTheme = { responseSendIcon: '#555', responseStatus: '#ccc', responseOk: '#8cd656', - responseError: '#f06f57' + responseError: '#f06f57', + responseOverlayBg: 'rgba(30, 30, 30, 0.6)' }, collection: { diff --git a/packages/bruno-app/src/themes/light.js b/packages/bruno-app/src/themes/light.js index b461f44de..5b9f1a8bc 100644 --- a/packages/bruno-app/src/themes/light.js +++ b/packages/bruno-app/src/themes/light.js @@ -109,7 +109,8 @@ const lightTheme = { responseSendIcon: 'rgb(209, 213, 219)', responseStatus: 'rgb(117 117 117)', responseOk: '#047857', - responseError: 'rgb(185, 28, 28)' + responseError: 'rgb(185, 28, 28)', + responseOverlayBg: 'rgba(255, 255, 255, 0.6)' }, collection: { diff --git a/packages/bruno-app/src/utils/common/platform.js b/packages/bruno-app/src/utils/common/platform.js index e49a66ec9..771daaf14 100644 --- a/packages/bruno-app/src/utils/common/platform.js +++ b/packages/bruno-app/src/utils/common/platform.js @@ -41,3 +41,10 @@ export const isWindowsOS = () => { return osFamily.includes('windows'); }; + +export const isMacOS = () => { + const os = platform.os; + const osFamily = os.family.toLowerCase(); + + return osFamily.includes('os x'); +}; diff --git a/packages/bruno-app/src/utils/network/index.js b/packages/bruno-app/src/utils/network/index.js index 2c5c3a1d3..042546854 100644 --- a/packages/bruno-app/src/utils/network/index.js +++ b/packages/bruno-app/src/utils/network/index.js @@ -29,14 +29,11 @@ const sendHttpRequest = async (item, collection, environment, collectionVariable }); }; -export const fetchGqlSchema = async (endpoint, environment, request, collectionVariables) => { +export const fetchGqlSchema = async (endpoint, environment, request, collection) => { return new Promise((resolve, reject) => { const { ipcRenderer } = window; - ipcRenderer - .invoke('fetch-gql-schema', endpoint, environment, request, collectionVariables) - .then(resolve) - .catch(reject); + ipcRenderer.invoke('fetch-gql-schema', endpoint, environment, request, collection).then(resolve).catch(reject); }); }; diff --git a/packages/bruno-electron/package.json b/packages/bruno-electron/package.json index 6cdd6914d..033d4b696 100644 --- a/packages/bruno-electron/package.json +++ b/packages/bruno-electron/package.json @@ -1,5 +1,5 @@ { - "version": "v0.21.0", + "version": "v0.21.1", "name": "bruno", "description": "Opensource API Client for Exploring and Testing APIs", "homepage": "https://www.usebruno.com", diff --git a/packages/bruno-electron/src/app/menu-template.js b/packages/bruno-electron/src/app/menu-template.js index 2efd93cde..6b4707729 100644 --- a/packages/bruno-electron/src/app/menu-template.js +++ b/packages/bruno-electron/src/app/menu-template.js @@ -24,7 +24,10 @@ const template = [ { role: 'cut' }, { role: 'copy' }, { role: 'paste' }, - { role: 'selectAll' } + { role: 'selectAll' }, + { type: 'separator' }, + { role: 'hide' }, + { role: 'hideOthers' } ] }, { diff --git a/packages/bruno-electron/src/app/watcher.js b/packages/bruno-electron/src/app/watcher.js index 96822ec64..6b5d57381 100644 --- a/packages/bruno-electron/src/app/watcher.js +++ b/packages/bruno-electron/src/app/watcher.js @@ -2,8 +2,8 @@ const _ = require('lodash'); const fs = require('fs'); const path = require('path'); const chokidar = require('chokidar'); -const { hasBruExtension, writeFile } = require('../utils/filesystem'); -const { bruToEnvJson, envJsonToBru, bruToJson, jsonToBru } = require('../bru'); +const { hasBruExtension } = require('../utils/filesystem'); +const { bruToEnvJson, bruToJson } = require('../bru'); const { dotenvToJson } = require('@usebruno/lang'); const { uuid } = require('../utils/common'); @@ -15,13 +15,6 @@ const EnvironmentSecretsStore = require('../store/env-secrets'); const environmentSecretsStore = new EnvironmentSecretsStore(); -const isJsonEnvironmentConfig = (pathname, collectionPath) => { - const dirname = path.dirname(pathname); - const basename = path.basename(pathname); - - return dirname === collectionPath && basename === 'environments.json'; -}; - const isDotEnvFile = (pathname, collectionPath) => { const dirname = path.dirname(pathname); const basename = path.basename(pathname); @@ -198,32 +191,6 @@ const add = async (win, pathname, collectionUid, collectionPath) => { } } - if (isJsonEnvironmentConfig(pathname, collectionPath)) { - try { - const dirname = path.dirname(pathname); - const bruContent = fs.readFileSync(pathname, 'utf8'); - - const jsonData = JSON.parse(bruContent); - - const envDirectory = path.join(dirname, 'environments'); - if (!fs.existsSync(envDirectory)) { - fs.mkdirSync(envDirectory); - } - - for (const env of jsonData) { - const bruEnvFilename = path.join(envDirectory, `${env.name}.bru`); - const bruContent = envJsonToBru(env); - await writeFile(bruEnvFilename, bruContent); - } - - await fs.unlinkSync(pathname); - } catch (err) { - // do nothing - } - - return; - } - if (isBruEnvironmentConfig(pathname, collectionPath)) { return addEnvironmentFile(win, pathname, collectionUid, collectionPath); } diff --git a/packages/bruno-electron/src/bru/index.js b/packages/bruno-electron/src/bru/index.js index a28c04a7b..ad4299593 100644 --- a/packages/bruno-electron/src/bru/index.js +++ b/packages/bruno-electron/src/bru/index.js @@ -1,6 +1,5 @@ const _ = require('lodash'); const { bruToJsonV2, jsonToBruV2, bruToEnvJsonV2, envJsonToBruV2 } = require('@usebruno/lang'); -const { each } = require('lodash'); const bruToEnvJson = (bru) => { try { @@ -10,7 +9,7 @@ const bruToEnvJson = (bru) => { // this need to be evaluated and safely removed // i don't see it being used in schema validation if (json && json.variables && json.variables.length) { - each(json.variables, (v) => (v.type = 'text')); + _.each(json.variables, (v) => (v.type = 'text')); } return json; diff --git a/packages/bruno-electron/src/index.js b/packages/bruno-electron/src/index.js index 3f67b8a96..5e9916ef0 100644 --- a/packages/bruno-electron/src/index.js +++ b/packages/bruno-electron/src/index.js @@ -9,6 +9,7 @@ const LastOpenedCollections = require('./store/last-opened-collections'); const registerNetworkIpc = require('./ipc/network'); const registerCollectionsIpc = require('./ipc/collection'); const Watcher = require('./app/watcher'); +const { loadWindowState, saveWindowState } = require('./utils/window'); const lastOpenedCollections = new LastOpenedCollections(); @@ -27,9 +28,13 @@ let watcher; // Prepare the renderer once the app is ready app.on('ready', async () => { + const { x, y, width, height } = loadWindowState(); + mainWindow = new BrowserWindow({ - width: 1280, - height: 768, + x, + y, + width, + height, webPreferences: { nodeIntegration: true, contextIsolation: true, @@ -54,6 +59,9 @@ app.on('ready', async () => { mainWindow.loadURL(url); watcher = new Watcher(); + mainWindow.on('resize', () => saveWindowState(mainWindow)); + mainWindow.on('move', () => saveWindowState(mainWindow)); + mainWindow.webContents.on('new-window', function (e, url) { e.preventDefault(); require('electron').shell.openExternal(url); diff --git a/packages/bruno-electron/src/ipc/collection.js b/packages/bruno-electron/src/ipc/collection.js index 864aff82e..03a15305b 100644 --- a/packages/bruno-electron/src/ipc/collection.js +++ b/packages/bruno-electron/src/ipc/collection.js @@ -486,6 +486,10 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection return Promise.reject(error); } }); + + ipcMain.handle('renderer:open-devtools', async () => { + mainWindow.webContents.openDevTools(); + }); }; const registerMainEventHandlers = (mainWindow, watcher, lastOpenedCollections) => { diff --git a/packages/bruno-electron/src/ipc/network/index.js b/packages/bruno-electron/src/ipc/network/index.js index 0586054d1..a0b66099c 100644 --- a/packages/bruno-electron/src/ipc/network/index.js +++ b/packages/bruno-electron/src/ipc/network/index.js @@ -469,7 +469,7 @@ const registerNetworkIpc = (mainWindow) => { }); }); - ipcMain.handle('fetch-gql-schema', async (event, endpoint, environment, request, collectionVariables) => { + ipcMain.handle('fetch-gql-schema', async (event, endpoint, environment, request, collection) => { try { const envVars = getEnvVars(environment); const preparedRequest = prepareGqlIntrospectionRequest(endpoint, envVars, request); @@ -483,7 +483,8 @@ const registerNetworkIpc = (mainWindow) => { }); } - interpolateVars(preparedRequest, envVars, collectionVariables); + const processEnvVars = getProcessEnvVars(collection.uid); + interpolateVars(preparedRequest, envVars, collection.collectionVariables, processEnvVars); const response = await axios(preparedRequest); diff --git a/packages/bruno-electron/src/ipc/network/prepare-gql-introspection-request.js b/packages/bruno-electron/src/ipc/network/prepare-gql-introspection-request.js index d41be8f4c..4a1e41c88 100644 --- a/packages/bruno-electron/src/ipc/network/prepare-gql-introspection-request.js +++ b/packages/bruno-electron/src/ipc/network/prepare-gql-introspection-request.js @@ -1,16 +1,12 @@ -const Mustache = require('mustache'); +const Handlebars = require('handlebars'); const { getIntrospectionQuery } = require('graphql'); const { get } = require('lodash'); -// override the default escape function to prevent escaping -Mustache.escape = function (value) { - return value; -}; - const prepareGqlIntrospectionRequest = (endpoint, envVars, request) => { if (endpoint && endpoint.length) { - endpoint = Mustache.render(endpoint, envVars); + endpoint = Handlebars.compile(endpoint, { noEscape: true })(envVars); } + const introspectionQuery = getIntrospectionQuery(); const queryParams = { query: introspectionQuery @@ -20,6 +16,7 @@ const prepareGqlIntrospectionRequest = (endpoint, envVars, request) => { method: 'POST', url: endpoint, headers: { + ...mapHeaders(request.headers), Accept: 'application/json', 'Content-Type': 'application/json' }, @@ -42,4 +39,10 @@ const prepareGqlIntrospectionRequest = (endpoint, envVars, request) => { return axiosRequest; }; +const mapHeaders = (headers) => { + const entries = headers.filter((header) => header.enabled).map(({ name, value }) => [name, value]); + + return Object.fromEntries(entries); +}; + module.exports = prepareGqlIntrospectionRequest; diff --git a/packages/bruno-electron/src/store/window-state.js b/packages/bruno-electron/src/store/window-state.js new file mode 100644 index 000000000..bb0a61b64 --- /dev/null +++ b/packages/bruno-electron/src/store/window-state.js @@ -0,0 +1,31 @@ +const _ = require('lodash'); +const Store = require('electron-store'); + +const DEFAULT_WINDOW_WIDTH = 1280; +const DEFAULT_WINDOW_HEIGHT = 768; + +class WindowStateStore { + constructor() { + this.store = new Store({ + name: 'preferences', + clearInvalidConfig: true + }); + } + + getBounds() { + return ( + this.store.get('window-bounds') || { + x: 0, + y: 0, + width: DEFAULT_WINDOW_WIDTH, + height: DEFAULT_WINDOW_HEIGHT + } + ); + } + + setBounds(bounds) { + this.store.set('window-bounds', bounds); + } +} + +module.exports = WindowStateStore; diff --git a/packages/bruno-electron/src/utils/window.js b/packages/bruno-electron/src/utils/window.js new file mode 100644 index 000000000..d824141d3 --- /dev/null +++ b/packages/bruno-electron/src/utils/window.js @@ -0,0 +1,53 @@ +const { screen } = require('electron'); +const WindowStateStore = require('../store/window-state'); + +const windowStateStore = new WindowStateStore(); + +const DEFAULT_WINDOW_WIDTH = 1280; +const DEFAULT_WINDOW_HEIGHT = 768; + +const loadWindowState = () => { + const bounds = windowStateStore.getBounds(); + + const positionValid = isPositionValid(bounds); + const sizeValid = isSizeValid(bounds); + + return { + x: bounds.x && positionValid ? bounds.x : undefined, + y: bounds.y && positionValid ? bounds.y : undefined, + width: bounds.width && sizeValid ? bounds.width : DEFAULT_WINDOW_WIDTH, + height: bounds.height && sizeValid ? bounds.height : DEFAULT_WINDOW_HEIGHT + }; +}; + +const saveWindowState = (window) => { + const bounds = window.getBounds(); + + windowStateStore.setBounds(bounds); +}; + +const isPositionValid = (bounds) => { + const area = getArea(bounds); + + return ( + bounds.x >= area.x && + bounds.y >= area.y && + bounds.x + bounds.width <= area.x + area.width && + bounds.y + bounds.height <= area.y + area.height + ); +}; + +const isSizeValid = (bounds) => { + const area = getArea(bounds); + + return bounds.width <= area.width && bounds.height <= area.height; +}; + +const getArea = (bounds) => { + return screen.getDisplayMatching(bounds).workArea; +}; + +module.exports = { + loadWindowState, + saveWindowState +}; diff --git a/packages/bruno-js/src/runtime/assert-runtime.js b/packages/bruno-js/src/runtime/assert-runtime.js index f0f84fbc0..a9588263a 100644 --- a/packages/bruno-js/src/runtime/assert-runtime.js +++ b/packages/bruno-js/src/runtime/assert-runtime.js @@ -268,7 +268,7 @@ class AssertRuntime { expect(lhs).to.endWith(rhs); break; case 'between': - const [min, max] = value.split(','); + const [min, max] = rhs; expect(lhs).to.be.within(min, max); break; case 'isEmpty': diff --git a/packages/bruno-lang/v2/src/collectionBruToJson.js b/packages/bruno-lang/v2/src/collectionBruToJson.js new file mode 100644 index 000000000..d78f752c0 --- /dev/null +++ b/packages/bruno-lang/v2/src/collectionBruToJson.js @@ -0,0 +1,273 @@ +const ohm = require('ohm-js'); +const _ = require('lodash'); +const { outdentString } = require('../../v1/src/utils'); + +const grammar = ohm.grammar(`Bru { + BruFile = (meta | query | headers | auth | auths | vars | script | tests | docs)* + auths = authbasic | authbearer + + nl = "\\r"? "\\n" + st = " " | "\\t" + stnl = st | nl + tagend = nl "}" + optionalnl = ~tagend nl + keychar = ~(tagend | st | nl | ":") any + valuechar = ~(nl | tagend) any + + // Dictionary Blocks + dictionary = st* "{" pairlist? tagend + pairlist = optionalnl* pair (~tagend stnl* pair)* (~tagend space)* + pair = st* key st* ":" st* value st* + key = keychar* + value = valuechar* + + // Text Blocks + textblock = textline (~tagend nl textline)* + textline = textchar* + textchar = ~nl any + + meta = "meta" dictionary + + auth = "auth" dictionary + + headers = "headers" dictionary + + query = "query" dictionary + + vars = varsreq | varsres + varsreq = "vars:pre-request" dictionary + varsres = "vars:post-response" dictionary + + authbasic = "auth:basic" dictionary + authbearer = "auth:bearer" dictionary + + script = scriptreq | scriptres + scriptreq = "script:pre-request" st* "{" nl* textblock tagend + scriptres = "script:post-response" st* "{" nl* textblock tagend + tests = "tests" st* "{" nl* textblock tagend + docs = "docs" st* "{" nl* textblock tagend +}`); + +const mapPairListToKeyValPairs = (pairList = [], parseEnabled = true) => { + if (!pairList.length) { + return []; + } + return _.map(pairList[0], (pair) => { + let name = _.keys(pair)[0]; + let value = pair[name]; + + if (!parseEnabled) { + return { + name, + value + }; + } + + let enabled = true; + if (name && name.length && name.charAt(0) === '~') { + name = name.slice(1); + enabled = false; + } + + return { + name, + value, + enabled + }; + }); +}; + +const concatArrays = (objValue, srcValue) => { + if (_.isArray(objValue) && _.isArray(srcValue)) { + return objValue.concat(srcValue); + } +}; + +const mapPairListToKeyValPair = (pairList = []) => { + if (!pairList || !pairList.length) { + return {}; + } + + return _.merge({}, ...pairList[0]); +}; + +const sem = grammar.createSemantics().addAttribute('ast', { + BruFile(tags) { + if (!tags || !tags.ast || !tags.ast.length) { + return {}; + } + + return _.reduce( + tags.ast, + (result, item) => { + return _.mergeWith(result, item, concatArrays); + }, + {} + ); + }, + dictionary(_1, _2, pairlist, _3) { + return pairlist.ast; + }, + pairlist(_1, pair, _2, rest, _3) { + return [pair.ast, ...rest.ast]; + }, + pair(_1, key, _2, _3, _4, value, _5) { + let res = {}; + res[key.ast] = value.ast ? value.ast.trim() : ''; + return res; + }, + key(chars) { + return chars.sourceString ? chars.sourceString.trim() : ''; + }, + value(chars) { + return chars.sourceString ? chars.sourceString.trim() : ''; + }, + textblock(line, _1, rest) { + return [line.ast, ...rest.ast].join('\n'); + }, + textline(chars) { + return chars.sourceString; + }, + textchar(char) { + return char.sourceString; + }, + nl(_1, _2) { + return ''; + }, + st(_) { + return ''; + }, + tagend(_1, _2) { + return ''; + }, + _iter(...elements) { + return elements.map((e) => e.ast); + }, + meta(_1, dictionary) { + let meta = mapPairListToKeyValPair(dictionary.ast) || {}; + + meta.type = 'collection'; + + return { + meta + }; + }, + auth(_1, dictionary) { + let auth = mapPairListToKeyValPair(dictionary.ast) || {}; + + return { + auth: { + mode: auth ? auth.mode : 'none' + } + }; + }, + query(_1, dictionary) { + return { + query: mapPairListToKeyValPairs(dictionary.ast) + }; + }, + headers(_1, dictionary) { + return { + headers: mapPairListToKeyValPairs(dictionary.ast) + }; + }, + authbasic(_1, dictionary) { + const auth = mapPairListToKeyValPairs(dictionary.ast, false); + const usernameKey = _.find(auth, { name: 'username' }); + const passwordKey = _.find(auth, { name: 'password' }); + const username = usernameKey ? usernameKey.value : ''; + const password = passwordKey ? passwordKey.value : ''; + return { + auth: { + basic: { + username, + password + } + } + }; + }, + authbearer(_1, dictionary) { + const auth = mapPairListToKeyValPairs(dictionary.ast, false); + const tokenKey = _.find(auth, { name: 'token' }); + const token = tokenKey ? tokenKey.value : ''; + return { + auth: { + bearer: { + token + } + } + }; + }, + varsreq(_1, dictionary) { + const vars = mapPairListToKeyValPairs(dictionary.ast); + _.each(vars, (v) => { + let name = v.name; + if (name && name.length && name.charAt(0) === '@') { + v.name = name.slice(1); + v.local = true; + } else { + v.local = false; + } + }); + + return { + vars: { + req: vars + } + }; + }, + varsres(_1, dictionary) { + const vars = mapPairListToKeyValPairs(dictionary.ast); + _.each(vars, (v) => { + let name = v.name; + if (name && name.length && name.charAt(0) === '@') { + v.name = name.slice(1); + v.local = true; + } else { + v.local = false; + } + }); + + return { + vars: { + res: vars + } + }; + }, + scriptreq(_1, _2, _3, _4, textblock, _5) { + return { + script: { + req: outdentString(textblock.sourceString) + } + }; + }, + scriptres(_1, _2, _3, _4, textblock, _5) { + return { + script: { + res: outdentString(textblock.sourceString) + } + }; + }, + tests(_1, _2, _3, _4, textblock, _5) { + return { + tests: outdentString(textblock.sourceString) + }; + }, + docs(_1, _2, _3, _4, textblock, _5) { + return { + docs: outdentString(textblock.sourceString) + }; + } +}); + +const parser = (input) => { + const match = grammar.match(input); + + if (match.succeeded()) { + return sem(match).ast; + } else { + throw new Error(match.message); + } +}; + +module.exports = parser; diff --git a/packages/bruno-lang/v2/src/jsonToCollectionBru.js b/packages/bruno-lang/v2/src/jsonToCollectionBru.js new file mode 100644 index 000000000..f20fbc680 --- /dev/null +++ b/packages/bruno-lang/v2/src/jsonToCollectionBru.js @@ -0,0 +1,185 @@ +const _ = require('lodash'); + +const { indentString } = require('../../v1/src/utils'); + +const enabled = (items = []) => items.filter((item) => item.enabled); +const disabled = (items = []) => items.filter((item) => !item.enabled); + +// remove the last line if two new lines are found +const stripLastLine = (text) => { + if (!text || !text.length) return text; + + return text.replace(/(\r?\n)$/, ''); +}; + +const jsonToBru = (json) => { + const { meta, query, headers, auth, script, tests, vars, docs } = json; + + let bru = ''; + + if (meta) { + bru += 'meta {\n'; + for (const key in meta) { + bru += ` ${key}: ${meta[key]}\n`; + } + bru += '}\n\n'; + } + + if (query && query.length) { + bru += 'query {'; + if (enabled(query).length) { + bru += `\n${indentString( + enabled(query) + .map((item) => `${item.name}: ${item.value}`) + .join('\n') + )}`; + } + + if (disabled(query).length) { + bru += `\n${indentString( + disabled(query) + .map((item) => `~${item.name}: ${item.value}`) + .join('\n') + )}`; + } + + bru += '\n}\n\n'; + } + + if (headers && headers.length) { + bru += 'headers {'; + if (enabled(headers).length) { + bru += `\n${indentString( + enabled(headers) + .map((item) => `${item.name}: ${item.value}`) + .join('\n') + )}`; + } + + if (disabled(headers).length) { + bru += `\n${indentString( + disabled(headers) + .map((item) => `~${item.name}: ${item.value}`) + .join('\n') + )}`; + } + + bru += '\n}\n\n'; + } + + if (auth && auth.mode) { + bru += `auth { +${indentString(`mode: ${auth.mode}`)} +} + +`; + } + + if (auth && auth.basic) { + bru += `auth:basic { +${indentString(`username: ${auth.basic.username}`)} +${indentString(`password: ${auth.basic.password}`)} +} + +`; + } + + if (auth && auth.bearer) { + bru += `auth:bearer { +${indentString(`token: ${auth.bearer.token}`)} +} + +`; + } + + let reqvars = _.get(vars, 'req'); + let resvars = _.get(vars, 'res'); + if (reqvars && reqvars.length) { + const varsEnabled = _.filter(reqvars, (v) => v.enabled && !v.local); + const varsDisabled = _.filter(reqvars, (v) => !v.enabled && !v.local); + const varsLocalEnabled = _.filter(reqvars, (v) => v.enabled && v.local); + const varsLocalDisabled = _.filter(reqvars, (v) => !v.enabled && v.local); + + bru += `vars:pre-request {`; + + if (varsEnabled.length) { + bru += `\n${indentString(varsEnabled.map((item) => `${item.name}: ${item.value}`).join('\n'))}`; + } + + if (varsLocalEnabled.length) { + bru += `\n${indentString(varsLocalEnabled.map((item) => `@${item.name}: ${item.value}`).join('\n'))}`; + } + + if (varsDisabled.length) { + bru += `\n${indentString(varsDisabled.map((item) => `~${item.name}: ${item.value}`).join('\n'))}`; + } + + if (varsLocalDisabled.length) { + bru += `\n${indentString(varsLocalDisabled.map((item) => `~@${item.name}: ${item.value}`).join('\n'))}`; + } + + bru += '\n}\n\n'; + } + if (resvars && resvars.length) { + const varsEnabled = _.filter(resvars, (v) => v.enabled && !v.local); + const varsDisabled = _.filter(resvars, (v) => !v.enabled && !v.local); + const varsLocalEnabled = _.filter(resvars, (v) => v.enabled && v.local); + const varsLocalDisabled = _.filter(resvars, (v) => !v.enabled && v.local); + + bru += `vars:post-response {`; + + if (varsEnabled.length) { + bru += `\n${indentString(varsEnabled.map((item) => `${item.name}: ${item.value}`).join('\n'))}`; + } + + if (varsLocalEnabled.length) { + bru += `\n${indentString(varsLocalEnabled.map((item) => `@${item.name}: ${item.value}`).join('\n'))}`; + } + + if (varsDisabled.length) { + bru += `\n${indentString(varsDisabled.map((item) => `~${item.name}: ${item.value}`).join('\n'))}`; + } + + if (varsLocalDisabled.length) { + bru += `\n${indentString(varsLocalDisabled.map((item) => `~@${item.name}: ${item.value}`).join('\n'))}`; + } + + bru += '\n}\n\n'; + } + + if (script && script.req && script.req.length) { + bru += `script:pre-request { +${indentString(script.req)} +} + +`; + } + + if (script && script.res && script.res.length) { + bru += `script:post-response { +${indentString(script.res)} +} + +`; + } + + if (tests && tests.length) { + bru += `tests { +${indentString(tests)} +} + +`; + } + + if (docs && docs.length) { + bru += `docs { +${indentString(docs)} +} + +`; + } + + return stripLastLine(bru); +}; + +module.exports = jsonToBru; diff --git a/packages/bruno-lang/v2/tests/collection.spec.js b/packages/bruno-lang/v2/tests/collection.spec.js new file mode 100644 index 000000000..4bdb7f9dc --- /dev/null +++ b/packages/bruno-lang/v2/tests/collection.spec.js @@ -0,0 +1,24 @@ +const fs = require('fs'); +const path = require('path'); +const collectionBruToJson = require('../src/collectionBruToJson'); +const jsonToCollectionBru = require('../src/jsonToCollectionBru'); + +describe('collectionBruToJson', () => { + it('should parse the collection bru file', () => { + const input = fs.readFileSync(path.join(__dirname, 'fixtures', 'collection.bru'), 'utf8'); + const expected = require('./fixtures/collection.json'); + const output = collectionBruToJson(input); + + expect(output).toEqual(expected); + }); +}); + +describe('jsonToCollectionBru', () => { + it('should convert the collection json to bru', () => { + const input = require('./fixtures/collection.json'); + const expected = fs.readFileSync(path.join(__dirname, 'fixtures', 'collection.bru'), 'utf8'); + const output = jsonToCollectionBru(input); + + expect(output).toEqual(expected); + }); +}); diff --git a/packages/bruno-lang/v2/tests/fixtures/collection.bru b/packages/bruno-lang/v2/tests/fixtures/collection.bru new file mode 100644 index 000000000..a02be30cb --- /dev/null +++ b/packages/bruno-lang/v2/tests/fixtures/collection.bru @@ -0,0 +1,43 @@ +meta { + type: collection +} + +headers { + content-type: application/json + Authorization: Bearer 123 + ~transaction-id: {{transactionId}} +} + +auth { + mode: none +} + +auth:basic { + username: john + password: secret +} + +auth:bearer { + token: 123 +} + +vars:pre-request { + departingDate: 2020-01-01 + ~returningDate: 2020-01-02 +} + +vars:post-response { + ~transactionId: $res.body.transactionId +} + +script:pre-request { + console.log("In Collection pre Request Script"); +} + +script:post-response { + console.log("In Collection post Request Script"); +} + +docs { + This request needs auth token to be set in the headers. +} diff --git a/packages/bruno-lang/v2/tests/fixtures/collection.json b/packages/bruno-lang/v2/tests/fixtures/collection.json new file mode 100644 index 000000000..de827d11e --- /dev/null +++ b/packages/bruno-lang/v2/tests/fixtures/collection.json @@ -0,0 +1,61 @@ +{ + "meta": { + "type": "collection" + }, + "headers": [ + { + "name": "content-type", + "value": "application/json", + "enabled": true + }, + { + "name": "Authorization", + "value": "Bearer 123", + "enabled": true + }, + { + "name": "transaction-id", + "value": "{{transactionId}}", + "enabled": false + } + ], + "auth": { + "mode": "none", + "basic": { + "username": "john", + "password": "secret" + }, + "bearer": { + "token": "123" + } + }, + "vars": { + "req": [ + { + "name": "departingDate", + "value": "2020-01-01", + "enabled": true, + "local": false + }, + { + "name": "returningDate", + "value": "2020-01-02", + "enabled": false, + "local": false + } + ], + "res": [ + { + "name": "transactionId", + "value": "$res.body.transactionId", + "enabled": false, + "local": false + } + ] + }, + "script": { + "req": "console.log(\"In Collection pre Request Script\");", + "res": "console.log(\"In Collection post Request Script\");" + }, + "docs": "This request needs auth token to be set in the headers." +} diff --git a/packages/bruno-schema/src/collections/index.js b/packages/bruno-schema/src/collections/index.js index 81cd2528b..337f0147b 100644 --- a/packages/bruno-schema/src/collections/index.js +++ b/packages/bruno-schema/src/collections/index.js @@ -123,7 +123,7 @@ const itemSchema = Yup.object({ uid: uidSchema, type: Yup.string().oneOf(['http-request', 'graphql-request', 'folder']).required('type is required'), seq: Yup.number().min(1), - name: Yup.string().min(1, 'name must be atleast 1 characters').required('name is required'), + name: Yup.string().min(1, 'name must be at least 1 character').required('name is required'), request: requestSchema.when('type', { is: (type) => ['http-request', 'graphql-request'].includes(type), then: (schema) => schema.required('request is required when item-type is request') @@ -138,7 +138,7 @@ const itemSchema = Yup.object({ const collectionSchema = Yup.object({ version: Yup.string().oneOf(['1']).required('version is required'), uid: uidSchema, - name: Yup.string().min(1, 'name must be atleast 1 characters').required('name is required'), + name: Yup.string().min(1, 'name must be at least 1 character').required('name is required'), items: Yup.array().of(itemSchema), activeEnvironmentUid: Yup.string() .length(21, 'activeEnvironmentUid must be 21 characters in length') diff --git a/packages/bruno-schema/src/collections/itemSchema.spec.js b/packages/bruno-schema/src/collections/itemSchema.spec.js index a949f3c2b..8c46bed2c 100644 --- a/packages/bruno-schema/src/collections/itemSchema.spec.js +++ b/packages/bruno-schema/src/collections/itemSchema.spec.js @@ -34,7 +34,7 @@ describe('Item Schema Validation', () => { return Promise.all([ expect(itemSchema.validate(item)).rejects.toEqual( - validationErrorWithMessages('name must be atleast 1 characters') + validationErrorWithMessages('name must be at least 1 character') ) ]); });