Compare commits

...

32 Commits

Author SHA1 Message Date
Alex Meijer c855f42c00
Merge pull request #94 from opencost/dependabot/github_actions/tspascoal/get-user-teams-membership-3
Bump tspascoal/get-user-teams-membership from 2 to 3
2025-08-07 13:53:36 -04:00
Alex Meijer 1e0e0f9d2c
Merge branch 'main' into dependabot/github_actions/tspascoal/get-user-teams-membership-3 2025-08-07 13:53:28 -04:00
Alex Meijer b182f8eeed
Merge pull request #99 from opencost/dependabot/npm_and_yarn/babel/core-7.28.0
Bump @babel/core from 7.26.8 to 7.28.0
2025-08-07 13:47:35 -04:00
Alex Meijer 474f285864
Merge branch 'main' into dependabot/npm_and_yarn/babel/core-7.28.0 2025-08-07 13:47:05 -04:00
Alex Meijer aa0c95ddd2
Merge pull request #103 from cpetersen5/main
Change order of checkout steps
2025-08-07 12:22:34 -04:00
Christian Petersen 3dff690f8a
Change order of checkout steps 2025-08-07 10:19:59 -06:00
Alex Meijer 0d59411e83
Merge pull request #102 from cpetersen5/main
Add step to checkout opencost-ui in Build and Publish Release workflow
2025-08-07 12:15:02 -04:00
Christian Petersen a6f8efa219
Merge branch 'main' of github.com:cpetersen5/opencost-ui 2025-08-07 10:12:52 -06:00
Christian Petersen 7b32959631
Add step to checkout opencost-ui in Build and Publish Release workflow 2025-08-07 10:12:34 -06:00
Christian Petersen 980c996947
Merge branch 'opencost:main' into main 2025-08-07 10:10:37 -06:00
Alex Meijer 61747f15f4
Merge pull request #101 from cpetersen5/main
Remove working directory from build and publish container step
2025-08-07 12:03:20 -04:00
Christian Petersen dda060aa0f
Remove working directory from build and publish container step
Signed-off-by: Christian Petersen <Christian.Petersen2@ibm.com>
2025-08-07 10:03:11 -06:00
Christian Petersen e68fb9cd2d
Remove working directory from build and publish container step 2025-08-07 10:01:10 -06:00
Alex Meijer 09fe99a22d
Merge pull request #100 from SharmaVansh1910/patch-1
Update README.md: Fix Links
2025-08-01 11:44:50 -04:00
VANSH SHARMA b8e5256ba4
Update README.md
Signed-off-by: VANSH SHARMA <vansh1910sharma@gmail.com>
2025-08-01 21:07:36 +05:30
Alex Meijer a1760dacad
Merge pull request #97 from reschandreas/main
fix images and loading of external costs
2025-07-28 07:43:02 -04:00
dependabot[bot] 0fbfae1751
Bump @babel/core from 7.26.8 to 7.28.0
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.26.8 to 7.28.0.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.28.0/packages/babel-core)

---
updated-dependencies:
- dependency-name: "@babel/core"
  dependency-version: 7.28.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-28 05:16:58 +00:00
