diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 64c8eaed87..fdad25a3cd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,18 +6,18 @@ on: branches: - '**' env: - NODE_VERSION: 16.10.0 + NODE_VERSION: 18.9.0 jobs: check-ci: name: Node Engine Check timeout-minutes: 15 - runs-on: ubuntu-18.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Use Node.js ${{ env.NODE_VERSION }} uses: actions/setup-node@v1 with: - node-version: ${{ env.node-version }} + node-version: ${{ env.NODE_VERSION }} - name: Cache Node.js modules uses: actions/cache@v2 with: @@ -32,13 +32,13 @@ jobs: check-lint: name: Lint timeout-minutes: 15 - runs-on: ubuntu-18.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Use Node.js ${{ env.NODE_VERSION }} uses: actions/setup-node@v1 with: - node-version: ${{ env.node-version }} + node-version: ${{ env.NODE_VERSION }} - name: Cache Node.js modules uses: actions/cache@v2 with: @@ -52,13 +52,13 @@ jobs: check-circular: name: Circular Dependencies timeout-minutes: 5 - runs-on: ubuntu-18.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Use Node.js ${{ env.NODE_VERSION }} uses: actions/setup-node@v1 with: - node-version: ${{ env.node-version }} + node-version: ${{ env.NODE_VERSION }} - name: Cache Node.js modules uses: actions/cache@v2 with: @@ -86,7 +86,7 @@ jobs: fail-fast: false name: ${{ matrix.name }} timeout-minutes: 15 - runs-on: ubuntu-18.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Set up QEMU @@ -100,7 +100,7 @@ jobs: check-lock-file-version: name: NPM Lock File Version timeout-minutes: 5 - runs-on: ubuntu-18.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Check NPM lock file version @@ -114,13 +114,15 @@ jobs: - name: Node 12 NODE_VERSION: 12.22.12 - name: Node 14 - NODE_VERSION: 14.19.2 + NODE_VERSION: 14.20.0 - name: Node 16 - NODE_VERSION: 16.10.0 + NODE_VERSION: 16.17.0 + - name: Node 18 + NODE_VERSION: 18.9.0 fail-fast: false name: ${{ matrix.name }} timeout-minutes: 15 - runs-on: ubuntu-18.04 + runs-on: ubuntu-latest env: NODE_VERSION: ${{ matrix.NODE_VERSION }} steps: diff --git a/.github/workflows/release-automated.yml b/.github/workflows/release-automated.yml index f20761db87..a95ae9f746 100644 --- a/.github/workflows/release-automated.yml +++ b/.github/workflows/release-automated.yml @@ -38,7 +38,7 @@ jobs: env: REGISTRY: docker.io IMAGE_NAME: parseplatform/parse-dashboard - runs-on: ubuntu-18.04 + runs-on: ubuntu-latest permissions: contents: read packages: write diff --git a/.github/workflows/release-manual-docker.yml b/.github/workflows/release-manual-docker.yml index 9863468b73..99160e7b09 100644 --- a/.github/workflows/release-manual-docker.yml +++ b/.github/workflows/release-manual-docker.yml @@ -8,13 +8,13 @@ on: inputs: ref: default: '' - description: 'Reference (tag / SHA):' + description: 'Reference (tag / SHA):' env: REGISTRY: docker.io IMAGE_NAME: parseplatform/parse-dashboard jobs: build: - runs-on: ubuntu-18.04 + runs-on: ubuntu-latest permissions: contents: read packages: write diff --git a/Parse-Dashboard/Authentication.js b/Parse-Dashboard/Authentication.js index 6a859fa546..0a6beee442 100644 --- a/Parse-Dashboard/Authentication.js +++ b/Parse-Dashboard/Authentication.js @@ -30,13 +30,13 @@ function initialize(app, options) { otpCode: req.body.otpCode }); if (!match.matchingUsername) { - return cb(null, false, { message: 'Invalid username or password' }); - } - if (match.otpMissing) { - return cb(null, false, { message: 'Please enter your one-time password.' }); + return cb(null, false, { message: JSON.stringify({ text: 'Invalid username or password' }) }); } if (!match.otpValid) { - return cb(null, false, { message: 'Invalid one-time password.' }); + return cb(null, false, { message: JSON.stringify({ text: 'Invalid one-time password.', otpLength: match.otpMissingLength || 6}) }); + } + if (match.otpMissingLength) { + return cb(null, false, { message: JSON.stringify({ text: 'Please enter your one-time password.', otpLength: match.otpMissingLength || 6 })}); } cb(null, match.matchingUsername); }) @@ -91,7 +91,7 @@ function authenticate(userToTest, usernameOnly) { let appsUserHasAccessTo = null; let matchingUsername = null; let isReadOnly = false; - let otpMissing = false; + let otpMissingLength = false; let otpValid = true; //they provided auth @@ -104,17 +104,20 @@ function authenticate(userToTest, usernameOnly) { let usernameMatches = userToTest.name == user.user; if (usernameMatches && user.mfa && !usernameOnly) { if (!userToTest.otpCode) { - otpMissing = true; + otpMissingLength = user.mfaDigits || 6; } else { const totp = new OTPAuth.TOTP({ algorithm: user.mfaAlgorithm || 'SHA1', - secret: OTPAuth.Secret.fromBase32(user.mfa) + secret: OTPAuth.Secret.fromBase32(user.mfa), + digits: user.mfaDigits, + period: user.mfaPeriod, }); const valid = totp.validate({ token: userToTest.otpCode }); if (valid === null) { otpValid = false; + otpMissingLength = user.mfaDigits || 6; } } } @@ -132,7 +135,7 @@ function authenticate(userToTest, usernameOnly) { return { isAuthenticated, matchingUsername, - otpMissing, + otpMissingLength, otpValid, appsUserHasAccessTo, isReadOnly, diff --git a/Parse-Dashboard/CLI/mfa.js b/Parse-Dashboard/CLI/mfa.js index f862f2cf45..3f26a73a98 100644 --- a/Parse-Dashboard/CLI/mfa.js +++ b/Parse-Dashboard/CLI/mfa.js @@ -65,7 +65,19 @@ const generateSecret = ({ app, username, algorithm, digits, period }) => { secret }); const url = totp.toString(); - return { secret: secret.base32, url }; + const config = { mfa: secret.base32 }; + config.app = app; + config.url = url; + if (algorithm !== 'SHA1') { + config.mfaAlgorithm = algorithm; + } + if (digits != 6) { + config.mfaDigits = digits; + } + if (period != 30) { + config.mfaPeriod = period; + } + return { config }; }; const showQR = text => { const QRCode = require('qrcode'); @@ -77,7 +89,10 @@ const showQR = text => { }); }; -const showInstructions = ({ app, username, passwordCopied, secret, url, encrypt, config }) => { +const showInstructions = ({ app, username, passwordCopied, encrypt, config }) => { + const {secret, url} = config; + const mfaJSON = {...config}; + delete mfaJSON.url; let orderCounter = 0; const getOrder = () => { orderCounter++; @@ -90,7 +105,7 @@ const showInstructions = ({ app, username, passwordCopied, secret, url, encrypt, console.log( `\n${getOrder()}. Add the following settings for user "${username}" ${app ? `in app "${app}" ` : '' }to the Parse Dashboard configuration.` + - `\n\n ${JSON.stringify(config)}` + `\n\n ${JSON.stringify(mfaJSON)}` ); if (passwordCopied) { @@ -101,14 +116,14 @@ const showInstructions = ({ app, username, passwordCopied, secret, url, encrypt, if (secret) { console.log( - `\n${getOrder()}. Open the authenticator app to scan the QR code above or enter this secret code:` + - `\n\n ${secret}` + + `\n${getOrder()}. Open the authenticator app to scan the QR code above or enter this secret code:` + + `\n\n ${secret}` + '\n\n If the secret code generates incorrect one-time passwords, try this alternative:' + - `\n\n ${url}` + + `\n\n ${url}` + `\n\n${getOrder()}. Destroy any records of the QR code and the secret code to secure the account.` ); } - + if (encrypt) { console.log( `\n${getOrder()}. Make sure that "useEncryptedPasswords" is set to "true" in your dashboard configuration.` + @@ -173,6 +188,7 @@ module.exports = { const salt = bcrypt.genSaltSync(10); data.pass = bcrypt.hashSync(data.pass, salt); } + const config = {}; if (mfa) { const { app } = await inquirer.prompt([ { @@ -182,18 +198,13 @@ module.exports = { } ]); const { algorithm, digits, period } = await getAlgorithm(); - const { secret, url } = generateSecret({ app, username, algorithm, digits, period }); - data.mfa = secret; - data.app = app; - data.url = url; - if (algorithm !== 'SHA1') { - data.mfaAlgorithm = algorithm; - } - showQR(data.url); + const secret =generateSecret({ app, username, algorithm, digits, period }); + Object.assign(config, secret.config); + showQR(secret.config.url); } - - const config = { mfa: data.mfa, user: data.user, pass: data.pass }; - showInstructions({ app: data.app, username, passwordCopied: true, secret: data.mfa, url: data.url, encrypt, config }); + config.user = data.user; + config.pass = data.pass ; + showInstructions({ app: data.app, username, passwordCopied: true, encrypt, config }); }, async createMFA() { console.log(''); @@ -212,14 +223,9 @@ module.exports = { ]); const { algorithm, digits, period } = await getAlgorithm(); - const { url, secret } = generateSecret({ app, username, algorithm, digits, period }); - showQR(url); - + const { config } = generateSecret({ app, username, algorithm, digits, period }); + showQR(config.url); // Compose config - const config = { mfa: secret }; - if (algorithm !== 'SHA1') { - config.mfaAlgorithm = algorithm; - } - showInstructions({ app, username, secret, url, config }); + showInstructions({ app, username, config }); } }; diff --git a/Parse-Dashboard/app.js b/Parse-Dashboard/app.js index 7af0fb2db5..0149b8c634 100644 --- a/Parse-Dashboard/app.js +++ b/Parse-Dashboard/app.js @@ -184,22 +184,22 @@ module.exports = function(config, options) { ` } res.send(` + - - Parse Dashboard - -
- ${errors} - - - - + + +
+ ${errors} + + + + `); }); @@ -212,20 +212,20 @@ module.exports = function(config, options) { res.append('username', req.user.matchingUsername); } res.send(` + - - Parse Dashboard - -
- - - + + +
+ + + `); }); }); diff --git a/README.md b/README.md index 245a35885e..a4e96e3de5 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![Build Status](https://github.com/parse-community/parse-dashboard/workflows/ci/badge.svg?branch=alpha)](https://github.com/parse-community/parse-dashboard/actions?query=workflow%3Aci+branch%3Aalpha) [![Snyk Badge](https://snyk.io/test/github/parse-community/parse-dashboard/badge.svg)](https://snyk.io/test/github/parse-community/parse-dashboard) -[![Node Version](https://img.shields.io/badge/nodejs-12,_14,_16-green.svg?logo=node.js&style=flat)](https://nodejs.org/) +[![Node Version](https://img.shields.io/badge/nodejs-12,_14,_16,_18-green.svg?logo=node.js&style=flat)](https://nodejs.org/) [![auto-release](https://img.shields.io/badge/%F0%9F%9A%80-auto--release-9e34eb.svg)](https://github.com/parse-community/parse-dashboard/releases) [![npm latest version](https://img.shields.io/npm/v/parse-dashboard/latest.svg)](https://www.npmjs.com/package/parse-dashboard) @@ -102,10 +102,10 @@ Parse Dashboard is continuously tested with the most recent releases of Node.js | Version | Latest Version | End-of-Life | Compatible | |------------|----------------|-------------|--------------| -| Node.js 12 | 12.22.12 | April 2022 | ✅ Yes | -| Node.js 14 | 14.19.2 | April 2023 | ✅ Yes | -| Node.js 16 | 16.10.0 | April 2024 | ✅ Yes | -| Node.js 17 | 17.x | June 2022 | ❌ Not tested | +| Node.js 12 | 12.22.12 | April 2022 | ✅ Yes | +| Node.js 14 | 14.20.0 | April 2023 | ✅ Yes | +| Node.js 16 | 16.17.0 | April 2024 | ✅ Yes | +| Node.js 18 | 18.9.0 | May 2025 | ✅ Yes | ## Configuring Parse Dashboard diff --git a/changelogs/CHANGELOG_alpha.md b/changelogs/CHANGELOG_alpha.md index b8c8175b5a..4715a0e8e6 100644 --- a/changelogs/CHANGELOG_alpha.md +++ b/changelogs/CHANGELOG_alpha.md @@ -1,3 +1,95 @@ +# [4.2.0-alpha.17](https://github.com/ParsePlatform/parse-dashboard/compare/4.2.0-alpha.16...4.2.0-alpha.17) (2022-09-21) + + +### Bug Fixes + +* view relation dialog requires browser refresh when navigating ([#2275](https://github.com/ParsePlatform/parse-dashboard/issues/2275)) ([d60a8b7](https://github.com/ParsePlatform/parse-dashboard/commit/d60a8b7c1ab6c4c8dd85051d9c1acb05a0a69a59)) + +# [4.2.0-alpha.16](https://github.com/ParsePlatform/parse-dashboard/compare/4.2.0-alpha.15...4.2.0-alpha.16) (2022-09-21) + + +### Bug Fixes + +* file upload dialog in data browser shows multiple times ([#2276](https://github.com/ParsePlatform/parse-dashboard/issues/2276)) ([3927340](https://github.com/ParsePlatform/parse-dashboard/commit/39273403568f7ca13a349cac53fbb6a99d8823cc)) + +# [4.2.0-alpha.15](https://github.com/ParsePlatform/parse-dashboard/compare/4.2.0-alpha.14...4.2.0-alpha.15) (2022-09-19) + + +### Bug Fixes + +* context menu in data browser is not scrollable ([#2271](https://github.com/ParsePlatform/parse-dashboard/issues/2271)) ([6c54bd8](https://github.com/ParsePlatform/parse-dashboard/commit/6c54bd82b872d5efed827c3582b4fb3f0aa24a95)) + +# [4.2.0-alpha.14](https://github.com/ParsePlatform/parse-dashboard/compare/4.2.0-alpha.13...4.2.0-alpha.14) (2022-09-17) + + +### Features + +* show skeleton as loading indicator in data browser while data is loading ([#2273](https://github.com/ParsePlatform/parse-dashboard/issues/2273)) ([059f616](https://github.com/ParsePlatform/parse-dashboard/commit/059f616718006c6f559b0b07a8da641367497d9a)) + +# [4.2.0-alpha.13](https://github.com/ParsePlatform/parse-dashboard/compare/4.2.0-alpha.12...4.2.0-alpha.13) (2022-09-17) + + +### Features + +* add column name to related records ([#2264](https://github.com/ParsePlatform/parse-dashboard/issues/2264)) ([cc82533](https://github.com/ParsePlatform/parse-dashboard/commit/cc82533ae3066daa7b789131a76a409720d45b0b)) + +# [4.2.0-alpha.12](https://github.com/ParsePlatform/parse-dashboard/compare/4.2.0-alpha.11...4.2.0-alpha.12) (2022-09-14) + + +### Features + +* auto-submit one-time password (OTP) after entering ([#2257](https://github.com/ParsePlatform/parse-dashboard/issues/2257)) ([e528705](https://github.com/ParsePlatform/parse-dashboard/commit/e5287054cff3bff368ba4e379eebf05bfb7d8bd5)) + +# [4.2.0-alpha.11](https://github.com/ParsePlatform/parse-dashboard/compare/4.2.0-alpha.10...4.2.0-alpha.11) (2022-09-13) + + +### Bug Fixes + +* column names in data browser menu not left-aligned ([#2263](https://github.com/ParsePlatform/parse-dashboard/issues/2263)) ([fc5673a](https://github.com/ParsePlatform/parse-dashboard/commit/fc5673a0ebbc7b4d51e122dbb71172803513309e)) + +# [4.2.0-alpha.10](https://github.com/ParsePlatform/parse-dashboard/compare/4.2.0-alpha.9...4.2.0-alpha.10) (2022-09-12) + + +### Features + +* add Node 18 support ([#2206](https://github.com/ParsePlatform/parse-dashboard/issues/2206)) ([bc7895a](https://github.com/ParsePlatform/parse-dashboard/commit/bc7895aadacc2cc6b0bbcfe786b73d7b82527e55)) + +# [4.2.0-alpha.9](https://github.com/ParsePlatform/parse-dashboard/compare/4.2.0-alpha.8...4.2.0-alpha.9) (2022-09-12) + + +### Bug Fixes + +* login fails with error `req.session.regenerate is not a function` ([#2260](https://github.com/ParsePlatform/parse-dashboard/issues/2260)) ([1dc2b91](https://github.com/ParsePlatform/parse-dashboard/commit/1dc2b915e16a2038268f886d4c24e7b081ae0531)) + +# [4.2.0-alpha.8](https://github.com/ParsePlatform/parse-dashboard/compare/4.2.0-alpha.7...4.2.0-alpha.8) (2022-09-08) + + +### Features + +* add option to auto-sort columns alphabetically ([#2252](https://github.com/ParsePlatform/parse-dashboard/issues/2252)) ([2b7f20f](https://github.com/ParsePlatform/parse-dashboard/commit/2b7f20fcc088f74915b50ec1219038ba9b233c27)) + +# [4.2.0-alpha.7](https://github.com/ParsePlatform/parse-dashboard/compare/4.2.0-alpha.6...4.2.0-alpha.7) (2022-09-08) + + +### Bug Fixes + +* dashboard contains invalid html for top-level document ([#2254](https://github.com/ParsePlatform/parse-dashboard/issues/2254)) ([bbce857](https://github.com/ParsePlatform/parse-dashboard/commit/bbce8579ef634bf8e6800f3a6ab8cd650e971695)) + +# [4.2.0-alpha.6](https://github.com/ParsePlatform/parse-dashboard/compare/4.2.0-alpha.5...4.2.0-alpha.6) (2022-09-08) + + +### Features + +* apply filter in data browser by pressing "Enter" key ([#2256](https://github.com/ParsePlatform/parse-dashboard/issues/2256)) ([bc4f9eb](https://github.com/ParsePlatform/parse-dashboard/commit/bc4f9eb9cad9eb8e362dca20bf932cb3d1e6721c)) + +# [4.2.0-alpha.5](https://github.com/ParsePlatform/parse-dashboard/compare/4.2.0-alpha.4...4.2.0-alpha.5) (2022-09-06) + + +### Bug Fixes + +* login fails with error `req.session.regenerate is not a function` ([#2197](https://github.com/ParsePlatform/parse-dashboard/issues/2197)) [skip release] ([014d9c1](https://github.com/ParsePlatform/parse-dashboard/commit/014d9c15b0c4efad8b0762e5a49f6a740ead5edb)) +* unnecessary count operations in Data Browser ([#2250](https://github.com/ParsePlatform/parse-dashboard/issues/2250)) ([bfc1684](https://github.com/ParsePlatform/parse-dashboard/commit/bfc1684375b7c2120e2a4ae566e5b3c38c0ca110)) + # [4.2.0-alpha.4](https://github.com/ParsePlatform/parse-dashboard/compare/4.2.0-alpha.3...4.2.0-alpha.4) (2022-07-20) diff --git a/ci/ciCheck.js b/ci/ciCheck.js index c3d08ec59f..2c24db28c8 100644 --- a/ci/ciCheck.js +++ b/ci/ciCheck.js @@ -28,7 +28,7 @@ async function checkNodeVersions() { '<12.0.0', // These versions have reached their end-of-life support date '>=13.0.0 <14.0.0', // These versions have reached their end-of-life support date '>=15.0.0 <16.0.0', // These versions have reached their end-of-life support date - '>=16.0.0' // Parse Dashboard is currently not officially Node 16 compatible + '>=17.0.0 <18.0.0', // These versions have reached their end-of-life support date ], }).check(); } diff --git a/package-lock.json b/package-lock.json index 3da69a5874..f0dc2afdde 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "parse-dashboard", - "version": "4.2.0-beta.1", + "version": "4.2.0-alpha.17", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -2241,6 +2241,12 @@ "integrity": "sha512-6nFkfkmSeV/rqSaS4oWHgmpnYw194f6hmWF5is6b0J1naJZoiD0NTc9AiUwPHvWsowkjuHErCZT1wa0jg+BLIA==", "dev": true }, + "@gar/promisify": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", + "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", + "dev": true + }, "@graphiql/react": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/@graphiql/react/-/react-0.6.0.tgz", @@ -3020,6 +3026,34 @@ "fastq": "^1.6.0" } }, + "@npmcli/fs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", + "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", + "dev": true, + "requires": { + "@gar/promisify": "^1.0.1", + "semver": "^7.3.5" + } + }, + "@npmcli/move-file": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", + "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", + "dev": true, + "requires": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, + "dependencies": { + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + } + } + }, "@octokit/auth-token": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz", @@ -4069,6 +4103,17 @@ "debug": "4" } }, + "agentkeepalive": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.2.1.tgz", + "integrity": "sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "depd": "^1.1.2", + "humanize-ms": "^1.2.1" + } + }, "aggregate-error": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", @@ -4113,12 +4158,6 @@ "write-file-atomic": "^3.0.3" } }, - "amdefine": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", - "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", - "dev": true - }, "ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -4286,36 +4325,19 @@ "dev": true }, "aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", "dev": true }, "are-we-there-yet": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", - "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", + "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", "dev": true, "requires": { "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - } + "readable-stream": "^3.6.0" } }, "argparse": { @@ -4449,7 +4471,7 @@ "async-foreach": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz", - "integrity": "sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=", + "integrity": "sha512-VUeSMD8nEGBWaZK4lizI1sf3yEC7pnAQ/mrI7pC2fBz2s/tq5jWWEngTwaf0Gruu/OoXRGLGg1XFqpYBiGTYJA==", "dev": true }, "async-limiter": { @@ -4977,6 +4999,49 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" }, + "cacache": { + "version": "15.3.0", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", + "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", + "dev": true, + "requires": { + "@npmcli/fs": "^1.0.0", + "@npmcli/move-file": "^1.0.1", + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "glob": "^7.1.4", + "infer-owner": "^1.0.4", + "lru-cache": "^6.0.0", + "minipass": "^3.1.1", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.2", + "mkdirp": "^1.0.3", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.0.2", + "unique-filename": "^1.1.1" + }, + "dependencies": { + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + }, + "p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + } + } + }, "cache-base": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", @@ -5294,12 +5359,6 @@ "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", "dev": true }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true - }, "codemirror": { "version": "5.65.7", "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.7.tgz", @@ -5421,7 +5480,7 @@ "console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", "dev": true }, "content-disposition": { @@ -6018,7 +6077,7 @@ "delegates": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", "dev": true }, "depd": { @@ -6435,6 +6494,28 @@ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" }, + "encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, + "optional": true, + "requires": { + "iconv-lite": "^0.6.2" + }, + "dependencies": { + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } + } + }, "end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -6480,6 +6561,12 @@ "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", "dev": true }, + "err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true + }, "error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -7837,55 +7924,26 @@ "dev": true }, "gauge": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", "dev": true, "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" }, "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } } } }, @@ -7938,7 +7996,7 @@ "get-stdin": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", - "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", + "integrity": "sha512-F5aQMywwJ2n85s4hJPTT9RPxGmubonuB10MNYo17/xph174n2MIR33HRguhzVag10O/npM7SPk73LMZNP+FaWw==", "dev": true }, "get-stream": { @@ -8083,13 +8141,13 @@ } }, "globule": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.3.tgz", - "integrity": "sha512-mb1aYtDbIjTu4ShMB85m3UzjX9BVKe9WCzsnfMSZk+K5GpIbBOexgg4PPCt5eHDEG5/ZQAUX2Kct02zfiPLsKg==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.4.tgz", + "integrity": "sha512-OPTIfhMBh7JbBYDpa5b+Q5ptmMWKwcNcFSR/0c6t8V4f3ZAVBEsKNY37QdVqmLRYSMhOUGYrY0QhSoEpzGr/Eg==", "dev": true, "requires": { "glob": "~7.1.1", - "lodash": "~4.17.10", + "lodash": "^4.17.21", "minimatch": "~3.0.2" }, "dependencies": { @@ -8269,7 +8327,7 @@ "has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", "dev": true }, "has-value": { @@ -8535,6 +8593,15 @@ "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", "dev": true }, + "humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "dev": true, + "requires": { + "ms": "^2.0.0" + } + }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -8633,6 +8700,12 @@ "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=", "dev": true }, + "infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "dev": true + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -8747,6 +8820,12 @@ "loose-envify": "^1.0.0" } }, + "ip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", + "dev": true + }, "ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -8913,6 +8992,12 @@ "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==" }, + "is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "dev": true + }, "is-negative-zero": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", @@ -11354,6 +11439,30 @@ } } }, + "make-fetch-happen": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", + "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", + "dev": true, + "requires": { + "agentkeepalive": "^4.1.3", + "cacache": "^15.2.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^6.0.0", + "minipass": "^3.1.3", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^1.3.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.2", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^6.0.0", + "ssri": "^8.0.0" + } + }, "makeerror": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", @@ -11592,14 +11701,62 @@ } }, "minipass": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.6.tgz", - "integrity": "sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ==", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.4.tgz", + "integrity": "sha512-I9WPbWHCGu8W+6k1ZiGpPu0GkoKBeorkfKNuAFBNS1HNFJvke82sxvI5bzcCNpWPorkOO5QQ+zomzzwRxejXiw==", "dev": true, "requires": { "yallist": "^4.0.0" } }, + "minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-fetch": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", + "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", + "dev": true, + "requires": { + "encoding": "^0.1.12", + "minipass": "^3.1.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.0.0" + } + }, + "minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, "minizlib": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", @@ -11786,33 +11943,33 @@ } }, "node-gyp": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-7.1.2.tgz", - "integrity": "sha512-CbpcIo7C3eMu3dL1c3d0xw449fHIGALIJsRP4DDPHpyiW8vcriNY7ubh9TE4zEKfSxscY7PjeFnshE7h75ynjQ==", + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", + "integrity": "sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==", "dev": true, "requires": { "env-paths": "^2.2.0", "glob": "^7.1.4", - "graceful-fs": "^4.2.3", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^9.1.0", "nopt": "^5.0.0", - "npmlog": "^4.1.2", - "request": "^2.88.2", + "npmlog": "^6.0.0", "rimraf": "^3.0.2", - "semver": "^7.3.2", - "tar": "^6.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", "which": "^2.0.2" }, "dependencies": { "npmlog": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", + "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", "dev": true, "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" } } } @@ -11866,9 +12023,9 @@ "dev": true }, "node-sass": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-7.0.0.tgz", - "integrity": "sha512-6yUnsD3L8fVbgMX6nKQqZkjRcG7a/PpmF0pEyeWf+BgbTj2ToJlCYrnUifL2KbjV5gIY22I3oppahBWA3B+jUg==", + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-7.0.3.tgz", + "integrity": "sha512-8MIlsY/4dXUkJDYht9pIWBhMil3uHmE8b/AdJPjmFn1nBx9X9BASzfzmsCy0uCCb8eqI3SYYzVPDswWqSx7gjw==", "dev": true, "requires": { "async-foreach": "^0.1.3", @@ -11880,10 +12037,10 @@ "lodash": "^4.17.15", "meow": "^9.0.0", "nan": "^2.13.2", - "node-gyp": "^7.1.0", + "node-gyp": "^8.4.1", "npmlog": "^5.0.0", "request": "^2.88.0", - "sass-graph": "2.2.5", + "sass-graph": "^4.0.1", "stdout-stream": "^1.4.0", "true-case-path": "^1.0.2" }, @@ -14142,12 +14299,6 @@ "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz", "integrity": "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==" }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true - }, "nwsapi": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", @@ -15035,6 +15186,22 @@ "asap": "~2.0.3" } }, + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "dev": true + }, + "promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "requires": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + } + }, "prompts": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.1.tgz", @@ -16042,6 +16209,12 @@ "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", "dev": true }, + "retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true + }, "reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -16332,15 +16505,84 @@ } }, "sass-graph": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.5.tgz", - "integrity": "sha512-VFWDAHOe6mRuT4mZRd4eKE+d8Uedrk6Xnh7Sh9b4NGufQLQjOrvf/MQoOdx+0s92L89FeyUUNfU597j/3uNpag==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-4.0.1.tgz", + "integrity": "sha512-5YCfmGBmxoIRYHnKK2AKzrAkCoQ8ozO+iumT8K4tXJXRVCPf+7s1/9KxTSW3Rbvf+7Y7b4FR3mWyLnQr3PHocA==", "dev": true, "requires": { "glob": "^7.0.0", - "lodash": "^4.0.0", - "scss-tokenizer": "^0.2.3", - "yargs": "^13.3.2" + "lodash": "^4.17.11", + "scss-tokenizer": "^0.4.3", + "yargs": "^17.2.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yargs": { + "version": "17.5.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", + "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" + } + }, + "yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true + } } }, "sass-loader": { @@ -16397,23 +16639,20 @@ } }, "scss-tokenizer": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz", - "integrity": "sha1-jrBtualyMzOCTT9VMGQRSYR85dE=", + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.4.3.tgz", + "integrity": "sha512-raKLgf1LI5QMQnG+RxHz6oK0sL3x3I4FN2UDLqgLOGO8hodECNnNh5BXn7fAyBxrA8zVzdQizQ6XjNJQ+uBwMw==", "dev": true, "requires": { - "js-base64": "^2.1.8", - "source-map": "^0.4.2" + "js-base64": "^2.4.9", + "source-map": "^0.7.3" }, "dependencies": { "source-map": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", - "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", - "dev": true, - "requires": { - "amdefine": ">=0.0.4" - } + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true } } }, @@ -16808,6 +17047,12 @@ "is-fullwidth-code-point": "^2.0.0" } }, + "smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true + }, "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", @@ -16930,6 +17175,38 @@ } } }, + "socks": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.0.tgz", + "integrity": "sha512-scnOe9y4VuiNUULJN72GrM26BNOjVsfPXI+j+98PkyEfsIXroa5ofyjT+FzGvn/xHs73U2JtoBYAVx9Hl4quSA==", + "dev": true, + "requires": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + } + }, + "socks-proxy-agent": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz", + "integrity": "sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==", + "dev": true, + "requires": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + } + } + }, "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -17067,6 +17344,15 @@ "tweetnacl": "~0.14.0" } }, + "ssri": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", + "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "dev": true, + "requires": { + "minipass": "^3.1.1" + } + }, "stack-utils": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.5.tgz", @@ -18017,6 +18303,24 @@ "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", "dev": true }, + "unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "dev": true, + "requires": { + "unique-slug": "^2.0.0" + } + }, + "unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4" + } + }, "unique-string": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", diff --git a/package.json b/package.json index aec7eb98f5..b93e51e45a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-dashboard", - "version": "4.2.0-beta.1", + "version": "4.2.0-alpha.17", "repository": { "type": "git", "url": "https://github.com/ParsePlatform/parse-dashboard" @@ -103,7 +103,7 @@ "jest": "24.8.0", "madge": "5.0.1", "marked": "4.0.10", - "node-sass": "7.0.0", + "node-sass": "7.0.3", "null-loader": "4.0.1", "path-to-regexp": "3.2.0", "puppeteer": "3.0.0", diff --git a/src/components/BrowserCell/BrowserCell.react.js b/src/components/BrowserCell/BrowserCell.react.js index f038ba03f6..faaa5011db 100644 --- a/src/components/BrowserCell/BrowserCell.react.js +++ b/src/components/BrowserCell/BrowserCell.react.js @@ -335,7 +335,7 @@ export default class BrowserCell extends Component { cl.forEach((column, field) => { if (column.targetClass !== pointerClassName) { return; } relatedRecordsMenuItem.items.push({ - text: className, callback: () => { + text: `${className}`, subtext: `${field}`, callback: () => { let relatedObject = value; if (this.props.field === 'objectId') { relatedObject = new Parse.Object(pointerClassName); diff --git a/src/components/BrowserFilter/BrowserFilter.react.js b/src/components/BrowserFilter/BrowserFilter.react.js index 3d7fe21496..d9a37caf27 100644 --- a/src/components/BrowserFilter/BrowserFilter.react.js +++ b/src/components/BrowserFilter/BrowserFilter.react.js @@ -117,6 +117,7 @@ export default class BrowserFilter extends React.Component { schema={this.props.schema} filters={this.state.filters} onChange={filters => this.setState({ filters: filters })} + onSearch={this.apply.bind(this)} renderRow={props => ( 0} parentContentId={POPOVER_CONTENT_ID} /> )} diff --git a/src/components/BrowserFilter/FilterRow.react.js b/src/components/BrowserFilter/FilterRow.react.js index f10dc18c37..429487193b 100644 --- a/src/components/BrowserFilter/FilterRow.react.js +++ b/src/components/BrowserFilter/FilterRow.react.js @@ -27,13 +27,13 @@ let setFocus = (input) => { } } -function compareValue(info, value, onChangeCompareTo, active, parentContentId) { +function compareValue(info, value, onChangeCompareTo, onKeyDown, active, parentContentId) { switch (info.type) { case null: return null; case 'Object': case 'String': - return onChangeCompareTo(e.target.value)} ref={setFocus}/>; + return onChangeCompareTo(e.target.value)} onKeyDown={onKeyDown} ref={setFocus}/>; case 'Pointer': return ( + }} + onKeyDown={onKeyDown} + /> ); case 'Date': return ( @@ -70,7 +72,7 @@ function compareValue(info, value, onChangeCompareTo, active, parentContentId) { className={styles.date} value={Parse._decode('date', value)} onChange={(value) => onChangeCompareTo(Parse._encode(value))} - ref={setFocus} + ref={setFocus} parentContentId={parentContentId} /> ); } @@ -86,6 +88,7 @@ let FilterRow = ({ onChangeField, onChangeConstraint, onChangeCompareTo, + onKeyDown, onDeleteRow, active, parentContentId, @@ -102,7 +105,7 @@ let FilterRow = ({ value={Constraints[currentConstraint].name} options={constraints.map((c) => Constraints[c].name)} onChange={(c) => onChangeConstraint(constraintLookup[c], compareTo)} /> - {compareValue(compareInfo, compareTo, onChangeCompareTo, active, parentContentId)} + {compareValue(compareInfo, compareTo, onChangeCompareTo, onKeyDown, active, parentContentId)} ); diff --git a/src/components/ColumnsConfiguration/ColumnConfigurationItem.react.js b/src/components/ColumnsConfiguration/ColumnConfigurationItem.react.js index 087e88b385..279beb1926 100644 --- a/src/components/ColumnsConfiguration/ColumnConfigurationItem.react.js +++ b/src/components/ColumnsConfiguration/ColumnConfigurationItem.react.js @@ -35,7 +35,7 @@ export default ({ name, handleColumnDragDrop, index, onChangeVisible, visible })
{name}
-
+
diff --git a/src/components/ColumnsConfiguration/ColumnConfigurationItem.scss b/src/components/ColumnsConfiguration/ColumnConfigurationItem.scss index 68400d4ae6..bd0bf9347b 100644 --- a/src/components/ColumnsConfiguration/ColumnConfigurationItem.scss +++ b/src/components/ColumnsConfiguration/ColumnConfigurationItem.scss @@ -1,7 +1,6 @@ .columnConfigItem { padding: 8px 10px; display: flex; - justify-content: space-between; border-radius: 5px; cursor: grab; } @@ -18,8 +17,13 @@ } .columnConfigItemName { - width: 110px; text-overflow: ellipsis; overflow: hidden; line-height: 24px; +} + +.columnIcon { + width: auto; + flex-grow: 1; + justify-content: end; } \ No newline at end of file diff --git a/src/components/ColumnsConfiguration/ColumnsConfiguration.react.js b/src/components/ColumnsConfiguration/ColumnsConfiguration.react.js index 5a1f7ad0d0..fdc088bea0 100644 --- a/src/components/ColumnsConfiguration/ColumnsConfiguration.react.js +++ b/src/components/ColumnsConfiguration/ColumnsConfiguration.react.js @@ -54,6 +54,23 @@ export default class ColumnsConfiguration extends React.Component { this.props.handleColumnsOrder(this.props.order.map(order => ({ ...order, visible: false }))); } + autoSort() { + const defaultOrder = ['objectId', 'createdAt', 'updatedAt', 'ACL'] + const order = { + default: [], + other: [] + }; + for (const column of this.props.order) { + const index = defaultOrder.indexOf(column.name); + if (index !== -1) { + order.default[index] = column; + } else { + order.other.push(column) + } + } + this.props.handleColumnsOrder([...order.default.filter(column => column), ...order.other.sort((a,b) => a.name.localeCompare(b.name))]); + } + render() { const { handleColumnDragDrop, handleColumnsOrder, order, disabled } = this.props; let [ title, entry ] = [styles.title, styles.entry ].map(className => ( @@ -118,6 +135,10 @@ export default class ColumnsConfiguration extends React.Component { color='white' value='Show all' onClick={this.showAll.bind(this)} /> +
diff --git a/src/components/ColumnsConfiguration/ColumnsConfiguration.scss b/src/components/ColumnsConfiguration/ColumnsConfiguration.scss index eb3220140d..c22e03aa48 100644 --- a/src/components/ColumnsConfiguration/ColumnsConfiguration.scss +++ b/src/components/ColumnsConfiguration/ColumnsConfiguration.scss @@ -64,7 +64,7 @@ right: 0; border-radius: 5px 0 5px 5px; background: #797691; - width: 220px; + width: 320px; font-size: 14px; .columnConfigContainer { diff --git a/src/components/ContextMenu/ContextMenu.react.js b/src/components/ContextMenu/ContextMenu.react.js index 64687510b5..611e1e0a99 100644 --- a/src/components/ContextMenu/ContextMenu.react.js +++ b/src/components/ContextMenu/ContextMenu.react.js @@ -14,7 +14,7 @@ const getPositionToFitVisibleScreen = (ref) => { const elBox = ref.current.getBoundingClientRect(); const y = (elBox.y + elBox.height) < window.innerHeight ? - 0 : (window.innerHeight - (elBox.y + elBox.height)); + 0 : (0 - elBox.y + 100); // If there's a previous element show current next to it. // Try on right side first, then on left if there's no place. @@ -45,6 +45,8 @@ const MenuSection = ({ level, items, path, setPath, hide }) => { const style = position ? { left: position.x, top: position.y, + maxHeight: '80vh', + overflowY: 'scroll', opacity: 1 } : {}; @@ -75,6 +77,7 @@ const MenuSection = ({ level, items, path, setPath, hide }) => { }} > {item.text} + {item.subtext && - {item.subtext}} ); })} diff --git a/src/components/ContextMenu/ContextMenu.scss b/src/components/ContextMenu/ContextMenu.scss index f4fae68bab..78278cd828 100644 --- a/src/components/ContextMenu/ContextMenu.scss +++ b/src/components/ContextMenu/ContextMenu.scss @@ -17,6 +17,9 @@ cursor: pointer; white-space: nowrap; padding: 0 30px 0 10px; + span { + color: #A2A6B1 + } } li:hover { diff --git a/src/components/DataBrowserHeaderBar/DataBrowserHeaderBar.react.js b/src/components/DataBrowserHeaderBar/DataBrowserHeaderBar.react.js index b1c89280ca..d021924386 100644 --- a/src/components/DataBrowserHeaderBar/DataBrowserHeaderBar.react.js +++ b/src/components/DataBrowserHeaderBar/DataBrowserHeaderBar.react.js @@ -14,7 +14,7 @@ import { DndProvider } from 'react-dnd' export default class DataBrowserHeaderBar extends React.Component { render() { - let { headers, onResize, selectAll, onAddColumn, updateOrdering, readonly, preventSchemaEdits, selected } = this.props; + let { headers, onResize, selectAll, onAddColumn, updateOrdering, readonly, preventSchemaEdits, selected, isDataLoaded } = this.props; let elements = [
{readonly @@ -85,9 +85,32 @@ export default class DataBrowserHeaderBar extends React.Component { ); } + function renderSkeleton() { + if (isDataLoaded) return null; + var skeletons = [1, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1]; + return ( +
+ {skeletons.map(function (opacity, index) { + return ( +
+ ); + })} +
+ ); + } + return ( -
{elements}
+
+ {elements} + {renderSkeleton()} +
) } diff --git a/src/components/DataBrowserHeaderBar/DataBrowserHeaderBar.scss b/src/components/DataBrowserHeaderBar/DataBrowserHeaderBar.scss index d6d2097b92..df45061d13 100644 --- a/src/components/DataBrowserHeaderBar/DataBrowserHeaderBar.scss +++ b/src/components/DataBrowserHeaderBar/DataBrowserHeaderBar.scss @@ -77,3 +77,32 @@ cursor: not-allowed; } } + +.skeleton { + position: absolute; + width: 100%; + height: 100%; + top: 30px; +} + +.skeletonRow { + border-top: 1px solid #e3e3ea; + border-bottom: 1px solid #e3e3ea; + height: 30px; + width:100%; + vertical-align: middle; + padding-left: 2px; + margin-top: 30px; + line-height: 31px; + animation: skeleton-loading 1s linear infinite alternate; +} + +@keyframes skeleton-loading { + 0% { + background-color:#ffffff; + } + 100% { + background-color: #e3e3ea; + + } +} diff --git a/src/components/Filter/Filter.react.js b/src/components/Filter/Filter.react.js index c08c82d6e0..453e5d4046 100644 --- a/src/components/Filter/Filter.react.js +++ b/src/components/Filter/Filter.react.js @@ -44,7 +44,7 @@ function deleteRow(filters, index) { return filters.delete(index); } -let Filter = ({ schema, filters, renderRow, onChange, blacklist, className }) => { +let Filter = ({ schema, filters, renderRow, onChange, onSearch, blacklist, className }) => { const currentApp = React.useContext(CurrentApp); blacklist = blacklist || []; let available = Filters.availableFilters(schema, filters); @@ -116,6 +116,11 @@ let Filter = ({ schema, filters, renderRow, onChange, blacklist, className }) => onChangeCompareTo: newCompare => { onChange(changeCompareTo(schema, filters, i, compareType, newCompare)); }, + onKeyDown: ({key}) => { + if (key === 'Enter') { + onSearch(); + } + }, onDeleteRow: () => { onChange(deleteRow(filters, i)); } diff --git a/src/dashboard/Data/Browser/Browser.react.js b/src/dashboard/Data/Browser/Browser.react.js index 341c46f9d3..23702a7419 100644 --- a/src/dashboard/Data/Browser/Browser.react.js +++ b/src/dashboard/Data/Browser/Browser.react.js @@ -149,6 +149,13 @@ class Browser extends DashboardView { this.cancelPendingEditRows = this.cancelPendingEditRows.bind(this); this.dataBrowserRef = React.createRef(); + window.addEventListener('popstate', () => { + this.setState({ + relation: null, + data: null, + }) + this.refresh(); + }); } componentWillMount() { @@ -171,10 +178,11 @@ class Browser extends DashboardView { if (this.props.params.appId !== nextProps.params.appId || !this.props.params.className) { this.setState({ counts: {} }); Parse.Object._clearAllState(); + + nextProps.schema.dispatch(ActionTypes.FETCH) + .then(() => this.handleFetchedSchema()); } this.prefetchData(nextProps, nextContext); - nextProps.schema.dispatch(ActionTypes.FETCH) - .then(() => this.handleFetchedSchema()); } if (!nextProps.params.className && nextProps.schema.data.get('classes')) { this.redirectToFirstClass(nextProps.schema.data.get('classes'), nextContext); @@ -831,6 +839,7 @@ class Browser extends DashboardView { const url = `${this.getRelationURL()}${filterQueryString ? `?filters=${filterQueryString}` : ''}`; history.push(url); }); + this.fetchRelation(relation, filters); } handlePointerClick({ className, id, field = 'objectId' }) { diff --git a/src/dashboard/Data/Browser/BrowserTable.react.js b/src/dashboard/Data/Browser/BrowserTable.react.js index eb48eaef0f..13da8dce27 100644 --- a/src/dashboard/Data/Browser/BrowserTable.react.js +++ b/src/dashboard/Data/Browser/BrowserTable.react.js @@ -444,7 +444,9 @@ export default class BrowserTable extends React.Component { handleDragDrop={this.props.handleHeaderDragDrop} onResize={this.props.handleResize} onAddColumn={this.props.onAddColumn} - preventSchemaEdits={this.context.preventSchemaEdits} /> + preventSchemaEdits={this.context.preventSchemaEdits} + isDataLoaded={!!this.props.data} + />
); } diff --git a/src/dashboard/Data/Browser/EditRowDialog.react.js b/src/dashboard/Data/Browser/EditRowDialog.react.js index 99a32026c4..1dde61268d 100644 --- a/src/dashboard/Data/Browser/EditRowDialog.react.js +++ b/src/dashboard/Data/Browser/EditRowDialog.react.js @@ -23,7 +23,7 @@ export default class EditRowDialog extends React.Component { const { currentObject, openObjectPickers, expandedTextAreas } = this.initializeState( selectedObject ); - this.state = { currentObject, openObjectPickers, expandedTextAreas, showFileEditor: false }; + this.state = { currentObject, openObjectPickers, expandedTextAreas, showFileEditor: null }; this.updateCurrentObject = this.updateCurrentObject.bind(this); this.handleChange = this.handleChange.bind(this); @@ -224,15 +224,15 @@ export default class EditRowDialog extends React.Component { this.setState({ expandedTextAreas }); } - openFileEditor() { + openFileEditor(column) { this.setState({ - showFileEditor: true + showFileEditor: column }); } hideFileEditor() { this.setState({ - showFileEditor: false + showFileEditor: null }); } @@ -358,9 +358,9 @@ export default class EditRowDialog extends React.Component {
this.openFileEditor()} + onClick={() => this.openFileEditor(name)} /> - {this.state.showFileEditor && ( + {this.state.showFileEditor === name && ( { +const readOnlyApps = apps.map((app) => { app.readOnly = true; return app; }); @@ -55,7 +55,7 @@ function createAuthenticationResult(isAuthenticated, matchingUsername, appsUserH matchingUsername, appsUserHasAccessTo, isReadOnly, - otpMissing: false, + otpMissingLength: false, otpValid: true } } diff --git a/src/login/Login.js b/src/login/Login.js index 51f0331aaf..79f4de1b23 100644 --- a/src/login/Login.js +++ b/src/login/Login.js @@ -16,8 +16,16 @@ export default class Login extends React.Component { super(); let errorDiv = document.getElementById('login_errors'); + let otpLength = 6; if (errorDiv) { this.errors = errorDiv.innerHTML; + try { + const json = JSON.parse(this.errors) + this.errors = json.text + otpLength = json.otpLength; + } catch (e) { + this.errors = `could not pass error json: ${e}`; + } } this.state = { @@ -30,6 +38,7 @@ export default class Login extends React.Component { this.inputRefUser = React.createRef(); this.inputRefPass = React.createRef(); this.inputRefMfa = React.createRef(); + this.otpLength = otpLength; } componentDidMount() { @@ -53,6 +62,15 @@ export default class Login extends React.Component { const {path} = this.props; const updateField = (field, e) => { this.setState({[field]: e.target.value}); + if (field === 'otp' && e.target.value.length >= this.otpLength) { + const input = document.querySelectorAll('input'); + for (const field of input) { + if (field.type === 'submit') { + field.click(); + break; + } + } + } } const formSubmit = () => { sessionStorage.setItem('username', this.state.username); @@ -95,7 +113,11 @@ export default class Login extends React.Component { input={ updateField('otp', e)} ref={this.inputRefMfa} /> } />