diff --git a/.github/workflows/ci-automated-check-environment.yml b/.github/workflows/ci-automated-check-environment.yml index e24484db9f..79c6b35f95 100644 --- a/.github/workflows/ci-automated-check-environment.yml +++ b/.github/workflows/ci-automated-check-environment.yml @@ -13,13 +13,13 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout default branch - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Setup Node - uses: actions/setup-node@v2 + uses: actions/setup-node@v4 with: - node-version: 14 + node-version: 18 - name: Cache Node.js modules - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.npm key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} @@ -36,7 +36,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout default branch - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Compose branch name for PR id: branch run: echo "::set-output name=name::ci-bump-environment" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c3cf088219..5ca64fd872 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,20 +6,20 @@ on: branches: - '**' env: - NODE_VERSION: 18.9.0 + NODE_VERSION: 20.11.1 jobs: check-ci: name: Node Engine Check timeout-minutes: 15 runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@v1 + uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} - name: Cache Node.js modules - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.npm key: ${{ runner.os }}-node-${{ env.NODE_VERSION }}-${{ hashFiles('**/package-lock.json') }} @@ -34,13 +34,13 @@ jobs: timeout-minutes: 15 runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@v1 + uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} - name: Cache Node.js modules - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.npm key: ${{ runner.os }}-node-${{ env.NODE_VERSION }}-${{ hashFiles('**/package-lock.json') }} @@ -54,13 +54,13 @@ jobs: timeout-minutes: 15 runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@v1 + uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} - name: Cache Node.js modules - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.npm key: ${{ runner.os }}-node-${{ env.NODE_VERSION }}-${{ hashFiles('**/package-lock.json') }} @@ -88,7 +88,7 @@ jobs: timeout-minutes: 15 runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up QEMU uses: docker/setup-qemu-action@v1 - name: Set up Docker Buildx @@ -102,21 +102,19 @@ jobs: timeout-minutes: 5 runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Check NPM lock file version uses: mansona/npm-lockfile-version@v1 with: - version: 1 + version: 3 check-build: strategy: matrix: include: - - name: Node 14 - NODE_VERSION: 14.20.1 - - name: Node 16 - NODE_VERSION: 16.17.0 - name: Node 18 - NODE_VERSION: 18.9.0 + NODE_VERSION: 18.19.1 + - name: Node 20 + NODE_VERSION: 20.11.1 fail-fast: false name: ${{ matrix.name }} timeout-minutes: 15 @@ -131,13 +129,13 @@ jobs: echo "::set-output name=node_major::$(echo $node_major)" - name: Fix usage of insecure GitHub protocol run: sudo git config --system url."https://github".insteadOf "git://github" - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Use Node.js ${{ matrix.NODE_VERSION }} - uses: actions/setup-node@v1 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.NODE_VERSION }} - name: Cache Node.js modules - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.npm key: ${{ runner.os }}-node-${{ matrix.NODE_VERSION }}-${{ hashFiles('**/package-lock.json') }} diff --git a/Parse-Dashboard/app.js b/Parse-Dashboard/app.js index 2ecb143cf4..7dedd1b8fc 100644 --- a/Parse-Dashboard/app.js +++ b/Parse-Dashboard/app.js @@ -217,6 +217,7 @@ module.exports = function(config, options) { + `); @@ -257,6 +258,7 @@ module.exports = function(config, options) { + `); diff --git a/Parse-Dashboard/index.ejs b/Parse-Dashboard/index.ejs index 5ccf504d92..ae53f72c16 100644 --- a/Parse-Dashboard/index.ejs +++ b/Parse-Dashboard/index.ejs @@ -34,7 +34,8 @@ }()); - - + + + diff --git a/Parse-Dashboard/login.ejs b/Parse-Dashboard/login.ejs index f7d00cf744..ac4cba26cd 100644 --- a/Parse-Dashboard/login.ejs +++ b/Parse-Dashboard/login.ejs @@ -36,5 +36,6 @@ + diff --git a/README.md b/README.md index 5c439fbf62..b61bb8f32b 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ [![Build Status](https://github.com/parse-community/parse-dashboard/workflows/ci/badge.svg?branch=release)](https://github.com/parse-community/parse-dashboard/actions?query=workflow%3Aci+branch%3Arelease) [![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-14,_16,_18-green.svg?logo=node.js&style=flat)](https://nodejs.org/) +[![Node Version](https://img.shields.io/badge/nodejs-18,_20-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) @@ -107,9 +107,8 @@ Parse Dashboard is continuously tested with the most recent releases of Node.js | Version | Latest Version | End-of-Life | Compatible | |------------|----------------|-------------|------------| -| Node.js 14 | 14.20.1 | April 2023 | ✅ Yes | -| Node.js 16 | 16.17.0 | April 2024 | ✅ Yes | -| Node.js 18 | 18.9.0 | May 2025 | ✅ Yes | +| Node.js 18 | 18.9.1 | May 2025 | ✅ Yes | +| Node.js 20 | 20.11.1 | April 2026 | ✅ Yes | ## Configuring Parse Dashboard diff --git a/changelogs/CHANGELOG_alpha.md b/changelogs/CHANGELOG_alpha.md index bb07cb68f7..37f772648c 100644 --- a/changelogs/CHANGELOG_alpha.md +++ b/changelogs/CHANGELOG_alpha.md @@ -1,3 +1,79 @@ +# [6.0.0-alpha.1](https://github.com/ParsePlatform/parse-dashboard/compare/5.4.0-alpha.8...6.0.0-alpha.1) (2024-03-05) + + +### Features + +* Add Node 20 support; remove Node 14, 16 support ([#2532](https://github.com/ParsePlatform/parse-dashboard/issues/2532)) ([578a339](https://github.com/ParsePlatform/parse-dashboard/commit/578a339c04990b5ecb3f80d34c690c6d34218bfa)) +* Add Node 20 support; remove Node 14, 16 support ([#2535](https://github.com/ParsePlatform/parse-dashboard/issues/2535)) ([5c90f2d](https://github.com/ParsePlatform/parse-dashboard/commit/5c90f2de1b98a2099453c8f8c0d6817330f7133d)) + + +### BREAKING CHANGES + +* Removes support for Node 14 and 16 ([5c90f2d](5c90f2d)) + +# [5.4.0-alpha.8](https://github.com/ParsePlatform/parse-dashboard/compare/5.4.0-alpha.7...5.4.0-alpha.8) (2024-02-29) + + +### Bug Fixes + +* Config page fails to load ([#2531](https://github.com/ParsePlatform/parse-dashboard/issues/2531)) ([d721b7c](https://github.com/ParsePlatform/parse-dashboard/commit/d721b7c4f3b98df96a229e60529604b038857d53)) + +# [5.4.0-alpha.7](https://github.com/ParsePlatform/parse-dashboard/compare/5.4.0-alpha.6...5.4.0-alpha.7) (2024-02-26) + + +### Features + +* Add descriptive statistics for number cells in data browser ([#2529](https://github.com/ParsePlatform/parse-dashboard/issues/2529)) ([ead9ec4](https://github.com/ParsePlatform/parse-dashboard/commit/ead9ec4d39abc211540bc76616498533b31001a6)) + +# [5.4.0-alpha.6](https://github.com/ParsePlatform/parse-dashboard/compare/5.4.0-alpha.5...5.4.0-alpha.6) (2024-02-26) + + +### Bug Fixes + +* App metrics for user and installation counts show dash ([#2528](https://github.com/ParsePlatform/parse-dashboard/issues/2528)) ([850d7b3](https://github.com/ParsePlatform/parse-dashboard/commit/850d7b3f20160761a21f68ec398d7207b8226770)) + +# [5.4.0-alpha.5](https://github.com/ParsePlatform/parse-dashboard/compare/5.4.0-alpha.4...5.4.0-alpha.5) (2024-02-18) + + +### Bug Fixes + +* Open pointer in new tab in data browser not working when mount path is not root ([#2527](https://github.com/ParsePlatform/parse-dashboard/issues/2527)) ([2f4081f](https://github.com/ParsePlatform/parse-dashboard/commit/2f4081f217e1c5d906ed8789e09a3377ddc15121)) + +# [5.4.0-alpha.4](https://github.com/ParsePlatform/parse-dashboard/compare/5.4.0-alpha.3...5.4.0-alpha.4) (2024-02-15) + + +### Bug Fixes + +* Data browser redirects to wrong class when changing app ([#2526](https://github.com/ParsePlatform/parse-dashboard/issues/2526)) ([7713f54](https://github.com/ParsePlatform/parse-dashboard/commit/7713f542ef9ef97cbf784fa267f7ea2a51c9472a)) + +# [5.4.0-alpha.3](https://github.com/ParsePlatform/parse-dashboard/compare/5.4.0-alpha.2...5.4.0-alpha.3) (2023-12-16) + + +### Bug Fixes + +* Dashboard crashes if Parse Server Cloud Function script returns object ([#2516](https://github.com/ParsePlatform/parse-dashboard/issues/2516)) ([5de08f8](https://github.com/ParsePlatform/parse-dashboard/commit/5de08f8f4d67f287a589c70d8b8d36f9f76897cf)) + +# [5.4.0-alpha.2](https://github.com/ParsePlatform/parse-dashboard/compare/5.4.0-alpha.1...5.4.0-alpha.2) (2023-12-16) + + +### Features + +* Execute script for selected rows ([#2508](https://github.com/ParsePlatform/parse-dashboard/issues/2508)) ([5d9901e](https://github.com/ParsePlatform/parse-dashboard/commit/5d9901e27b14517f22993ac094bdd7d8fbac401f)) + +# [5.4.0-alpha.1](https://github.com/ParsePlatform/parse-dashboard/compare/5.3.0...5.4.0-alpha.1) (2023-12-02) + + +### Features + +* Add refresh indicator to Cloud Config page ([#2505](https://github.com/ParsePlatform/parse-dashboard/issues/2505)) ([a10d1f0](https://github.com/ParsePlatform/parse-dashboard/commit/a10d1f0825688d403206ce7cbacada191dbf5c3b)) + +# [5.3.0-alpha.2](https://github.com/ParsePlatform/parse-dashboard/compare/5.3.0-alpha.1...5.3.0-alpha.2) (2023-10-18) + + +### Features + +* Add refresh indicator to Cloud Config page ([#2505](https://github.com/ParsePlatform/parse-dashboard/issues/2505)) ([a10d1f0](https://github.com/ParsePlatform/parse-dashboard/commit/a10d1f0825688d403206ce7cbacada191dbf5c3b)) + # [5.3.0-alpha.1](https://github.com/ParsePlatform/parse-dashboard/compare/5.2.0...5.3.0-alpha.1) (2023-09-20) diff --git a/changelogs/CHANGELOG_beta.md b/changelogs/CHANGELOG_beta.md index 269484967d..6239f56bbb 100644 --- a/changelogs/CHANGELOG_beta.md +++ b/changelogs/CHANGELOG_beta.md @@ -1,3 +1,10 @@ +# [5.4.0-beta.1](https://github.com/ParsePlatform/parse-dashboard/compare/5.3.0...5.4.0-beta.1) (2023-11-16) + + +### Features + +* Add refresh indicator to Cloud Config page ([#2505](https://github.com/ParsePlatform/parse-dashboard/issues/2505)) ([a10d1f0](https://github.com/ParsePlatform/parse-dashboard/commit/a10d1f0825688d403206ce7cbacada191dbf5c3b)) + # [5.3.0-beta.1](https://github.com/ParsePlatform/parse-dashboard/compare/5.2.0...5.3.0-beta.1) (2023-09-15) diff --git a/changelogs/CHANGELOG_release.md b/changelogs/CHANGELOG_release.md index 690a58f24b..00b1250f81 100644 --- a/changelogs/CHANGELOG_release.md +++ b/changelogs/CHANGELOG_release.md @@ -1,3 +1,29 @@ +# [5.3.0](https://github.com/ParsePlatform/parse-dashboard/compare/5.2.0...5.3.0) (2023-11-16) + + +### Bug Fixes + +* Adding a file when adding a new row in the data browser doesn't show filename ([#2471](https://github.com/ParsePlatform/parse-dashboard/issues/2471)) ([5bbb94e](https://github.com/ParsePlatform/parse-dashboard/commit/5bbb94e5b5266af5ed770d0241605eb859699831)) +* File extension is hidden in file field when editing object in modal dialog in data browser ([#2472](https://github.com/ParsePlatform/parse-dashboard/issues/2472)) ([8df4e4d](https://github.com/ParsePlatform/parse-dashboard/commit/8df4e4d9abf2ef9e487a48b209f33bedc03b55a3)) +* Incorrect highlight maker position in class list in data browser ([#2490](https://github.com/ParsePlatform/parse-dashboard/issues/2490)) ([8c28d24](https://github.com/ParsePlatform/parse-dashboard/commit/8c28d245cfe5d9558ffd276b9660f73449c4f35a)) +* Pasting location coordinates into field of type `GeoPoint` does not work in data browser ([#2464](https://github.com/ParsePlatform/parse-dashboard/issues/2464)) ([a8ce343](https://github.com/ParsePlatform/parse-dashboard/commit/a8ce3436a4ffe76ccf892965fa21dc2a467e2d14)) +* Selecting a saved filter in data browser also highlights other filters with equal names ([#2466](https://github.com/ParsePlatform/parse-dashboard/issues/2466)) ([35360fe](https://github.com/ParsePlatform/parse-dashboard/commit/35360fec68edbca619075227960062859bb9db2e)) +* Vertical scrollbar in data browser is outside visible area when scrolling horizontally ([#2457](https://github.com/ParsePlatform/parse-dashboard/issues/2457)) ([5acac3f](https://github.com/ParsePlatform/parse-dashboard/commit/5acac3fb5c74cbb24ec96b721d874fbc36096c39)) + +### Features + +* Add Cloud Function execution on Parse Object in data browser ([#2409](https://github.com/ParsePlatform/parse-dashboard/issues/2409)) ([996ce91](https://github.com/ParsePlatform/parse-dashboard/commit/996ce916bfedb92c36deede4c234dde8c0554cbb)) +* Add parameter `selectedField` to script payload to determine which object field was selected when script was invoked ([#2483](https://github.com/ParsePlatform/parse-dashboard/issues/2483)) ([e98d653](https://github.com/ParsePlatform/parse-dashboard/commit/e98d653b96787720dad5310c5af98869e2ac2923)) +* Add refresh button to Cloud Config page ([#2480](https://github.com/ParsePlatform/parse-dashboard/issues/2480)) ([be212b0](https://github.com/ParsePlatform/parse-dashboard/commit/be212b0ad6c777f7c5ee9a74cac0affa63faa1c1)) +* Add security checks page ([#2491](https://github.com/ParsePlatform/parse-dashboard/issues/2491)) ([103b9c6](https://github.com/ParsePlatform/parse-dashboard/commit/103b9c61d152487898062485b40f11ecdac3d2e7)) +* Add support for confirmation dialog before script execution in data browser ([#2481](https://github.com/ParsePlatform/parse-dashboard/issues/2481)) ([64d3913](https://github.com/ParsePlatform/parse-dashboard/commit/64d391320bbdb519af8ff93fe8579315ef48e36e)) +* Add typing with auto-complete to select a filter field in the data browser ([#2463](https://github.com/ParsePlatform/parse-dashboard/issues/2463)) ([257f76b](https://github.com/ParsePlatform/parse-dashboard/commit/257f76bbf8d1e880e3b7b704edee2eebf76451c8)) +* Reopen last opened class when navigating to data browser ([#2468](https://github.com/ParsePlatform/parse-dashboard/issues/2468)) ([3d7148e](https://github.com/ParsePlatform/parse-dashboard/commit/3d7148e75a6e9eaeeb7cbb546885b5916f6025bb)) + +### Reverts + +* fix: Vertical scrollbar in data browser is outside visible area when scrolling horizontally ([#2457](https://github.com/ParsePlatform/parse-dashboard/issues/2457)) ([#2477](https://github.com/ParsePlatform/parse-dashboard/issues/2477)) ([2f1d84e](https://github.com/ParsePlatform/parse-dashboard/commit/2f1d84e41c24507b516b933037807f1061182991)) + # [5.2.0](https://github.com/ParsePlatform/parse-dashboard/compare/5.1.0...5.2.0) (2023-09-15) diff --git a/nginx-uffizzi/nginx.conf b/nginx-uffizzi/nginx.conf index 137e462c42..589caf8c85 100644 --- a/nginx-uffizzi/nginx.conf +++ b/nginx-uffizzi/nginx.conf @@ -17,7 +17,7 @@ http { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-NginX-Proxy true; - proxy_pass http://localhost:4040/dashboard/; + proxy_pass http://localhost:4040; proxy_ssl_session_reuse off; proxy_set_header Host $http_host; proxy_redirect off; @@ -29,7 +29,7 @@ http { proxy_set_header X-Real-IP $remote_addr; keepalive_requests 10; keepalive_timeout 75s; - proxy_pass http://localhost:1337/parse/; + proxy_pass http://localhost:1337; proxy_http_version 1.1; } } diff --git a/package.json b/package.json index 7b7cc099c4..dc262adda3 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "core-js": "3.28.0", "csurf": "1.11.0", "csvtojson": "2.0.10", - "express": "4.18.1", + "express": "4.19.2", "file-loader": "6.2.0", "graphiql": "2.0.8", "graphql": "16.8.1", @@ -64,7 +64,7 @@ "intro.js": "2.9.3", "jquery": "3.7.1", "js-base64": "3.7.5", - "js-beautify": "1.14.6", + "js-beautify": "1.14.10", "js-cookie": "3.0.5", "jstree": "3.3.16", "lottie-react": "2.4.0", @@ -178,7 +178,7 @@ "parse-dashboard": "./bin/parse-dashboard" }, "engines": { - "node": ">=14.20.1" + "node": ">=18.0.0 <21" }, "main": "Parse-Dashboard/app.js", "jest": { diff --git a/src/components/B4ACodeTree/B4ACodeTree.react.js b/src/components/B4ACodeTree/B4ACodeTree.react.js index 00abb46ce5..d562bba98b 100644 --- a/src/components/B4ACodeTree/B4ACodeTree.react.js +++ b/src/components/B4ACodeTree/B4ACodeTree.react.js @@ -11,6 +11,7 @@ import B4ATreeActions from 'components/B4ACodeTree/B4ATreeActions'; import Swal from 'sweetalert2'; import B4ACloudCodeInfo from 'components/B4ACodeTree/B4ACloudCodeInfo.react'; import folderInfoIcon from './icons/folder-info.png'; +import B4aEmptyState from 'components/B4aEmptyState/B4aEmptyState.react'; // import CloudCodeChanges from 'lib/CloudCodeChanges'; import PropTypes from 'lib/PropTypes'; import Icon from 'components/Icon/Icon.react'; @@ -266,9 +267,9 @@ export default class B4ACodeTree extends React.Component { content = ; } else if (this.state.isFolderSelected === true) { - content = this.state.source && this.state.source !== '' ? :
; } else if (this.state.selectedFile) { @@ -293,7 +294,7 @@ export default class B4ACodeTree extends React.Component { ; } else { content = ( - + ); } diff --git a/src/components/B4aEmptyState/B4aEmptyState.react.js b/src/components/B4aEmptyState/B4aEmptyState.react.js index bbc2f2f03c..c45ae9b44a 100644 --- a/src/components/B4aEmptyState/B4aEmptyState.react.js +++ b/src/components/B4aEmptyState/B4aEmptyState.react.js @@ -26,11 +26,10 @@ const ctaButton = (cta, action, primary = true) => { }; -const B4aEmptyState = ({ icon = 'ghost-icon', title, description, cta = '', action = () => {}, secondaryCta = '', secondaryAction = () => {}, fill = '#C1E2FF'}) => { +const B4aEmptyState = ({ imgSrc = ghostImg, title, description, cta = '', action = () => {}, secondaryCta = '', secondaryAction = () => {}, dark = true, margin }) => { return ( -
- empty state - {/* */} +
+ empty state
{title}
{description}
diff --git a/src/components/B4aEmptyState/B4aEmptyState.scss b/src/components/B4aEmptyState/B4aEmptyState.scss index 32507d23c6..46c6ad64c9 100644 --- a/src/components/B4aEmptyState/B4aEmptyState.scss +++ b/src/components/B4aEmptyState/B4aEmptyState.scss @@ -63,4 +63,13 @@ } } + &.light { + .title { + color: $dark; + } + .description { + color: $regal-blue; + } + } + } \ No newline at end of file diff --git a/src/components/BrowserCell/BrowserCell.react.js b/src/components/BrowserCell/BrowserCell.react.js index be47f85b36..1f58f6c670 100644 --- a/src/components/BrowserCell/BrowserCell.react.js +++ b/src/components/BrowserCell/BrowserCell.react.js @@ -539,6 +539,8 @@ class BrowserCell extends Component { isRequired, markRequiredFieldRow, readonly, + handleCellClick, + selectedCells, } = this.props; const classes = [...this.state.classes]; @@ -576,6 +578,22 @@ class BrowserCell extends Component { ); } + if (selectedCells?.list.has(`${row}-${col}`)) { + if (selectedCells.rowStart === row) { + classes.push(styles.topBorder); + } + if (selectedCells.rowEnd === row) { + classes.push(styles.bottomBorder); + } + if (selectedCells.colStart === col) { + classes.push(styles.leftBorder); + } + if (selectedCells.colEnd === col) { + classes.push(styles.rightBorder); + } + classes.push(styles.selected); + } + const content = { diff --git a/src/components/BrowserCell/BrowserCell.scss b/src/components/BrowserCell/BrowserCell.scss index 7252bd32d1..d29e9a9064 100644 --- a/src/components/BrowserCell/BrowserCell.scss +++ b/src/components/BrowserCell/BrowserCell.scss @@ -41,6 +41,72 @@ // opacity: .9; // } + +.leftBorder { + position: relative; + + &:after { + position: absolute; + pointer-events: none; + content: ''; + border-left: 2px solid #555572; + top: 0; + left: 0; + right: 0; + bottom: 0; + } +} + +.rightBorder { + position: relative; + + &:after { + position: absolute; + pointer-events: none; + content: ''; + border-right: 2px solid #555572; + top: 0; + left: 0; + right: 0; + bottom: 0; + } +} + +.topBorder { + position: relative; + + &:after { + position: absolute; + pointer-events: none; + content: ''; + border-top: 2px solid #555572; + top: 0; + left: 0; + right: 0; + bottom: 0; + } +} + +.bottomBorder { + position: relative; + + &:after { + position: absolute; + pointer-events: none; + content: ''; + border-bottom: 2px solid #555572; + top: 0; + left: 0; + right: 0; + bottom: 0; + } +} + +.selected { + background-color: #e3effd; +} + + .hasMore{ height: auto; max-height: 25px; diff --git a/src/components/BrowserRow/BrowserRow.react.js b/src/components/BrowserRow/BrowserRow.react.js index e2ca8b36c3..fdd58508e6 100644 --- a/src/components/BrowserRow/BrowserRow.react.js +++ b/src/components/BrowserRow/BrowserRow.react.js @@ -155,6 +155,8 @@ export default class BrowserRow extends Component { showNote={this.props.showNote} onRefresh={this.props.onRefresh} scripts={this.props.scripts} + handleCellClick={this.props.handleCellClick} + selectedCells={this.props.selectedCells} />
diff --git a/src/components/Dropdown/Dropdown.scss b/src/components/Dropdown/Dropdown.scss index aff5b73e8e..a5074e4d80 100644 --- a/src/components/Dropdown/Dropdown.scss +++ b/src/components/Dropdown/Dropdown.scss @@ -20,6 +20,15 @@ &.dark { background: $regal-blue; color: $white; + + & .current { + &:not(.hideArrow){ + &:after { + border-right: 1px solid $white; + border-bottom: 1px solid $white; + } + } + } } } @@ -86,10 +95,11 @@ border-right: 1px solid $dark-blue; border-bottom: 1px solid $dark-blue; transform: rotate(45deg); + transition: 0.3s; } &.arrowUp::after { - transform: rotate(226deg); + transform: rotate(226deg) translate(-2px, -5px); } } diff --git a/src/components/FormTableCollab/FormTableCollab.scss b/src/components/FormTableCollab/FormTableCollab.scss index ea65c7a235..6ff9258c6d 100644 --- a/src/components/FormTableCollab/FormTableCollab.scss +++ b/src/components/FormTableCollab/FormTableCollab.scss @@ -23,7 +23,7 @@ .title { @include ellipsis(); display: inline-block; - width: 100%; + width: 75%; padding-right: 20px; } diff --git a/src/components/Sidebar/B4aSidebar.scss b/src/components/Sidebar/B4aSidebar.scss index d2d2a9ac1f..b647ab3334 100644 --- a/src/components/Sidebar/B4aSidebar.scss +++ b/src/components/Sidebar/B4aSidebar.scss @@ -455,6 +455,7 @@ a.subitem { } &:hover { + cursor: pointer; svg { fill: $white; } diff --git a/src/components/Sidebar/Sidebar.scss b/src/components/Sidebar/Sidebar.scss index a355a15250..9185793eb3 100644 --- a/src/components/Sidebar/Sidebar.scss +++ b/src/components/Sidebar/Sidebar.scss @@ -452,6 +452,7 @@ a.subitem { display: flex; justify-content: center; align-items: center; + cursor: pointer; svg { fill: $white; transform: rotate(90deg); diff --git a/src/components/Toolbar/Toolbar.react.js b/src/components/Toolbar/Toolbar.react.js index 5c344063ad..6949a6215d 100644 --- a/src/components/Toolbar/Toolbar.react.js +++ b/src/components/Toolbar/Toolbar.react.js @@ -6,10 +6,109 @@ * the root directory of this source tree. */ import PropTypes from 'lib/PropTypes'; -import React from 'react'; +import React, { useEffect } from 'react'; import Icon from 'components/Icon/Icon.react'; import styles from 'components/Toolbar/Toolbar.scss'; -import { useNavigate, useNavigationType } from 'react-router-dom'; +import Popover from 'components/Popover/Popover.react'; +import Position from 'lib/Position'; +import { useNavigate, useNavigationType, NavigationType } from 'react-router-dom'; + +const POPOVER_CONTENT_ID = 'toolbarStatsPopover'; + +const Stats = ({ data }) => { + const [selected, setSelected] = React.useState(null); + const [open, setOpen] = React.useState(false); + const buttonRef = React.useRef(); + + const statsOptions = [ + { + type: 'sum', + label: 'Sum', + getValue: data => data.reduce((sum, value) => sum + value, 0), + }, + { + type: 'mean', + label: 'Mean', + getValue: data => data.reduce((sum, value) => sum + value, 0) / data.length, + }, + { + type: 'count', + label: 'Count', + getValue: data => data.length, + }, + { + type: 'p99', + label: 'P99', + getValue: data => { + const sorted = data.sort((a, b) => a - b); + return sorted[Math.floor(sorted.length * 0.99)]; + }, + }, + ]; + + const toggle = () => { + setOpen(!open); + }; + + const renderPopover = () => { + const node = buttonRef.current; + const position = Position.inDocument(node); + return ( + +
+
+
+ {statsOptions.map(item => { + const itemStyle = [styles.stats_popover_item]; + if (item.type === selected?.type) { + itemStyle.push(styles.active); + } + return ( +
{ + setSelected(item); + toggle(); + }} + > + {item.label} +
+ ); + })} +
+
+
+ ); + }; + + useEffect(() => { + setSelected(statsOptions[0]); + }, []); + + return ( + <> + {selected ? ( + + ) : null} + {open ? renderPopover() : null} + + ); +}; const Toolbar = props => { const action = useNavigationType(); @@ -55,6 +154,7 @@ const Toolbar = props => {
+ {props?.selectedData?.length ? : null}
{props.children}
); @@ -65,6 +165,7 @@ Toolbar.propTypes = { subsection: PropTypes.string, details: PropTypes.string, relation: PropTypes.object, + selectedData: PropTypes.array, }; export default Toolbar; diff --git a/src/components/Toolbar/Toolbar.scss b/src/components/Toolbar/Toolbar.scss index 06b2fb8304..5b95a630f4 100644 --- a/src/components/Toolbar/Toolbar.scss +++ b/src/components/Toolbar/Toolbar.scss @@ -186,4 +186,43 @@ body:global(.sidebarCollapsed) { .publicAccess { display: none; } -} \ No newline at end of file +} +.stats { + position: absolute; + right: 20px; + bottom: 10px; + background: $blue; + border-radius: 3px; + padding: 2px 6px; + font-size: 14px; + color: white; + box-shadow: none; + border: none; +} + +.stats_popover_container { + display: flex; + flex-direction: column; + background: $blue; + border-radius: 3px; + margin-top: 1px; + gap: 2px; + padding: 2px 0px; + font-size: 14px; + color: white; +} + +.stats_popover_item { + cursor: pointer; + padding: 0px 6px; + + &:hover { + color: $blue; + background-color: white; + } +} + +.active { + color: $blue; + background-color: white; +} diff --git a/src/dashboard/Apps/AppsIndex.react.js b/src/dashboard/Apps/AppsIndex.react.js index 8c78c96a07..8ffe3f84bd 100644 --- a/src/dashboard/Apps/AppsIndex.react.js +++ b/src/dashboard/Apps/AppsIndex.react.js @@ -144,6 +144,7 @@ class AppsIndex extends React.Component { if (nextApp.serverInfo.status !== prevApp.serverInfo.status && nextApp.serverInfo.status === 'SUCCESS') { // app's status changed this.getAppsIndexStats(nextApp); + this.forceUpdate(); } } diff --git a/src/dashboard/Dashboard.js b/src/dashboard/Dashboard.js index bea2f53160..27b84ef05a 100644 --- a/src/dashboard/Dashboard.js +++ b/src/dashboard/Dashboard.js @@ -73,7 +73,7 @@ import DashboardSettings from './Settings/DashboardSettings/DashboardSettings.re import Security from './Settings/Security/Security.react'; import { Navbar } from '@back4app2/react-components'; import back4app2 from '../lib/back4app2'; -import { initializeAmplitude } from 'lib/amplitudeEvents'; +import { initializeAmplitude, initializeLogRocketSession } from 'lib/amplitudeEvents'; const ShowSchemaOverview = false; //In progress features. Change false to true to work on this feature. @@ -227,6 +227,10 @@ class Dashboard extends React.Component { } initializeAmplitude(user.email); + waitForScriptToLoad(() => typeof window.LogRocket !== 'undefined').then(() => { + // eslint-disable-next-line no-undef + initializeLogRocketSession(user.email); + }).catch(err => console.log(err)); // fetch serverInfo request for each app apps.forEach(async (app) => { diff --git a/src/dashboard/Data/ApiConsole/RestConsole.react.js b/src/dashboard/Data/ApiConsole/RestConsole.react.js index f5e6634018..15cc7eef06 100644 --- a/src/dashboard/Data/ApiConsole/RestConsole.react.js +++ b/src/dashboard/Data/ApiConsole/RestConsole.react.js @@ -299,22 +299,17 @@ export default class RestConsole extends Component { - - } - secondary={ -