Andreas Resch 3b9b26fbf8
fix images and loading of external costs
Signed-off-by: Andreas Resch <andreas@resch.io>
2025-07-27 09:24:20 +02:00
Alex Meijer 6444dffdea
Merge pull request #77 from opencost/dependabot/npm_and_yarn/date-io/core-3.2.0
Bump @date-io/core from 1.3.13 to 3.2.0
2025-07-24 16:23:16 -04:00
Alex Meijer 483d4b4d02
Merge branch 'main' into dependabot/npm_and_yarn/date-io/core-3.2.0 2025-07-24 14:54:04 -04:00
Alex Meijer 244d62b05d
Merge pull request #84 from andoriyaprashant/tablepagination
Fix deprecated and missing props in TablePagination
2025-07-10 14:13:50 -04:00
dependabot[bot] 243c07c117
Bump tspascoal/get-user-teams-membership from 2 to 3
Bumps [tspascoal/get-user-teams-membership](https://github.com/tspascoal/get-user-teams-membership) from 2 to 3.
- [Release notes](https://github.com/tspascoal/get-user-teams-membership/releases)
- [Commits](https://github.com/tspascoal/get-user-teams-membership/compare/v2...v3)

---
updated-dependencies:
- dependency-name: tspascoal/get-user-teams-membership
  dependency-version: '3'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-16 04:52:42 +00:00
Alex Meijer 82b4d90762
Merge branch 'main' into dependabot/npm_and_yarn/date-io/core-3.2.0 2025-06-12 11:36:42 -04:00
Alex Meijer 76ef9f7ba4
Merge pull request #93 from opencost/atm/trigger-demo-promotion-debug
bugfix
2025-06-09 13:54:01 -04:00
Alex Meijer 1eaf0ab553 bugfix
Signed-off-by: Alex Meijer <alexander.meijer@ibm.com>
2025-06-09 13:48:47 -04:00
Alex Meijer a81d15bf86
Merge pull request #92 from opencost/atm/trigger-demo-promotion-debug
debugging builds, refactor
2025-06-09 13:44:48 -04:00
Alex Meijer 7a35df1d05 debugging builds, refactor
Signed-off-by: Alex Meijer <alexander.meijer@ibm.com>
2025-06-09 12:33:31 -04:00
Alex Meijer 39b6cf4566
Merge pull request #91 from opencost/atm/trigger-demo-promotion
add automation to promote to demo
2025-06-09 10:58:00 -04:00
Alex Meijer 99774230e0 add automation to promote to demo
Signed-off-by: Alex Meijer <alexander.meijer@ibm.com>
2025-06-09 08:27:36 -04:00
Leonardo Rodrigues de Mello 56121e8565
Merge branch 'main' into tablepagination 2025-05-29 16:16:15 -04:00
andoriyaprashant 3ab380e20b Fix deprecated and missing props in TablePagination
Signed-off-by: andoriyaprashant <prashantandoriya@gmail.com>
2025-05-16 21:06:06 +05:30
dependabot[bot] 812c9924c5
Bump @date-io/core from 1.3.13 to 3.2.0
Bumps [@date-io/core](https://github.com/dmtrKovalenko/date-io) from 1.3.13 to 3.2.0.
- [Release notes](https://github.com/dmtrKovalenko/date-io/releases)
- [Commits](https://github.com/dmtrKovalenko/date-io/compare/v1.3.13...v3.2.0)

---
updated-dependencies:
- dependency-name: "@date-io/core"
  dependency-version: 3.2.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-23 13:23:56 +00:00
12 changed files with 391 additions and 185 deletions

View File

@ -0,0 +1,59 @@
name: 'Build Container'
description: 'Build and publish OpenCost UI container image'
inputs:
actor:
description: 'GitHub actor'
required: true
GITHUB_TOKEN:
description: 'GitHub token for authentication'
required: true
image_tag:
description: 'Full image tag to use for the container'
required: true
release_version:
description: 'Release version for the container'
required: true
registry:
description: 'Container registry to use'
required: true
default: 'ghcr.io'
runs:
using: "composite"
steps:
- name: Log into registry
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772
with:
registry: ${{ inputs.registry }}
username: ${{ inputs.actor }}
password: ${{ inputs.GITHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
buildkitd-flags: --debug
- name: Set up just
uses: extractions/setup-just@v3
- name: Install crane
uses: imjasonh/setup-crane@v0.3
- name: Install manifest-tool
run: |
mkdir -p manifest-tool
pushd manifest-tool
wget -q https://github.com/estesp/manifest-tool/releases/download/v2.0.8/binaries-manifest-tool-2.0.8.tar.gz
tar -xzf binaries-manifest-tool-2.0.8.tar.gz
cp manifest-tool-linux-amd64 manifest-tool
echo "$(pwd)" >> $GITHUB_PATH
shell: bash
- name: Build and push (multiarch)
env:
IMAGE_TAG: ${{ inputs.image_tag }}
RELEASE_VERSION: ${{ inputs.release_version }}
run: |
just build "$IMAGE_TAG" "$RELEASE_VERSION"
shell: bash

View File

@ -0,0 +1,59 @@
name: Build and Publish Develop UI
on:
workflow_run:
workflows: [Build/Test]
types: [completed]
branches: [main]
concurrency:
group: build-opencost-ui-develop
cancel-in-progress: false
env:
# Use docker.io for Docker Hub if empty
REGISTRY: ghcr.io
jobs:
build-and-publish-opencost-ui:
runs-on: ubuntu-latest
if: ${{ github.event.workflow_run.conclusion == 'success' }}
permissions:
contents: read
packages: write
steps:
- name: Checkout Repo
uses: actions/checkout@v4
- name: Set SHA
id: sha
run: |
echo "OC_SHORTHASH=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
- name: Set OpenCost Image Tags
id: tags
run: |
echo "IMAGE_TAG=ghcr.io/${{ github.repository_owner }}/opencost-ui:develop-${{ steps.sha.outputs.OC_SHORTHASH }}" >> $GITHUB_OUTPUT
- name: Build and publish container
uses: ./.github/actions/build-container
with:
actor: ${{ github.actor }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
image_tag: ${{ steps.tags.outputs.IMAGE_TAG }}
release_version: develop-${{ steps.sha.outputs.OC_SHORTHASH }}
registry: ${{ env.REGISTRY }}
- name: Install crane
uses: imjasonh/setup-crane@v0.4
- name: Tag and push latest image
run: |
# Extract the repository part (everything before the last colon)
REPO=$(echo "${{ steps.tags.outputs.IMAGE_TAG }}" | sed 's/:.*$//')
# Create the new tag
NEW_TAG="${REPO}:develop-latest"
echo "Copying ${{ steps.tags.outputs.IMAGE_TAG }} to ${NEW_TAG}"
crane copy "${{ steps.tags.outputs.IMAGE_TAG }}" "${NEW_TAG}"

View File

@ -59,6 +59,12 @@ jobs:
VERSION_NUMBER=${{ steps.version_number.outputs.RELEASE_VERSION }}
echo "BRANCH_NAME=v${VERSION_NUMBER%.*}" >> $GITHUB_ENV
# checkout opencost UI to allow access to actions
- name: Checkout actions
uses: actions/checkout@v4
with:
repository: 'opencost/opencost-ui'
- name: Checkout Repo
uses: actions/checkout@v4
with:
@ -73,15 +79,6 @@ jobs:
echo "OC_SHORTHASH=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
popd
# Login against a Docker registry except on PR
# https://github.com/docker/login-action
- name: Log into registry ${{ env.REGISTRY }}
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set OpenCost Image Tags
id: tags
run: |
@ -89,36 +86,17 @@ jobs:
echo "IMAGE_TAG_UI_LATEST=ghcr.io/opencost/opencost-ui:latest" >> $GITHUB_OUTPUT
echo "IMAGE_TAG_UI_VERSION=ghcr.io/opencost/opencost-ui:${{ steps.version_number.outputs.RELEASE_VERSION }}" >> $GITHUB_OUTPUT
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and publish container
uses: ./.github/actions/build-container
with:
buildkitd-flags: --debug
- name: Set up just
uses: extractions/setup-just@v3
actor: ${{ github.actor }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
image_tag: ${{ steps.tags.outputs.IMAGE_TAG_UI }}
release_version: ${{ steps.version_number.outputs.RELEASE_VERSION }}
registry: ${{ env.REGISTRY }}
- name: Install crane
uses: imjasonh/setup-crane@v0.3
## Install manifest-tool, which is required to combine multi-arch images
## https://github.com/estesp/manifest-tool
- name: Install manifest-tool
uses: imjasonh/setup-crane@v0.4
- name: Tag and push latest image
run: |
mkdir -p manifest-tool
pushd manifest-tool
wget -q https://github.com/estesp/manifest-tool/releases/download/v2.0.8/binaries-manifest-tool-2.0.8.tar.gz
tar -xzf binaries-manifest-tool-2.0.8.tar.gz
cp manifest-tool-linux-amd64 manifest-tool
echo "$(pwd)" >> $GITHUB_PATH
- name: Build and push (multiarch) OpenCost UI
working-directory: ./opencost-ui
env:
IMAGE_TAG_UI: ${{ steps.tags.outputs.IMAGE_TAG_UI }}
IMAGE_TAG_UI_LATEST: ${{ steps.tags.outputs.IMAGE_TAG_UI_LATEST }}
IMAGE_TAG_UI_VERSION: ${{ steps.tags.outputs.IMAGE_TAG_UI_VERSION }}
RELEASE_VERSION: ${{ steps.version_number.outputs.RELEASE_VERSION }}
run: |
just build "$IMAGE_TAG_UI" "$RELEASE_VERSION"
crane copy "$IMAGE_TAG_UI" "$IMAGE_TAG_UI_LATEST"
crane copy "$IMAGE_TAG_UI" "$IMAGE_TAG_UI_VERSION"
crane copy "${{ steps.tags.outputs.IMAGE_TAG_UI }}" "${{ steps.tags.outputs.IMAGE_TAG_UI_LATEST }}"
crane copy "${{ steps.tags.outputs.IMAGE_TAG_UI }}" "${{ steps.tags.outputs.IMAGE_TAG_UI_VERSION }}"

61
.github/workflows/build-test-image.yml vendored Normal file
View File

@ -0,0 +1,61 @@
name: Build and Publish UI Test Image
on:
merge_group:
types: [checks_requested]
pull_request_target:
branches:
- main
env:
REGISTRY: ghcr.io
jobs:
check_actor_permissions:
runs-on: ubuntu-latest
if: ${{ github.event_name == 'pull_request_target' }}
outputs:
ismaintainer: ${{ steps.determine-maintainer.outputs.ismaintainer }}
steps:
- name: Check team membership
uses: tspascoal/get-user-teams-membership@v3
id: teamAffiliation
with:
GITHUB_TOKEN: ${{ secrets.ORG_READER_PAT }}
username: ${{ github.actor }}
organization: opencost
- name: determine if actor is a maintainer
id: determine-maintainer
run: |
echo "Actor: ${{ github.actor }}"
echo "Is maintainer: ${{ contains(steps.teamAffiliation.outputs.teams, 'OpenCost Maintainers') || contains(github.actor, 'dependabot[bot]') }}"
echo "ismaintainer=${{ contains(steps.teamAffiliation.outputs.teams, 'OpenCost Maintainers') || contains(github.actor, 'dependabot[bot]') }}" >> $GITHUB_OUTPUT
build-and-publish-test-image:
runs-on: ubuntu-latest
needs: check_actor_permissions
if: ${{ (always() && !cancelled()) && ( github.event_name == 'merge_group' || needs.check_actor_permissions.outputs.ismaintainer == 'true') }}
permissions:
contents: read
packages: write
steps:
- name: Checkout Repo
uses: actions/checkout@v4
with:
ref: ${{ github.event.merge_group.head_sha || github.event.pull_request.head.sha }}
- name: Set SHA
id: sha
run: |
echo "OC_SHORTHASH=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
- name: Set OpenCost Image Tags
id: tags
run: |
echo "IMAGE_TAG=ghcr.io/${{ github.repository_owner }}/opencost-ui:test-${{ steps.sha.outputs.OC_SHORTHASH }}" >> $GITHUB_OUTPUT
- name: Build and publish container
uses: ./.github/actions/build-container
with:
actor: ${{ github.actor }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
image_tag: ${{ steps.tags.outputs.IMAGE_TAG }}
release_version: test-${{ steps.sha.outputs.OC_SHORTHASH }}
registry: ${{ env.REGISTRY }}

39
.github/workflows/promote-to-demo.yaml vendored Normal file
View File

@ -0,0 +1,39 @@
name: Promote UI to Demo
on:
workflow_run:
workflows: [Build and Publish Develop UI]
types: [completed]
branches: [main]
concurrency:
group: build-opencost-ui-develop
cancel-in-progress: false
jobs:
prep-image-name:
runs-on: ubuntu-latest
if: ${{ github.event.workflow_run.conclusion == 'success' }}
outputs:
image_tag: ${{ steps.tags.outputs.IMAGE_TAG }}
steps:
- name: Checkout Repo
uses: actions/checkout@v4
- name: Set SHA
id: sha
run: |
echo "OC_SHORTHASH=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
- name: Set OpenCost Image Tags
id: tags
run: |
echo "IMAGE_TAG=ghcr.io/${{ github.repository_owner }}/opencost-ui:develop-${{ steps.sha.outputs.OC_SHORTHASH }}" >> $GITHUB_OUTPUT
install-on-demo:
needs: [prep-image-name]
uses: opencost/opencost-infra/.github/workflows/promote-to-oc-demo.yaml@main
secrets: inherit
with:
img-fqdn: ${{ needs.prep-image-name.outputs.image_tag }}
is_be: false
is_fe: true

View File

@ -2,16 +2,16 @@
# OpenCost UI
<img src="./opencost-header.png"/>
<img src="src/images/logo.png"/>
This is the web UI for the [OpenCost](http://github.com/opencost/opencost) project. You can learn more about the [User Interface](https://www.opencost.io/docs/installation/ui) in the OpenCost docs.
[![OpenCost UI Walkthrough](./ui/src/thumbnail.png)](https://youtu.be/lCP4Ci9Kcdg)
[![OpenCost UI Walkthrough](./src/thumbnail.png)](https://youtu.be/lCP4Ci9Kcdg)
*OpenCost UI Walkthrough*
## Installing
See https://www.opencost.io/docs/install for the full instructions.
See [Installation Guide](https://opencost.io/docs/installation/install) for the full instructions.
## Using

260
package-lock.json generated
View File

@ -11,7 +11,7 @@
"license": "Apache-2.0",
"dependencies": {
"@babel/runtime": "^7.27.0",
"@date-io/core": "^1.3.13",
"@date-io/core": "^3.2.0",
"@date-io/date-fns": "^1.3.13",
"@material-ui/core": "^4.11.3",
"@material-ui/icons": "^4.11.2",
@ -28,7 +28,7 @@
"recharts": "^2.15.3"
},
"devDependencies": {
"@babel/core": "^7.26.8",
"@babel/core": "^7.28.0",
"@babel/plugin-proposal-class-properties": "^7.13.0",
"@babel/plugin-transform-runtime": "^7.26.10",
"@babel/preset-react": "^7.26.3",
@ -52,46 +52,47 @@
}
},
"node_modules/@babel/code-frame": {
"version": "7.26.2",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz",
"integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==",
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz",
"integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-validator-identifier": "^7.25.9",
"@babel/helper-validator-identifier": "^7.27.1",
"js-tokens": "^4.0.0",
"picocolors": "^1.0.0"
"picocolors": "^1.1.1"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/compat-data": {
"version": "7.26.5",
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.5.tgz",
"integrity": "sha512-XvcZi1KWf88RVbF9wn8MN6tYFloU5qX8KjuF3E1PVBmJ9eypXfs4GRiJwLuTZL0iSnJUKn1BFPa5BPZZJyFzPg==",
"version": "7.28.0",
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.0.tgz",
"integrity": "sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/core": {
"version": "7.26.8",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.8.tgz",
"integrity": "sha512-l+lkXCHS6tQEc5oUpK28xBOZ6+HwaH7YwoYQbLFiYb4nS2/l1tKnZEtEWkD0GuiYdvArf9qBS0XlQGXzPMsNqQ==",
"version": "7.28.0",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.0.tgz",
"integrity": "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@ampproject/remapping": "^2.2.0",
"@babel/code-frame": "^7.26.2",
"@babel/generator": "^7.26.8",
"@babel/helper-compilation-targets": "^7.26.5",
"@babel/helper-module-transforms": "^7.26.0",
"@babel/helpers": "^7.26.7",
"@babel/parser": "^7.26.8",
"@babel/template": "^7.26.8",
"@babel/traverse": "^7.26.8",
"@babel/types": "^7.26.8",
"@types/gensync": "^1.0.0",
"@babel/code-frame": "^7.27.1",
"@babel/generator": "^7.28.0",
"@babel/helper-compilation-targets": "^7.27.2",
"@babel/helper-module-transforms": "^7.27.3",
"@babel/helpers": "^7.27.6",
"@babel/parser": "^7.28.0",
"@babel/template": "^7.27.2",
"@babel/traverse": "^7.28.0",
"@babel/types": "^7.28.0",
"convert-source-map": "^2.0.0",
"debug": "^4.1.0",
"gensync": "^1.0.0-beta.2",
@ -107,16 +108,16 @@
}
},
"node_modules/@babel/generator": {
"version": "7.26.8",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.8.tgz",
"integrity": "sha512-ef383X5++iZHWAXX0SXQR6ZyQhw/0KtTkrTz61WXRhFM6dhpHulO/RJz79L8S6ugZHJkOOkUrUdxgdF2YiPFnA==",
"version": "7.28.0",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.0.tgz",
"integrity": "sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/parser": "^7.26.8",
"@babel/types": "^7.26.8",
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.25",
"@babel/parser": "^7.28.0",
"@babel/types": "^7.28.0",
"@jridgewell/gen-mapping": "^0.3.12",
"@jridgewell/trace-mapping": "^0.3.28",
"jsesc": "^3.0.2"
},
"engines": {
@ -136,13 +137,14 @@
}
},
"node_modules/@babel/helper-compilation-targets": {
"version": "7.26.5",
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.26.5.tgz",
"integrity": "sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA==",
"version": "7.27.2",
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz",
"integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/compat-data": "^7.26.5",
"@babel/helper-validator-option": "^7.25.9",
"@babel/compat-data": "^7.27.2",
"@babel/helper-validator-option": "^7.27.1",
"browserslist": "^4.24.0",
"lru-cache": "^5.1.1",
"semver": "^6.3.1"
@ -212,6 +214,16 @@
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-globals": {
"version": "7.28.0",
"resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz",
"integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-member-expression-to-functions": {
"version": "7.23.0",
"resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz",
@ -225,27 +237,29 @@
}
},
"node_modules/@babel/helper-module-imports": {
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz",
"integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==",
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz",
"integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/traverse": "^7.25.9",
"@babel/types": "^7.25.9"
"@babel/traverse": "^7.27.1",
"@babel/types": "^7.27.1"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-module-transforms": {
"version": "7.26.0",
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz",
"integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==",
"version": "7.27.3",
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz",
"integrity": "sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-module-imports": "^7.25.9",
"@babel/helper-validator-identifier": "^7.25.9",
"@babel/traverse": "^7.25.9"
"@babel/helper-module-imports": "^7.27.1",
"@babel/helper-validator-identifier": "^7.27.1",
"@babel/traverse": "^7.27.3"
},
"engines": {
"node": ">=6.9.0"
@ -318,54 +332,57 @@
}
},
"node_modules/@babel/helper-string-parser": {
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz",
"integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==",
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
"integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-validator-identifier": {
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz",
"integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==",
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz",
"integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-validator-option": {
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz",
"integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==",
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz",
"integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helpers": {
"version": "7.26.7",
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.7.tgz",
"integrity": "sha512-8NHiL98vsi0mbPQmYAGWwfcFaOy4j2HY49fXJCfuDcdE7fMIsH9a7GdaeXpIBsbT7307WU8KCMp5pUVDNL4f9A==",
"version": "7.28.2",
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.2.tgz",
"integrity": "sha512-/V9771t+EgXz62aCcyofnQhGM8DQACbRhvzKFsXKC9QM+5MadF8ZmIm0crDMaz3+o0h0zXfJnd4EhbYbxsrcFw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/template": "^7.25.9",
"@babel/types": "^7.26.7"
"@babel/template": "^7.27.2",
"@babel/types": "^7.28.2"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/parser": {
"version": "7.26.8",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.8.tgz",
"integrity": "sha512-TZIQ25pkSoaKEYYaHbbxkfL36GNsQ6iFiBbeuzAkLnXayKR1yP1zFe+NxuZWWsUyvt8icPU9CCq0sgWGXR1GEw==",
"version": "7.28.0",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.0.tgz",
"integrity": "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/types": "^7.26.8"
"@babel/types": "^7.28.0"
},
"bin": {
"parser": "bin/babel-parser.js"
@ -525,57 +542,58 @@
}
},
"node_modules/@babel/template": {
"version": "7.26.8",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.26.8.tgz",
"integrity": "sha512-iNKaX3ZebKIsCvJ+0jd6embf+Aulaa3vNBqZ41kM7iTWjx5qzWKXGHiJUW3+nTpQ18SG11hdF8OAzKrpXkb96Q==",
"version": "7.27.2",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz",
"integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.26.2",
"@babel/parser": "^7.26.8",
"@babel/types": "^7.26.8"
"@babel/code-frame": "^7.27.1",
"@babel/parser": "^7.27.2",
"@babel/types": "^7.27.1"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/traverse": {
"version": "7.26.8",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.8.tgz",
"integrity": "sha512-nic9tRkjYH0oB2dzr/JoGIm+4Q6SuYeLEiIiZDwBscRMYFJ+tMAz98fuel9ZnbXViA2I0HVSSRRK8DW5fjXStA==",
"version": "7.28.0",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.0.tgz",
"integrity": "sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.26.2",
"@babel/generator": "^7.26.8",
"@babel/parser": "^7.26.8",
"@babel/template": "^7.26.8",
"@babel/types": "^7.26.8",
"debug": "^4.3.1",
"globals": "^11.1.0"
"@babel/code-frame": "^7.27.1",
"@babel/generator": "^7.28.0",
"@babel/helper-globals": "^7.28.0",
"@babel/parser": "^7.28.0",
"@babel/template": "^7.27.2",
"@babel/types": "^7.28.0",
"debug": "^4.3.1"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/types": {
"version": "7.26.8",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.8.tgz",
"integrity": "sha512-eUuWapzEGWFEpHFxgEaBG8e3n6S8L3MSu0oda755rOfabWPnh0Our1AozNFVUxGFIhbKgd1ksprsoDGMinTOTA==",
"version": "7.28.2",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.2.tgz",
"integrity": "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-string-parser": "^7.25.9",
"@babel/helper-validator-identifier": "^7.25.9"
"@babel/helper-string-parser": "^7.27.1",
"@babel/helper-validator-identifier": "^7.27.1"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@date-io/core": {
"version": "1.3.13",
"resolved": "https://registry.npmjs.org/@date-io/core/-/core-1.3.13.tgz",
"integrity": "sha512-AlEKV7TxjeK+jxWVKcCFrfYAk8spX9aCyiToFIiLPtfQbsjmRGLIhb5VZgptQcJdHtLXo7+m0DuurwFgUToQuA=="
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/@date-io/core/-/core-3.2.0.tgz",
"integrity": "sha512-hqwXvY8/YBsT9RwQITG868ZNb1MVFFkF7W1Ecv4P472j/ZWa7EFcgSmxy8PUElNVZfvhdvfv+a8j6NWJqOX5mA==",
"license": "MIT"
},
"node_modules/@date-io/date-fns": {
"version": "1.3.13",
@ -588,23 +606,26 @@
"date-fns": "^2.0.0"
}
},
"node_modules/@date-io/date-fns/node_modules/@date-io/core": {
"version": "1.3.13",
"resolved": "https://registry.npmjs.org/@date-io/core/-/core-1.3.13.tgz",
"integrity": "sha512-AlEKV7TxjeK+jxWVKcCFrfYAk8spX9aCyiToFIiLPtfQbsjmRGLIhb5VZgptQcJdHtLXo7+m0DuurwFgUToQuA==",
"license": "MIT"
},
"node_modules/@emotion/hash": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz",
"integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow=="
},
"node_modules/@jridgewell/gen-mapping": {
"version": "0.3.8",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz",
"integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==",
"version": "0.3.12",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz",
"integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/set-array": "^1.2.1",
"@jridgewell/sourcemap-codec": "^1.4.10",
"@jridgewell/sourcemap-codec": "^1.5.0",
"@jridgewell/trace-mapping": "^0.3.24"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/resolve-uri": {
@ -616,26 +637,19 @@
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/set-array": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
"integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
"dev": true,
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.4.15",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==",
"dev": true
"version": "1.5.4",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz",
"integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==",
"dev": true,
"license": "MIT"
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.25",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
"integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
"version": "0.3.29",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz",
"integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/resolve-uri": "^3.1.0",
"@jridgewell/sourcemap-codec": "^1.4.14"
@ -822,6 +836,12 @@
"react-dom": "^16.8.0 || ^17.0.0"
}
},
"node_modules/@material-ui/pickers/node_modules/@date-io/core": {
"version": "1.3.13",
"resolved": "https://registry.npmjs.org/@date-io/core/-/core-1.3.13.tgz",
"integrity": "sha512-AlEKV7TxjeK+jxWVKcCFrfYAk8spX9aCyiToFIiLPtfQbsjmRGLIhb5VZgptQcJdHtLXo7+m0DuurwFgUToQuA==",
"license": "MIT"
},
"node_modules/@material-ui/styles": {
"version": "4.11.5",
"resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.11.5.tgz",
@ -2971,13 +2991,6 @@
"resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.1.tgz",
"integrity": "sha512-GGTvzKccVEhxmRfJEB6zhY9ieT4UhGVUIQaBzFpUO9OXy2ycAlnPCSJLzmGGgqt3KVjqN3QCQB4g1rsZnHsWhg=="
},
"node_modules/@types/gensync": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@types/gensync/-/gensync-1.0.4.tgz",
"integrity": "sha512-C3YYeRQWp2fmq9OryX+FoDy8nXS6scQ7dPptD8LnFDAUNcKWJjXQKDNJD3HVm+kOUsXhTOkpi69vI4EuAr95bA==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/prop-types": {
"version": "15.7.9",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.9.tgz",
@ -3769,15 +3782,6 @@
"node": ">=6"
}
},
"node_modules/globals": {
"version": "11.12.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
"integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
"dev": true,
"engines": {
"node": ">=4"
}
},
"node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",

View File

@ -15,7 +15,7 @@
],
"dependencies": {
"@babel/runtime": "^7.27.0",
"@date-io/core": "^1.3.13",
"@date-io/core": "^3.2.0",
"@date-io/date-fns": "^1.3.13",
"@material-ui/core": "^4.11.3",
"@material-ui/icons": "^4.11.2",
@ -32,7 +32,7 @@
"recharts": "^2.15.3"
},
"devDependencies": {
"@babel/core": "^7.26.8",
"@babel/core": "^7.28.0",
"@babel/plugin-proposal-class-properties": "^7.13.0",
"@babel/plugin-transform-runtime": "^7.26.10",
"@babel/preset-react": "^7.26.3",

View File

@ -6,6 +6,8 @@ import { BarChart } from "@material-ui/icons";
import { Cloud } from "@material-ui/icons";
import { makeStyles } from "@material-ui/styles";
const logo = new URL("../../images/logo.png", import.meta.url).href;
const DRAWER_WIDTH = 200;
const SidebarNav = ({ active }) => {
@ -55,7 +57,7 @@ const SidebarNav = ({ active }) => {
variant={"permanent"}
>
<img
src={require("../../images/logo.png")}
src={logo}
alt="OpenCost"
style={{ flexShrink: 1, padding: "1rem" }}
/>

View File

@ -238,8 +238,8 @@ const AllocationReport = ({
rowsPerPage={rowsPerPage}
rowsPerPageOptions={[10, 25, 50]}
page={Math.min(page, lastPage)}
onChangePage={handleChangePage}
onChangeRowsPerPage={handleChangeRowsPerPage}
onPageChange={handleChangePage}
onRowsPerPageChange={handleChangeRowsPerPage}
/>
</div>
);

View File

@ -204,8 +204,8 @@ const CloudCost = ({
rowsPerPage={rowsPerPage}
rowsPerPageOptions={[10, 25, 50]}
page={Math.min(page, lastPage)}
onChangePage={handleChangePage}
onChangeRowsPerPage={handleChangeRowsPerPage}
onPageChange={handleChangePage}
onRowsPerPageChange={handleChangeRowsPerPage}
/>
</div>
</div>

View File

@ -56,7 +56,7 @@ const ExternalCostsTable = ({
const routerHistory = useHistory();
const [page, setPage] = React.useState(0);
const [rowsPerPage, setRowsPerPage] = React.useState(25);
const numData = tableData.customCosts?.length;
const numData = tableData.customCosts?.length ?? 0;
const lastPage = Math.floor(numData / rowsPerPage);
@ -67,16 +67,20 @@ const ExternalCostsTable = ({
setPage(0);
};
const pageRows = tableData.customCosts.slice(
page * rowsPerPage,
page * rowsPerPage + rowsPerPage
);
let pageRows = [];
if (tableData && 'customCosts' in tableData) {
pageRows = tableData.customCosts.slice(
page * rowsPerPage,
page * rowsPerPage + rowsPerPage
);
}
React.useEffect(() => {
setPage(0);
}, [numData]);
if (tableData.customCosts.length === 0) {
if ('customCosts' in tableData && tableData.customCosts.length === 0) {
return (
<Typography variant="body2" className={classes.noResults}>
No results
@ -168,8 +172,8 @@ const ExternalCostsTable = ({
rowsPerPage={rowsPerPage}
rowsPerPageOptions={[10, 25, 50]}
page={Math.min(page, lastPage)}
onChangePage={handleChangePage}
onChangeRowsPerPage={handleChangeRowsPerPage}
onPageChange={handleChangePage}
onRowsPerPageChange={handleChangeRowsPerPage}
/>
</div>
);