From 1e4fb23af3d17fe8fa5b6cd9288409811e611739 Mon Sep 17 00:00:00 2001 From: Natalie Gaston Date: Wed, 4 Mar 2026 16:49:56 -0800 Subject: [PATCH 1/2] perf(devices): cache AMT features to reduce duplicate HTTP requests --- .github/workflows/codeql-analysis.yml | 6 +- .github/workflows/cypress.yaml | 4 +- .github/workflows/dependency-review.yml | 2 +- .github/workflows/nodejs.yaml | 2 +- .github/workflows/release.yml | 2 +- .github/workflows/scorecard.yml | 2 +- .github/workflows/trivy-scan.yaml | 4 +- Dockerfile | 2 +- package-lock.json | 64 +++++++++++++++---- .../device-toolbar.component.spec.ts | 45 ++++++------- .../device-toolbar.component.ts | 4 +- src/app/devices/devices.service.ts | 28 ++++++-- .../environment.enterprise.dev.ts | 1 + src/environments/environment.enterprise.ts | 1 + src/environments/environment.prod.ts | 1 + src/environments/environment.ts | 1 + 16 files changed, 117 insertions(+), 52 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 9bb888b36..81fdb3b88 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -55,7 +55,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@c793b717bc78562f491db7b0e93a3a178b099162 # v3.29.5 + uses: github/codeql-action/init@89a39a4e59826350b863aa6b6252a07ad50cf83e # v3.29.5 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -66,7 +66,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@c793b717bc78562f491db7b0e93a3a178b099162 # v3.29.5 + uses: github/codeql-action/autobuild@89a39a4e59826350b863aa6b6252a07ad50cf83e # v3.29.5 # â„šī¸ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -80,7 +80,7 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@c793b717bc78562f491db7b0e93a3a178b099162 # v3.29.5 + uses: github/codeql-action/analyze@89a39a4e59826350b863aa6b6252a07ad50cf83e # v3.29.5 - name: Generate Security Report uses: rsdmike/github-security-report-action@a149b24539044c92786ec39af8ba38c93496495d # v3.0.4 continue-on-error: true diff --git a/.github/workflows/cypress.yaml b/.github/workflows/cypress.yaml index 421375279..9ce360ab3 100644 --- a/.github/workflows/cypress.yaml +++ b/.github/workflows/cypress.yaml @@ -34,7 +34,7 @@ jobs: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 + uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 with: node-version: ${{ matrix.node-version }} - run: npm install cypress @@ -42,7 +42,7 @@ jobs: - run: docker run -d -p 4200:80 vprodemo.azurecr.ui/samplewebui:latest - run: npm run cy-runner - name: Publish Cypress Test Results - uses: dorny/test-reporter@3d76b34a4535afbd0600d347b09a6ee5deb3ed7f # v2.6.0 + uses: dorny/test-reporter@b082adf0eced0765477756c2a610396589b8c637 # v2.5.0 if: always() with: name: Cypress Tests diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index a635b5f32..112dfcb06 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -24,4 +24,4 @@ jobs: - name: 'Checkout Repository' uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: 'Dependency Review' - uses: actions/dependency-review-action@2031cfc080254a8a887f58cffee85186f0e49e48 # v4.9.0 + uses: actions/dependency-review-action@05fe4576374b728f0c523d6a13d64c25081e0803 # v4.8.3 diff --git a/.github/workflows/nodejs.yaml b/.github/workflows/nodejs.yaml index 37c566307..2fca7ffa8 100644 --- a/.github/workflows/nodejs.yaml +++ b/.github/workflows/nodejs.yaml @@ -28,7 +28,7 @@ jobs: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 + uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 with: node-version: ${{ matrix.node-version }} - run: npm install diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 67407c3da..6db45b2fd 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -31,7 +31,7 @@ jobs: with: persist-credentials: false - name: Use Node.js 20.x - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 + uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 with: node-version: '20.x' - name: Docker Setup Buildx diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index cbc3dcde1..74297cc6f 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -72,6 +72,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@c793b717bc78562f491db7b0e93a3a178b099162 # v2.1.27 + uses: github/codeql-action/upload-sarif@89a39a4e59826350b863aa6b6252a07ad50cf83e # v2.1.27 with: sarif_file: results.sarif diff --git a/.github/workflows/trivy-scan.yaml b/.github/workflows/trivy-scan.yaml index 104a4252c..882a0e502 100644 --- a/.github/workflows/trivy-scan.yaml +++ b/.github/workflows/trivy-scan.yaml @@ -24,7 +24,7 @@ jobs: run: docker build . --file Dockerfile --tag vprodemo.azurecr.io/webui:${{ github.sha }} --tag vprodemo.azurecr.io/webui:latest - name: Run Trivy vulnerability scanner - uses: aquasecurity/trivy-action@97e0b3872f55f89b95b2f65b3dbab56962816478 # master + uses: aquasecurity/trivy-action@e368e328979b113139d6f9068e03accaed98a518 # master with: image-ref: 'vprodemo.azurecr.io/webui:${{ github.sha }}' format: 'sarif' @@ -34,7 +34,7 @@ jobs: vuln-type: 'os,library' severity: 'UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL' - name: Upload Trivy scan results to GitHub Security tab - uses: github/codeql-action/upload-sarif@c793b717bc78562f491db7b0e93a3a178b099162 # v3.29.5 + uses: github/codeql-action/upload-sarif@89a39a4e59826350b863aa6b6252a07ad50cf83e # v3.29.5 if: always() with: sarif_file: 'webui-trivy-results.sarif' diff --git a/Dockerfile b/Dockerfile index 57e281206..816f31d37 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ # SPDX-License-Identifier: Apache-2.0 #*********************************************************************/ ### STAGE 1: Build ### -FROM node:25-bullseye-slim@sha256:8d92dea6d0a3e8d052cb9917888b3877a801ce6a2341d3cbc367c38e299a99d0 AS build +FROM node:25-bullseye-slim@sha256:01f830d06a7c032e68a4555340db472659efd7d47df468668a0d2d2082d4725c AS build WORKDIR /usr/src/app COPY package.json package-lock.json ./ RUN npm ci diff --git a/package-lock.json b/package-lock.json index f11b13c06..ac67be864 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,7 @@ "@xterm/xterm": "^6.0.0", "angular-oauth2-oidc": "^20.0.2", "angular-oauth2-oidc-jwks": "^20.0.0", + "cypress": "15.11.0", "date-fns": "^4.1.0", "esbuild": "^0.27.3", "monaco-editor": "^0.55.1", @@ -603,6 +604,7 @@ "integrity": "sha512-TCb3qYOC/uXKZCo56cJ6N9sHeWdFhyVqrbbYfFjTi09081T6jllgHDZL5Ms7gOMNY8KywWGGbhxwvzeA0RwTgA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@angular-eslint/bundled-angular-compiler": "21.2.0", "eslint-scope": "^9.0.0" @@ -632,6 +634,7 @@ "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-21.2.0.tgz", "integrity": "sha512-SzlLoMT/r5wKqPicx5okCAiN5UD5+VE7x/F1G6gSJCcnBfbK5PqHPUmDnMW4jw9Ode06KZDT7ntstn6fG+Ld8w==", "license": "MIT", + "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -760,6 +763,7 @@ "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-21.2.0.tgz", "integrity": "sha512-1P0TNL1F51NC7JAaXabaAHY7Y1zBloLSZXfml1POa4a116V+y/QZfPGsxM0LwD1qSSXhSb2LNl7duTtJAP39bA==", "license": "MIT", + "peer": true, "dependencies": { "parse5": "^8.0.0", "tslib": "^2.3.0" @@ -777,6 +781,7 @@ "integrity": "sha512-yaGEpckqgOemcHkoWeH92i9eNrcbr9iE/dnxL+Du6s9spTAXJ2jjtYfszhmowuQZkCK5rjecMb8ctNtHlaGCjg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@angular-devkit/architect": "0.2102.0", "@angular-devkit/core": "21.2.0", @@ -824,6 +829,7 @@ "resolved": "https://registry.npmjs.org/@angular/common/-/common-21.2.0.tgz", "integrity": "sha512-6zJMPi0i/XDniEgv3/t2BjuDHiOG44lgIR5PYyxqGpgJ0kqB5hku/0TuentNEi1VnBYgthnfhjek7c+lakXmhw==", "license": "MIT", + "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -840,6 +846,7 @@ "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-21.2.0.tgz", "integrity": "sha512-0RPkma8UVNpse/VJcXT9w6SKzTMz4J/uMGj0l9enM1frg9xrx1fwi/lLmaVV9Nr9LfqPjQdxNFFlvaBB7g/2zg==", "license": "MIT", + "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -853,6 +860,7 @@ "integrity": "sha512-gZd58p0/JjgdxMX3v+LjCB6e3dBIfNVr/YzXoh55TfffdBCUQY94hl1+DFQkJ72K5EX+1zbaz03dIm30kw1bGw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/core": "7.29.0", "@jridgewell/sourcemap-codec": "^1.4.14", @@ -885,6 +893,7 @@ "resolved": "https://registry.npmjs.org/@angular/core/-/core-21.2.0.tgz", "integrity": "sha512-VnTbmZq3g3Q+s3nCZ8VUDMLjMezOg/bqUxAJ/DrRWCrEcTP5JO3mrNPs3FHj+qlB0T+BQP7uQv6QTzPVKybwoA==", "license": "MIT", + "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -910,6 +919,7 @@ "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-21.2.0.tgz", "integrity": "sha512-NduUtPWLauH/FLayEDkLyaKAGqKzXbcfO7468LOWCXN3crhNVQyIWRQPOUcdpoJwDAGLpN85m3DhJhXNnA9c5w==", "license": "MIT", + "peer": true, "dependencies": { "@standard-schema/spec": "^1.0.0", "tslib": "^2.3.0" @@ -930,6 +940,7 @@ "integrity": "sha512-blVjzwHSaKbFNCQN/RZy8rSbFgajMw3kBzGrDY08atMDOPn90L2nE4dot+9d0JlKAX2gL8Qfx44YgIWBI5MfsA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/core": "7.29.0", "@types/babel__core": "7.20.5", @@ -971,6 +982,7 @@ "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-21.2.0.tgz", "integrity": "sha512-IUGukpvvT2B5Dl76qzk6rY7UIHUT9u4BhT2AwVz+5JqcX9KwQtYD17Gt7wj6bvIgCXKWG+CfN8Zd9DECOCYWjg==", "license": "MIT", + "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -1170,6 +1182,7 @@ "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", @@ -3614,9 +3627,9 @@ "optional": true }, "node_modules/@hono/node-server": { - "version": "1.19.10", - "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.10.tgz", - "integrity": "sha512-hZ7nOssGqRgyV3FVVQdfi+U4q02uB23bpnYpdvNXkYTRRyWx84b7yf1ans+dnJ/7h41sGL3CeQTfO+ZGxuO+Iw==", + "version": "1.19.9", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.9.tgz", + "integrity": "sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw==", "dev": true, "license": "MIT", "engines": { @@ -3914,6 +3927,7 @@ "integrity": "sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@inquirer/checkbox": "^4.3.2", "@inquirer/confirm": "^5.1.21", @@ -6878,6 +6892,7 @@ "integrity": "sha512-/rpCXHlCWeqClNBwUhDcusJxXYDjZTyE8v5oTO7WbL8eij2nKhUeU89/6xgjU7N4/Vh3He0BtyhJdQbDyhiXAw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "undici-types": "~7.16.0" } @@ -7040,6 +7055,7 @@ "integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.56.1", "@typescript-eslint/types": "8.56.1", @@ -7147,6 +7163,7 @@ "integrity": "sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -7189,6 +7206,7 @@ "integrity": "sha512-HPAVNIME3tABJ61siYlHzSWCGtOoeP2RTIaHXFMPqjrQKCGB9OgUVdiNgH7TJS2JNIQ5qQ4RsAUDuGaGme/KOA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.56.1", @@ -7417,6 +7435,7 @@ "resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-6.0.0.tgz", "integrity": "sha512-TQwDdQGtwwDt+2cgKDLn0IRaSxYu1tSUjgKarSDkUM0ZNiSRXFpjxEsvc/Zgc5kq5omJ+V0a8/kIM2WD3sMOYg==", "license": "MIT", + "peer": true, "workspaces": [ "addons/*" ] @@ -7499,6 +7518,7 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -7601,6 +7621,7 @@ "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -8300,6 +8321,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -8564,7 +8586,6 @@ "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==", "license": "BSD-3-Clause", - "peer": true, "engines": { "node": "*" } @@ -9282,7 +9303,6 @@ "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==", "license": "BSD-3-Clause", - "peer": true, "engines": { "node": "*" } @@ -10071,6 +10091,7 @@ "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "ansi-colors": "^4.1.1", "strip-ansi": "^6.0.1" @@ -10308,6 +10329,7 @@ "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -11505,11 +11527,12 @@ } }, "node_modules/hono": { - "version": "4.12.5", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.5.tgz", - "integrity": "sha512-3qq+FUBtlTHhtYxbxheZgY8NIFnkkC/MR8u5TTsr7YZ3wixryQ3cCwn3iZbg8p8B88iDBBAYSfZDS75t8MN7Vg==", + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.2.tgz", + "integrity": "sha512-gJnaDHXKDayjt8ue0n8Gs0A007yKXj4Xzb8+cNjZeYsSzzwKc0Lr+OZgYwVfB0pHfUs17EPoLvrOsEaJ9mj+Tg==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=16.9.0" } @@ -11966,8 +11989,7 @@ "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/is-core-module": { "version": "2.16.1", @@ -12383,7 +12405,8 @@ "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-6.1.0.tgz", "integrity": "sha512-p/tjBw58O6vxKIWMlrU+yys8lqR3+l3UrqwNTT7wpj+dQ7N4etQekFM8joI+cWzPDYqZf54kN+hLC1+s5TvZvg==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/jasmine-spec-reporter": { "version": "7.0.0", @@ -12416,6 +12439,7 @@ "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", "dev": true, "license": "MIT", + "peer": true, "bin": { "jiti": "lib/jiti-cli.mjs" } @@ -12596,6 +12620,7 @@ "integrity": "sha512-LrtUxbdvt1gOpo3gxG+VAJlJAEMhbWlM4YrFQgql98FwF7+K8K12LYO4hnDdUkNjeztYrOXEMqgTajSWgmtI/w==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@colors/colors": "1.5.0", "body-parser": "^1.19.0", @@ -13072,6 +13097,7 @@ "integrity": "sha512-j1n1IuTX1VQjIy3tT7cyGbX7nvQOsFLoIqobZv4ttI5axP923gA44zUj6miiA6R5Aoms4sEGVIIcucXUbRI14g==", "dev": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "copy-anything": "^2.0.1", "parse-node-version": "^1.0.1", @@ -13227,6 +13253,7 @@ "integrity": "sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "cli-truncate": "^5.0.0", "colorette": "^2.0.20", @@ -13727,7 +13754,6 @@ "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", "license": "BSD-3-Clause", - "peer": true, "dependencies": { "charenc": "0.0.2", "crypt": "0.0.2", @@ -14095,6 +14121,7 @@ "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.55.1.tgz", "integrity": "sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A==", "license": "MIT", + "peer": true, "dependencies": { "dompurify": "3.2.7", "marked": "14.0.0" @@ -15193,6 +15220,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -16015,6 +16043,7 @@ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", "license": "Apache-2.0", + "peer": true, "dependencies": { "tslib": "^2.1.0" } @@ -16071,6 +16100,7 @@ "integrity": "sha512-fDz1zJpd5GycprAbu4Q2PV/RprsRtKC/0z82z0JLgdytmcq0+ujJbJ/09bPGDxCLkKY3Np5cRAOcWiVkLXJURg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "chokidar": "^4.0.0", "immutable": "^5.0.2", @@ -17192,6 +17222,7 @@ "integrity": "sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg==", "dev": true, "license": "BSD-2-Clause", + "peer": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.15.0", @@ -17469,7 +17500,8 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD" + "license": "0BSD", + "peer": true }, "node_modules/tsyringe": { "version": "4.10.0", @@ -17619,6 +17651,7 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -17633,6 +17666,7 @@ "integrity": "sha512-U4lM6pjmBX7J5wk4szltF7I1cGBHXZopnAXCMXb3+fZ3B/0Z3hq3wS/CCUB2NZBNAExK92mCU2tEohWuwVMsDQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/eslint-plugin": "8.56.1", "@typescript-eslint/parser": "8.56.1", @@ -17921,6 +17955,7 @@ "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", @@ -18038,6 +18073,7 @@ "integrity": "sha512-dRXm0a2qcHPUBEzVk8uph0xWSjV/xZxenQQbLwnwP7caQCYpqG1qddwlyEkIDkYn0K8tvmcrZ+bOrzoQ3HxCDw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.8", @@ -18144,6 +18180,7 @@ "integrity": "sha512-9Gyu2F7+bg4Vv+pjbovuYDhHX+mqdqITykfzdM9UyKqKHlsE5aAjRhR+oOEfXW5vBeu8tarzlJFIZva4ZjAdrQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/bonjour": "^3.5.13", "@types/connect-history-api-fallback": "^1.5.4", @@ -18987,6 +19024,7 @@ "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", "dev": true, "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/src/app/devices/device-toolbar/device-toolbar.component.spec.ts b/src/app/devices/device-toolbar/device-toolbar.component.spec.ts index 6bf311cdc..ef1b4de34 100644 --- a/src/app/devices/device-toolbar/device-toolbar.component.spec.ts +++ b/src/app/devices/device-toolbar/device-toolbar.component.spec.ts @@ -38,6 +38,7 @@ describe('DeviceToolbarComponent', () => { 'sendDeactivate', 'getPowerState', 'getAMTFeatures', + 'getAMTFeaturesCached', 'getAMTVersion', 'featuresChanges' ]) @@ -54,28 +55,28 @@ describe('DeviceToolbarComponent', () => { ) devicesService.getPowerState.and.returnValue(of({ powerstate: 2 })) - devicesService.getAMTFeatures.and.returnValue( - of({ - userConsent: 'None', - ocr: true, - httpsBootSupported: true, - kvm: true, - sol: true, - ider: true, - redirection: true, - optInState: 1, - kvmAvailable: true, - winREBootSupported: true, - localPBABootSupported: true, - remoteErase: true, - pbaBootFilesPath: [], - winREBootFilesPath: { - instanceID: '', - biosBootString: '', - bootString: '' - } - } as any) - ) + const mockAMTFeatures = { + userConsent: 'None', + ocr: true, + httpsBootSupported: true, + kvm: true, + sol: true, + ider: true, + redirection: true, + optInState: 1, + kvmAvailable: true, + winREBootSupported: true, + localPBABootSupported: true, + remoteErase: true, + pbaBootFilesPath: [], + winREBootFilesPath: { + instanceID: '', + biosBootString: '', + bootString: '' + } + } as any + devicesService.getAMTFeatures.and.returnValue(of(mockAMTFeatures)) + devicesService.getAMTFeaturesCached.and.returnValue(of(mockAMTFeatures)) getDeviceSpy = devicesService.getDevice.and.returnValue(of({ guid: 'guid' } as any)) sendDeactivateSpy = devicesService.sendDeactivate.and.returnValue(of({ status: 'SUCCESS' })) sendDeactivateErrorSpy = devicesService.sendDeactivate.and.returnValue(throwError({ error: 'Error' })) diff --git a/src/app/devices/device-toolbar/device-toolbar.component.ts b/src/app/devices/device-toolbar/device-toolbar.component.ts index 73f306eb9..c2a621e0f 100644 --- a/src/app/devices/device-toolbar/device-toolbar.component.ts +++ b/src/app/devices/device-toolbar/device-toolbar.component.ts @@ -177,7 +177,9 @@ export class DeviceToolbarComponent implements OnInit { } private loadAMTFeatures(): void { - this.devicesService.getAMTFeatures(this.deviceId()).subscribe((features) => { + // Use cached features if fresher than 30s — avoids a duplicate AMT round-trip + // when the KVM/SOL component already loaded features moments before the toolbar. + this.devicesService.getAMTFeaturesCached(this.deviceId()).subscribe((features) => { this.amtFeatures.set(features) this.buildPowerOptions() }) diff --git a/src/app/devices/devices.service.ts b/src/app/devices/devices.service.ts index 71708d0ff..fbdd0a555 100644 --- a/src/app/devices/devices.service.ts +++ b/src/app/devices/devices.service.ts @@ -5,7 +5,7 @@ import { HttpClient } from '@angular/common/http' import { EventEmitter, Injectable, inject } from '@angular/core' -import { Observable, Subject, BehaviorSubject } from 'rxjs' +import { Observable, Subject, BehaviorSubject, of } from 'rxjs' import { catchError, map, tap } from 'rxjs/operators' import { environment } from 'src/environments/environment' import { @@ -43,6 +43,9 @@ export class DevicesService { private readonly http = inject(HttpClient) // Reactive AMT features stream, keyed by deviceId private readonly amtFeaturesStreams = new Map>() + // Timestamps for TTL-based features cache — configured via environment.amtFeaturesCacheTtlMs, capped at 3 min + private readonly featuresTimestamps = new Map() + private readonly FEATURES_TTL_MS = Math.min(environment.amtFeaturesCacheTtlMs ?? 30_000, 180_000) private getOrCreateFeaturesStream(deviceId: string): BehaviorSubject { if (!this.amtFeaturesStreams.has(deviceId)) { @@ -265,13 +268,31 @@ export class DevicesService { getAMTFeatures(guid: string): Observable { return this.http.get(`${environment.mpsServer}/api/v1/amt/features/${guid}`).pipe( - tap((features) => this.getOrCreateFeaturesStream(guid).next(features)), + tap((features) => { + this.getOrCreateFeaturesStream(guid).next(features) + this.featuresTimestamps.set(guid, Date.now()) + }), catchError((err) => { throw err }) ) } + /** + * Returns cached AMT features immediately if they are fresher than ttlMs, + * otherwise falls back to a real HTTP call. Eliminates duplicate round-trips + * when the toolbar and KVM component both load features within the same session. + * TTL is read from environment.amtFeaturesCacheTtlMs (default 30 s, max 3 min). + */ + getAMTFeaturesCached(guid: string, ttlMs = this.FEATURES_TTL_MS): Observable { + const cached = this.getOrCreateFeaturesStream(guid).value + const ts = this.featuresTimestamps.get(guid) ?? 0 + if (cached !== null && Date.now() - ts < ttlMs) { + return of(cached) + } + return this.getAMTFeatures(guid) + } + getAlarmOccurrences(guid: string): Observable { return this.http .get(`${environment.mpsServer}/api/v1/amt/alarmOccurrences/${guid}`) @@ -366,8 +387,7 @@ export class DevicesService { } getDevice(guid: string): Observable { - const query = `${environment.mpsServer}/api/v1/devices/${guid}` - return this.http.get(query).pipe( + return this.http.get(`${environment.mpsServer}/api/v1/devices/${guid}`).pipe( catchError((err) => { throw err }) diff --git a/src/environments/environment.enterprise.dev.ts b/src/environments/environment.enterprise.dev.ts index 9f14ff764..e4f6b019e 100644 --- a/src/environments/environment.enterprise.dev.ts +++ b/src/environments/environment.enterprise.dev.ts @@ -10,6 +10,7 @@ export const environment = { mpsServer: 'http://localhost:8181', rpsServer: 'http://localhost:8181', vault: '', + amtFeaturesCacheTtlMs: 30_000, // 30 s default; max 3 min (180_000) auth: { clientId: '##CLIENTID##', issuer: '##ISSUER##', diff --git a/src/environments/environment.enterprise.ts b/src/environments/environment.enterprise.ts index d1b08f534..c111e7cf3 100644 --- a/src/environments/environment.enterprise.ts +++ b/src/environments/environment.enterprise.ts @@ -10,6 +10,7 @@ export const environment = { mpsServer: '##CONSOLE_SERVER_API##', rpsServer: '##CONSOLE_SERVER_API##', vault: '##VAULT_SERVER##', + amtFeaturesCacheTtlMs: 30_000, // 30 s default; max 3 min (180_000) auth: { clientId: '##CLIENTID##', issuer: '##ISSUER##', diff --git a/src/environments/environment.prod.ts b/src/environments/environment.prod.ts index dc6e255d7..31d0f4fcb 100644 --- a/src/environments/environment.prod.ts +++ b/src/environments/environment.prod.ts @@ -10,5 +10,6 @@ export const environment = { mpsServer: '##MPS_SERVER##', rpsServer: '##RPS_SERVER##', vault: '##VAULT_SERVER##', + amtFeaturesCacheTtlMs: 30_000, // 30 s default; max 3 min (180_000) auth: {} } diff --git a/src/environments/environment.ts b/src/environments/environment.ts index 66afbd9a4..640e43292 100644 --- a/src/environments/environment.ts +++ b/src/environments/environment.ts @@ -14,6 +14,7 @@ export const environment = { mpsServer: 'http://localhost:3000', rpsServer: 'http://localhost:8081', vault: 'http://localhost/vault', + amtFeaturesCacheTtlMs: 30_000, // 30 s default; max 3 min (180_000) auth: { clientId: '', issuer: '', From 371446f86ddc607c13aa2ca9c27e1bc671581673 Mon Sep 17 00:00:00 2001 From: Natalie Gaston Date: Mon, 16 Mar 2026 14:18:27 -0700 Subject: [PATCH 2/2] build(gh-actions): update workflow action versions to match main - actions/setup-node: v6.2.0 -> v6.3.0 (cypress, nodejs, release) - dorny/test-reporter: v2.5.0 -> v2.6.0 (cypress) - actions/dependency-review-action: v4.8.3 -> v4.9.0 (dependency-review) --- .github/workflows/cypress.yaml | 4 ++-- .github/workflows/dependency-review.yml | 2 +- .github/workflows/nodejs.yaml | 2 +- .github/workflows/release.yml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/cypress.yaml b/.github/workflows/cypress.yaml index c8c877cd4..2c504f25a 100644 --- a/.github/workflows/cypress.yaml +++ b/.github/workflows/cypress.yaml @@ -34,7 +34,7 @@ jobs: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 + uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 with: node-version: ${{ matrix.node-version }} - run: npm install cypress @@ -42,7 +42,7 @@ jobs: - run: docker run -d -p 4200:80 vprodemo.azurecr.ui/samplewebui:latest - run: npm run cy-runner - name: Publish Cypress Test Results - uses: dorny/test-reporter@b082adf0eced0765477756c2a610396589b8c637 # v2.5.0 + uses: dorny/test-reporter@3d76b34a4535afbd0600d347b09a6ee5deb3ed7f # v2.6.0 if: always() with: name: Cypress Tests diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index 5694de75a..8e499c800 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -24,4 +24,4 @@ jobs: - name: 'Checkout Repository' uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: 'Dependency Review' - uses: actions/dependency-review-action@05fe4576374b728f0c523d6a13d64c25081e0803 # v4.8.3 + uses: actions/dependency-review-action@2031cfc080254a8a887f58cffee85186f0e49e48 # v4.9.0 diff --git a/.github/workflows/nodejs.yaml b/.github/workflows/nodejs.yaml index 87e7eab15..a469a0710 100644 --- a/.github/workflows/nodejs.yaml +++ b/.github/workflows/nodejs.yaml @@ -28,7 +28,7 @@ jobs: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 + uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 with: node-version: ${{ matrix.node-version }} - run: npm install diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index aefd1cf87..7a0145273 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -31,7 +31,7 @@ jobs: with: persist-credentials: false - name: Use Node.js 20.x - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 + uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 with: node-version: '20.x' - name: Docker Setup Buildx