summaryrefslogtreecommitdiff
AgeCommit message (Collapse)AuthorFilesLines
3 daysAdd asset tag edit functionality to overview pageHEADmasterNishant Tiwari7-5/+212
Implemented the ability to view and edit the system asset tag directly from the Overview page, including a modal dialog for editing, Vuex store action for saving, and truncation in the app header. Changes: - Added ModalAssetTag.vue component with: - Form input for editing the asset tag value - Vuelidate validation requiring a non-empty tag - Updated OverviewServer.vue to: - Display asset tag in the system information section - Add inline edit button using Carbon edit icon - Dispatch saveAssetTag store action with toast feedback - Refresh global system info after a successful save - Added saveAssetTag action to SystemStore.js using PATCH against the system path endpoint - Updated AppHeader.vue to truncate asset tags longer than 30 characters with an ellipsis, preserving full value in the title attribute for accessibility - Added translation keys for asset tag label, modal title, and success/error toast messages in en-US, ka-GE, and ru-RU locale files Testing: - Verified asset tag displays correctly in system info section - Verified modal opens, validates, and submits correctly - Verified PATCH request updates asset tag on the server - Validated success and error toast notifications display - Confirmed long asset tags are truncated in the header Change-Id: I6ac51dfc24b9d40986b74e9220cff955b029d659 Signed-off-by: Nishant Tiwari <tiwari.nishant@ibm.com>
3 daysImplemented Reboot BMC with TanStack Vue QueryNikhil Ashoka7-81/+179
This change migrates the Reboot BMC page from Vuex to TanStack Query and Composition API Key changes: 1. Redfish types (src/api/types/redfish.ts): - Adds Manager interface with LastResetTime and Actions fields, typed in PascalCase to match the Redfish schema 2. BMC reboot composable (src/components/Composables/useRebootBmc.ts): - Replaces Vuex controls/getLastBmcRebootTime and controls/rebootBmc with a Composition API composable - Uses useRedfishRoot() to resolve the Managers collection URI from ServiceRoot; fetches the first member (the BMC Manager) in queryFn - Configures staleTime: Infinity and gcTime: Infinity because LastResetTime only changes on a reboot; onSuccess invalidation handles the one real change event, avoiding unnecessary refetches - mutationFn is pure (no i18n strings, no toast calls); view owns all user-facing messages via try/catch - onSuccess calls invalidateQueries only (no optimistic update, which would be immediately overwritten by the refetch) - resetTarget prefers Actions['#Manager.Reset'].target from the cached Manager, falls back to the conventional Redfish path 3. View modernization (src/views/Operations/RebootBmc/RebootBmc.vue): - Refactors from Options API to <script setup>, using useRebootBmc(), useLoadingBar(), and useToast() composables - Loader semantics: isLoading drives the loading bar on first fetch only; cached data renders instantly on re-navigation with a silent background refetch (no flicker) - Reboot button disabled when bmcQuery.isError is true, preventing mutation dispatch with an unavailable reset target - Confirm dialog uses eventBus.$emit('confirm:open', ...) directly, matching the $confirm global property contract without Options API 4. Store cleanup (src/store/modules/Operations/ControlStore.js): - Removes lastBmcRebootTime state, getter, and setLastBmcRebootTime mutation (now owned by bmcQuery in the composable) - Removes getLastBmcRebootTime and rebootBmc actions (replaced by useQuery and useMutation in useRebootBmc.ts) - Removes unused i18n import - Remaining ControlStore state (isOperationInProgress, lastPowerOperationTime) and server power actions are unchanged; they are still used by ServerPowerOperations.vue and Firmware.vue 5. Toast rendering fix (src/components/Composables/useToast.ts, src/plugins/toast.js): - Fixes modelValue: false → true for danger/error toasts in both the Composition API useToast composable and the Options API ToastPlugin; modelValue: false suppressed toast rendering entirely in bootstrap-vue-next, making error toasts invisible app-wide Tested-by: Manual testing on development server - Last BMC reboot time loads correctly from Manager.LastResetTime - Reboot button triggers GracefulRestart POST; success and error toasts display with localized messages - Loading bar shows on first page load and during reboot POST; subsequent visits render cached data instantly - Read-only user receives the global Unauthorized toast (403 interceptor) followed by the page-level error toast Change-Id: I5d49527f176041958e48889d6261780fcffdd9df Signed-off-by: Nikhil Ashoka <a.nikhil@ibm.com>
3 daysAdded automated security auditNikhil Ashoka1-0/+38
- Add [`.github/workflows/security.yml`](.github/workflows/security.yml) to run npm ci with the lockfile enforced and lifecycle scripts disabled. - Run npm audit --audit-level=high --omit=dev against production dependencies. - Trigger the audit on pushes to master and weekly on Monday at 08:00 UTC. - Cancel superseded runs and limit each audit job to 10 minutes. Change-Id: Icd7227de004fd939629312f8af65fb0858c62d5c Signed-off-by: Nikhil Ashoka <a.nikhil@ibm.com>
2026-09-17Fix reversed expand chevron in the event log tableBill Chan1-4/+2
The expand button in Event Logs draws its chevron upside down in both states: collapsed shows an up chevron, expanded shows a down one. _tables.scss rotates the icon 180 degrees for any button inside a .table-row-expand cell that does not carry .collapsed: .table-row-expand .btn:not(.collapsed) svg { transform: rotate(180deg); } EventLogs opts into that rule through tdClass: 'table-row-expand' but never applies .collapsed to the button, so the selector matches in both states and the rotation is permanent. The template swaps two icons by hand, chevron--down when collapsed and chevron--up when expanded, and the constant rotation inverts each of them. The swap predates the rule and was correct when written. Before f4861f9 the stylesheet rotated only .btn.collapsed, which these buttons never match, so nothing was rotated and the explicit icons showed through. Inverting the selector to :not(.collapsed) captured every button that had opted out of the class. Adopt the pattern the other nine pages using .table-row-expand already follow, Certificates and every Inventory table among them: bind .collapsed to the row state and render chevron--down alone, letting the stylesheet supply the flip. chevron--down rotated 180 degrees is chevron--up exactly, the two path definitions mapping onto each other point for point under (x,y) -> (32-x, 32-y), so the rendered result is what the template always intended. IconChevronUp is then unused and is removed. Tested: eslint and vite build are clean on the modified file. A scan of every .vue file using .table-row-expand confirms this was the last one not binding .collapsed; the other nine already did. Confirmed in a browser: the expand chevron points down while the row is collapsed and up while it is expanded. Change-Id: I2b0e28ca31d6a363c3f18cf308f17dbf09e74c0f Signed-off-by: Bill Chan <bill_chan@jabil.com>
2026-09-15Add Socket Firewall workflow for supply-chain checksNishant Tiwari1-0/+30
Integrate Socket Firewall to enable automated dependency supply-chain vulnerability scanning. About Socket Firewall (first-time setup — for first-time readers): Socket Security [1] analyses npm dependency trees for supply-chain risks, typosquatting, protestware, and CVEs that traditional vulnerability scanners miss. Socket Firewall is their network-layer proxy approach: instead of running a separate CLI scan, it intercepts the ordinary `npm install` / `npm ci` call and flags any malicious package present within codebase.No separate setup or local install is required for the workflow added here — the `socketdev/action` handles everything inside the GitHub Actions runner. Why we need this change: Recent npm supply-chain attacks demonstrate the real and growing risk to projects that depend on third-party packages: - Axios npm compromise (Apr 2026) [2] - March 2026 supply-chain surge [3] - npm threat landscape / supply-chain attacks [4] - Red Hat @redhat-cloud-services compromise [5] - Keyv/Cacheable npm worm [6] Socket provides early visibility against such risks by reviewing the npm dependencies used by webui-vue and providing security/vulnerability assessments for our packages. Changes: - Added .github/workflows/socket.yml — GitHub Actions workflow that: - Triggers on a rolling 3-day schedule (06:00 UTC) and on manual workflow_dispatch - Checks out the repository and sets up Node.js 22 - Installs Socket Firewall via the official socketdev/action in firewall-free mode - Runs `sfw npm ci` through the firewall proxy; the job fails if any malicious or typosquatted package is detected Testing: - Verified socket.yml workflow syntax parses without errors - Confirmed socketdev/action runs correctly with mode: firewall-free - Verified `sfw npm ci` exits non-zero on a known-bad test package [1]: https://socket.dev [2]: https://www.cisa.gov/news-events/alerts/2026/04/20/supply-chain-compromise-impacts-axios-node-package-manager [3]: https://www.zscaler.com/blogs/security-research/supply-chain-attacks-surge-march-2026 [4]: https://unit42.paloaltonetworks.com/monitoring-npm-supply-chain-attacks/ [5]: https://access.redhat.com/security/vulnerabilities/RHSB-2026-006 [6]: https://www.wiz.io/blog/keyv-and-cacheable-npm-supply-chain-attack Signed-off-by: Nishant Tiwari <tiwari.nishant@ibm.com> Change-Id: I30384c351afe86cf660dab430e1bd68344c5c8d3
2026-09-15Revert policy selection on save errorVedangi Mittal1-14/+10
When a readonly user changes the policy and clicks save, the failed request left the radio group stuck on the new selection. Replace the split computed getter/setter with a local `selectedPolicy` data property and explicitly reset it to the store value on error. Change-Id: I1785384f0a654c8daa447a70e44336bb22ffa4d2 Signed-off-by: Vedangi Mittal <vedangimittal3004@gmail.com>
2026-09-11docs: Rework webui-vue offline build/SBOM designJason Westover1-0/+116
Rewrite the design around one decision: how to make webui-vue build offline and report per-dependency licenses using Yocto-native mechanisms. Recommend teaching autobump to generate per-component Yocto recipes from package-lock.json (a webui-vue-specific special case that changes no other recipe's build). Every npm dependency then fetches like any other recipe, and the image SBOM comes for free via per-recipe LICENSE and create-spdx. The webui-vue recipe is rewritten to DEPENDS on those recipes and build Vite offline; there is no separate pre-fetch step. Demote pre-built dist and ad-hoc npm pre-fetch to rejected/deferred alternatives, and abandon the repo-root CycloneDX/git-hook approach (91792). Incorporate maintainer review feedback: shorter and decision-focused, with no inlined recipe files. Change-Id: I7d73812cc91079080af80f22cba49cf19279b839 Signed-off-by: Jason Westover <jwestover@nvidia.com>
2026-08-31Security: Pin floating package versionsNikhil Ashoka2-4/+4
- Remove ^ from the two packages that allowed silent auto-updates on every npm install, closing the door on ChainDrop-style npm supply-chain attacks where a compromised higher patch/minor version is pulled in without review: - @typescript-eslint/eslint-plugin: ^8.55.0 → 8.56.1 - @typescript-eslint/parser: ^8.55.0 → 8.56.1 Change-Id: Ie8b3878ce2aeaee6a89ee9e4681a6088aa3de770 Signed-off-by: Nikhil Ashoka <a.nikhil@ibm.com>
2026-08-28Fix form conditions that test nonexistent propertiesBill Chan3-11/+9
Four conditions read a property that does not exist, so none of them evaluates the way its author intended. DateTime guards a block that shifts the third NTP address into the second slot after a successful save. The condition reads this.form.ntp.thirdAddres, while the form model defines thirdAddress, so it has never been true. Correcting the name would not make the block run: submitForm filters the empty entry out of the request and then calls setNtpValues(), which rebuilds form.ntp from the compacted list, so by the time the callback runs the second address is already populated and the third already empty. updateDateTime does not commit ntpServers either, so the watcher cannot reopen a hole. Remove the block rather than correct the name - a correctly spelled condition that is always false reads as live code, and invites a later refactor to revive a shift that would then run twice. The guard above it, if (!isNTPEnabled) return, existed only to protect that block and goes with it. ModalSettings and ModalAddDestination test validators that are not declared. lockoutDuration is validated by minValue but the template reads minvalue; lockoutThreshold and port are validated by minValue and maxValue but their templates read minLength and maxLength. Each reference yields undefined and the conditions negate it, so the branch is taken every time the invalid-feedback block renders, leaving the range message in the DOM even for a valid field, where CSS hides it. The message that appears is the right one today only because each of those fields has a single other validator; it would become wrong, silently, as soon as another one is added. Test the validator's $invalid flag instead, which is the form these same files already use for required.$invalid and ipAddress.$invalid. Negating the validator entry itself would not work either: in Vuelidate 2 it is an object, so the branch would never be taken. Tested: In a browser against a QEMU BMC, machine cypress, with each case run on this commit and on its parent. Settings > Date and time, NTP selected, first address set, second empty, third set: after Save the third value appears in the second field within 100ms and the third field is empty, identically before and after this change. That compaction is setNtpValues() inside submitForm, not the removed block. The success toast still appears. Account policy settings: a lockout threshold of 99999 reports "Value must be between 0 - 65535" and an empty one reports "Field required"; with unlock method set to manual, a lockout duration of 0 reports "Must be at least 1" and an empty one "Field required". SNMP alerts > Add destination: a port of 99999 and a port of abc both report "Value must be between 0 - 65535", while 161 and empty are accepted. Every one of those messages is identical before and after. The only difference observed is that before this change the range message is present but hidden for a valid field, and after it nothing is rendered. Also verified that every corrected name is declared where it is now read, that a scan of all .vue files reports no Vuelidate reference whose validator is undeclared in the same file, that eslint passes on all three files, and that prettier 3.4.2 reports both modal files clean. Change-Id: Ib59a22296452e890877e784d3077b166d6d81fc5 Signed-off-by: Bill Chan <bill_chan@jabil.com>
2026-08-20Fix auth popup on login page with env buildsJason M. Bills2-9/+9
The ~@/ prefix in @font-face url() declarations is webpack-specific syntax. Vite 6 does not strip the tilde, so the font URLs are left unresolved in the compiled CSS output and the font files are never emitted to dist/. When the browser loads the login page and requests a font at the broken path, bmcweb cannot find a matching route in webroutes::routes and — because no session exists — returns 401 with WWW-Authenticate: Basic, triggering the browser credentials popup. Remove the leading ~ so Vite resolves the @/ alias correctly, copies the font files into dist/assets/, and rewrites the CSS references to proper absolute paths that bmcweb registers and serves without auth. Fixes both _intel.scss and _ibm.scss which share the same pattern. Tested: Confirmed that with .env.intel loaded, there is no longer an auth popup when loading the login page. Change-Id: Ie2a40bed55da057ae75bac111736cb947bac5dc4 Signed-off-by: Jason M. Bills <jason.m.bills@linux.intel.com>
2026-08-20Fix translation bugs and remove unused keysNikhil Ashoka6-132/+22
- Fix three structural bugs found by locale audit: - ka-GE: rename pageFirmware.sectionTitleHostCards to sectionTitleBiosCards to match the key used by FirmwareCardsBios.vue. - ru-RU: move global.offline.okToRetryCancelToLogin out of global.toast.offline to global.offline, restoring the correct nesting path that matches en-US and ka-GE. - PostCodeLogs: fix deleteAllLogs confirm dialog to reference pagePostCodeLogs.modal.deleteAllMessage/Title instead of pageEventLogs.modal.*, decoupling the two pages so future wording changes to Event Logs cannot silently affect Post Code Logs. - TableDns: fix delete action title passed as a raw key string literal to TableRowAction; wrap with i18n.global.t() so the translated string is rendered instead of the key path. - Remove 30 unused translation keys from all three locale files (en-US, ru-RU, ka-GE). They were not being used. Change-Id: I7edd9b326e1a4ad096508d5ed1661e1234c7f571 Signed-off-by: Nikhil Ashoka <a.nikhil@ibm.com>
2026-08-13Fix header checkbox select-all in View All modeAravinth Sri Krishna Raja Raghavan2-8/+16
When "View All" is selected under Items per Page, perPage is 0. The selection logic fell back to `this.perPage || 10`, treating the falsy 0 as a page size of 10. Clicking the header checkbox therefore selected only the first 10 displayed logs instead of all of them, and the selected count did not reflect the true total. Treat perPage === 0 as "View All" so the computed page bounds span every item. The calculation is centralized in a getPageBounds() helper shared by the select-all handler and the header checkbox state logic, keeping the two paths consistent. Also fix a UI state bug where, after a resolve/unresolve action, the row checkboxes appeared unselected but the selection header remained visible and still referenced the stale selection. clearSelectedRows() is now called in a finally() block so it runs whether the dispatch succeeds or fails, keeping the selection state consistent. fix issue for: https://github.com/openbmc/webui-vue/issues/142 Change-Id: I46b33c1d73c633d6c7df446ceecaf4222be9ea90 Signed-off-by: Aravinth Sri Krishna Raja Raghavan <aravinths@ami.com>
2026-08-12show specific error for duplicate SNMP alert destinationVijaysankar Ravi4-1/+9
Use findMessageId() to detect ResourceAlreadyExists in the redfish error response and show a specific toast instead of the generic add destination error. Tested: Adding a duplicate SNMP destination on AST2600 EVB shows the specific error toast instead of the generic one. Related: https://gerrit.openbmc.org/c/openbmc/phosphor-dbus-interfaces/+/90890 https://gerrit.openbmc.org/c/openbmc/phosphor-snmp/+/92218 https://gerrit.openbmc.org/c/openbmc/bmcweb/+/93102 Change-Id: I5a4fc6541c246085099aaad7d2515bb84805cb16 Signed-off-by: Vijaysankar Ravi <vijaysankarr@ami.com>
2026-08-12Replace v-model with :model-value in PoliciesNikhil Ashoka1-49/+16
* Replaced v-model with :model-value on SSH, IPMI, vTPM, RTAD toggles and Session Timeout select, since the bound computed properties are read-only getters backed by the Vuex store. * Removed no-op setters (set(newValue) { return newValue; }) from all five computed properties that existed solely to satisfy v-model's two-way binding requirement. * Simplified rtadState and vtpmState boolean expressions from if/else blocks to a single equality check. * State changes continue to flow through the existing @update:model-value handlers which dispatch the appropriate Vuex store actions. * This change is a follow-up action from https://gerrit.openbmc.org/c/openbmc/webui-vue/+/89544 which implemented Basic Auth using :model-value — applying the same pattern consistently across all other policy toggles on the page. * Tested: Policies page loads correctly, all toggles and session timeout select reflect store state. Enable/Disable interactions dispatch store actions as expected. Change-Id: Ibb2ee51615ed23a397dd9b99eb99e2920320f8a4 Signed-off-by: Nikhil Ashoka <a.nikhil@ibm.com>
2026-07-20Fix toast visibility and auto-hide behaviorAravinth Sri Krishna Raja Raghavan1-3/+5
In bootstrap-vue-next 0.40.8 a toast's modelValue controls visibility: a number auto-hides after that many milliseconds, true shows until dismissed, and false is never rendered. Because non-success toasts were created with modelValue: false, only success toasts (which used a numeric value) ever appeared. Give every variant a valid modelValue so error, info, and warning toasts render. Success toasts auto-dismiss after 10s; all other variants stay visible until the user closes them manually so important messages are not missed. Change-Id: I2d885aa81d3cfb040d3e29f570f8c8855beae0f1 Signed-off-by: Aravinth Sri Krishna Raja Raghavan <aravinths@ami.com>
2026-06-25Add Access Denied alert to SOL consoleAravinth S12-71/+150
Non-admin users navigating to the Serial Over LAN page had no clear feedback — the page either failed silently or showed a generic error. Show the SOL button and nav item to all users and render an Access Denied alert when the session lacks the required privilege. A reusable AccessDeniedAlert global component is introduced so other restricted pages can adopt the same pattern with a single line. Change-Id: Ifbb93bb966c801b3a72230e8f3b752b62ef22929 Signed-off-by: Aravinth Sri Krishna Raja Raghavan <aravinths@ami.com>
2026-06-23OWNERS: Add myself as a reviewerAravinth S1-0/+4
Add myself to the reviewer list. These are my commits: https://gerrit.openbmc.org/q/owner:aravinths@ami.com Change-Id: I0b7cec9c67d6e0cfa008efe01c74ab89b5c5513f Signed-off-by: Aravinth Sri Krishna Raja Raghavan <aravinths@ami.com>
2026-06-23Preserve Content-Encoding header on dev proxy responseGrégoire Layet1-1/+0
The bmcweb backend can send content encoded in gzip or zstd. Without the content-encoding in the response, the browser does not decode the data. This breaks numerous function, as this is not intended behavior. Functions fetching the redfish API, like getSystemPath from the GlobalStore, would receive encoded data. Example: data: "(�/�d\u0003\u0000e\u0004\u0000�\u0006\u0017\u001bpi�f8l���@%\..." The solution is simply to remove the deletion of the content-encoding field. This line was introduced in 'Migrate build system from Vue-CLI to Vite'. 063a8e0efc946b319300c610a3fb44dde4433d31 In January 20, 2026 [1] There is no indication regarding an encoding issue being fixed in the commit message. Just removing the line fixes this issue. Now received data look like: data: { "@odata.id": "/redfish/v1/Systems", "@odata.type": "#ComputerSystemCollection.ComputerSystemCollection", "Members": [ { "@odata.id": "/redfish/v1/Systems/system" } ], "Members@odata.count": 1, "Name": "Computer System Collection" } [1] https://github.com/openbmc/webui-vue/commit/063a8e0efc946b319300c610a3fb44dde4433d31 Change-Id: Idfa0a82b34628bc83f47c3eeba1ffeb0e8748a4a Signed-off-by: Grégoire Layet <gregoire.layet@9elements.com>
2026-06-22Fix typo in useDnsStateIpv6 computed propertyAravinth S1-1/+1
The computed property useDnsStateIpv6 in NetworkGlobalSettings.vue had a duplicate 'v6' suffix, referencing useDnsEnabledIpv6v6 which does not exist on the store object. Correct the typo to useDnsEnabledIpv6 to match the property defined in the setGlobalNetworkSettings mutation in NetworkStore.js. Change-Id: I8772d62a81e8825f936c08d2f9056531d6ae811e Signed-off-by: Aravinth Sri Krishna Raja Raghavan <aravinths@ami.com>
2026-06-18Fix sensors page being emptyGrégoire Layet1-2/+1
Issue: The sensors page should list all sensors from all hosts. This is not the case. The commit adding this issue was 'Implemented Power page with VueQuery and Composition API' 99099183438d878391f66d3c674fa2cd037a7840 Committed on June 9, 2026 [1] The commit add to the discoverParentsWithSubResource function the select query parameter to the parentCollectionPath. As of today this function is only used in useAllSubResources. The useAllSubResources function is also only used once, with the parentCollectionPath='/redfish/v1/Chassis'. This path get back : { "@odata.id": "/redfish/v1/Systems", "@odata.type": "#ComputerSystemCollection.ComputerSystemCollection", "Members": [ { "@odata.id": "/redfish/v1/Systems/system" } ], "Members@odata.count": 1, "Name": "Computer System Collection" } If this is filtered with the select='Sensors', then we have nothing. There is no reason to apply the select filter to the parentCollectionPath query. Solution: This patch remove the filter on the parentCollectionPath query. Tested: - all sensors are now visible in the sensors page [1] https://github.com/openbmc/webui-vue/commit/99099183438d878391f66d3c674fa2cd037a7840 Change-Id: I0a35f9468a9583e4e87b6fd21cd9d81c08fd4fbe Signed-off-by: Grégoire Layet <gregoire.layet@9elements.com>
2026-06-17Add expandable rows to Certificates pageAravinth S7-3/+649
This change allows users to view detailed certificate information by clicking a chevron icon to expand each certificate row. This makes it easier for administrators to inspect certificates without leaving the page or using external tools. Why this enhancement is needed: System administrators need complete certificate details for security audits, compliance verification, and troubleshooting SSL/TLS issues. Previously, users had to export certificates or use external tools to view comprehensive information, which was inefficient. What's included in the expanded view: - Certificate metadata: version, serial number, signature algorithm - Complete issuer details: organization, common name, unit, location - Complete subject details: who the certificate is issued to - Full validity timestamps with timezone information Implementation details: - Expand button aria-label is row-specific (e.g. "Expand table row HTTPS Certificate") so screen readers identify each row uniquely - Two-column layout uses <b-col sm="6"> to stack on small screens, matching the Inventory page pattern - Section headings (Issuer Information, Subject Information) are conditionally rendered — hidden when all fields in the section are absent, avoiding empty bold headers - X.509 Version stored only when present in the API response; displayed as v1/v2/v3 (ASN.1 integer + 1) for human readability - formatSerialNumber only reformats strings that contain at least one A-F hex letter; pure decimal serials are returned as-is - CertificateString removed from Vuex state mapping entirely - Unit tests added: store mapping (issuer, subject, serialNumber, Version conversion, absent Version) and component tests (expandLabel per-row identity, formatSerialNumber all input cases) Tested with HTTPS, LDAP, and TrustStore certificate types. Change-Id: I735ad571c189d7ba84464bf4a9f1d2280175b128 Signed-off-by: Aravinth Sri Krishna Raja Raghavan <aravinths@ami.com>
2026-06-16Add password change confirmation for own userAravinth S4-9/+40
Ensure that when a logged-in user updates their own password through the WebUI, the user receives a confirmation popup before performing the PATCH request. After successful password change, the WebUI logs out the user by clearing frontend authentication state and redirecting to the login page. This implementation addresses architectural concerns by avoiding backend session management from the UI. The updateUser action remains pure - it only updates user data without side effects. Circular dependency (src/store/index.js importing UserManagementStore, which imported @/store) has been eliminated. Frontend logout is handled in the component layer after successful password update, not in the store. The logout action clears local authentication state and removes the session via the standard logout flow, without introducing circular dependencies or hidden side effects in store actions. Testing: 1. Log in as a test user through the WebUI 2. Navigate to the user settings/account management page 3. Attempt to change the password for the logged-in user 4. Verify that a confirmation dialog appears with the message: "This user will be logged out and must sign in again with the new password" 5. Click OK/Confirm in the dialog 6. Verify that the password is updated successfully 7. Verify that the user is logged out and redirected to login page 8. Attempt to log in with the new password 9. Confirm successful login with new credentials 10. Verify that changing another user's password (if permitted) does NOT show the confirmation dialog or trigger logout Change-Id: I638bac731294171648258260ff2af4a09bc02aa2 Signed-off-by: Aravinth Sri Krishna Raja Raghavan <aravinths@ami.com>
2026-06-16Fix network interface reset on data refreshAravinth S1-2/+8
When getEthernetData was called after any save action (e.g., adding an IPv4 address), it unconditionally reset selectedInterfaceId back to the first interface (eth0). This caused subsequent API patches to target eth0 even when the user had navigated to a different tab (e.g., eth1). Only set selectedInterfaceId to firstInterfaceId on initial load when it is empty, preserving the user's active tab selection across data refreshes. Testing: 1. Navigate to Settings > Network page 2. Verify eth0 is selected by default on initial load 3. Switch to eth1 tab 4. Add or modify an IPv4 address on eth1 5. Verify the change is saved to eth1 (not eth0) 6. Confirm eth1 tab remains selected after the save 7. Repeat steps 3-6 with other network interfaces if available 8. Test with different configuration changes (DHCP enable/disable, IPv6 settings) to ensure tab selection persists Fixes: https://github.com/openbmc/webui-vue/issues/125 Change-Id: Ic112e88173d4d3c5c1409a17bee4837673523991 Signed-off-by: Aravinth Sri Krishna Raja Raghavan <aravinths@ami.com>
2026-06-14Implemented Basic Auth in PoliciesNikhil Ashoka5-0/+125
- Implemented Basic Auth setting in Policies page. - User able to Enable/Disable the policy setting from UI. - Added property presence check. - Tested: p11 BMC machine, Able to enable/disable Basic auth, Checked with and without redfish property to ensure UI doesn't break. Checked success and error cases. Change-Id: I08c0ccb275dbe068894de9cb35d6a286b4dc6e4f Signed-off-by: Nikhil Ashoka <a.nikhil@ibm.com>
2026-06-12Downgrade xterm to v4 for bmcweb CSP compatibilityJason Westover3-39/+41
@xterm/xterm v6 injects runtime <style> elements via DomRenderer _injectCss(), which violates bmcweb's style-src 'self' Content Security Policy and breaks the Serial Over LAN console in production. Revert to xterm 4.19.0 with matching xterm-addon-attach and xterm-addon-fit packages, and restore the pre-v6 import paths in SerialOverLanConsole. Import xterm.css in an unscoped style block so Vue scoped attribute selectors do not prevent xterm's helper textarea hiding rules from applying to dynamically created terminal DOM. Change-Id: Ifc34dd876c576e53a5253d9dd215b8e86e97fc26 Signed-off-by: Jason Westover <jwestover@nvidia.com>
2026-06-11Register missing Bootstrap-Vue dropdown componentAravinth S1-0/+4
The TableFilter component uses BDropdownForm and BDropdownItemButton but these components were not imported or registered in main.js, causing Vue component resolution errors at runtime. Add both components to the bootstrap-vue-next imports and register them with the Vue app instance to resolve the errors. This follows the existing pattern in the codebase where Bootstrap-Vue-Next components are individually imported and registered rather than using a global registration approach. Change-Id: I4bb4ca75941b7bbc5bc6a12be44b22fc9c8d234e Signed-off-by: Aravinth Sri Krishna Raja Raghavan <aravinths@ami.com>
2026-06-09Implemented Power page with VueQuery and Composition APINikhil Ashoka12-212/+507
This change switches power control to the EnvironmentMetrics-based Redfish endpoint, derives minimum and maximum power cap values dynamically from Redfish data, and updates ControlMode and SetPoint handling to align with the latest schema. Key changes: 1. Power control API and Redfish types: - Removes src/api/services/powerControlService.ts; fetching and PATCH are handled in the composable using shared Redfish utilities - Adds EnvironmentMetrics and PowerLimitWatts types in src/api/types/redfish.ts with proper ControlMode enum ('Automatic' | 'Disabled' | 'Manual' | 'Override') - Chassis gains an EnvironmentMetrics link - Composable resolves the Chassis collection via useRedfishCollection<Chassis>('/redfish/v1/Chassis'), picks the first chassis with EnvironmentMetrics, and fetches that resource with useQuery; mutation sends PATCH and invalidates queries to refetch fresh server state (returns Promise<void>; view owns user-facing messages) 2. Power control composable (src/components/Composables/usePowerControl.ts): - Replaces Vuex PowerControlStore with a Composition API-based composable - Uses useRedfishRoot() and useRedfishCollection for cached ServiceRoot and Chassis; uses TanStack Query to load and cache EnvironmentMetrics power data - Configures staleTime (30s freshness window) and refetchInterval (30s automatic polling when tab visible) for live power consumption updates - Note: Only controls the first Chassis with EnvironmentMetrics in multi-chassis systems (intentional for current use case) - Forwards AbortSignal to API calls for proper request cancellation - Reuses shouldRetry function from useAllSubResources - Derives dynamic min and max power cap values from Redfish PowerLimitWatts.AllowableMin/Max - Provides a mutation for submitting updated SetPoint and ControlMode; omits SetPoint when disabling to avoid sending invalid values - Handles all ControlMode enum values (Automatic, Disabled, Manual, Override); UI sets Automatic/Disabled but preserves Manual/Override when read from server - Type-safe parameters (number | null instead of string coercion) 3. Toast composable and global plugin: - useToast.ts (renamed from .js) uses bootstrap-vue-next useToast() with TypeScript types; keeps successToast/errorToast API with i18n titles - Type restricted to string for simplicity; includes TODO for potential VNode support expansion if needed - src/plugins/toast.js continues to expose global $toast for Options API - BVToastMixin.js updated to use modelValue and extract VNode content for consistency with bootstrap-vue-next 0.40.8 - Both implementations use isStatus: true for consistent toast styling with status icons 4. Views modernization: - Refactors src/views/ResourceManagement/Power.vue to use <script setup>, usePowerControl(), and the new toast composable; submitForm uses try/catch and t('pageServerPowerOperations.toast.*') for success/error toasts - Implements value caching to preserve user's typed input when toggling power cap checkbox on/off - Guards form sync watcher with v$.value?.$dirty check to prevent overwriting in-progress edits during background refetch - Loader semantics: show on first load (isLoading) and mutations, but render cached data instantly on subsequent visits with silent background refetch (avoids flicker) - Renamed validator from 'between' to 'withinPowerCapRange' to avoid confusion with Vuelidate's built-in validator - Handles all ControlMode values (Automatic, Disabled, Manual, Override) in form state synchronization - Refactors src/views/Overview/OverviewPower.vue to read from the power control composable instead of Vuex; implements settled computed to emit overview-power-complete only when chassis collection is fetched AND either no EnvironmentMetrics exists or metrics query has completed (prevents premature completion) - Shows power cap for all active control modes (Automatic, Manual, Override) - Removes mapState/mapActions usage and related Vuex wiring 5. Store cleanup and typing: - Deletes src/store/modules/ResourceManagement/PowerControlStore.js - Removes PowerControlStore registration from src/store/index.js - Updates src/store/api.d.ts to match actual implementation (set_auth_token with snake_case, accepts string | null | undefined) - Adds src/i18n.d.ts to provide basic typing for the shared api Tested-by: Manual testing on development server - Power consumption and cap values load correctly from EnvironmentMetrics with automatic 30-second polling (refetchInterval) when tab is visible - Min and max power cap values reflect dynamic limits from Redfish - Updating the power cap and enable state sends correct SetPoint and ControlMode values; SetPoint is omitted when disabling - All ControlMode values (Automatic, Disabled, Manual, Override) are handled correctly - User's typed values are preserved when toggling power cap checkbox - Form edits are not overwritten by background refetch (dirty state guard) - Success/error toasts show localized messages with consistent modelValue-based timing and status icons - Overview power card reflects updated power state; overview loader waits for both chassis and metrics queries to settle before completing - Request cancellation works properly on component unmount Change-Id: Ic61631efd8790150a5e2914822f1dd25bd77305a Signed-off-by: Nikhil Ashoka <a.nikhil@ibm.com>
2026-06-02Add dynamic language selector in headerAravinth S11-53/+188
Enable users to switch between English, Russian, and Georgian languages directly from the application header, eliminating the need to log out and log back in to change language preferences. Prior to this enhancement, changing the interface language required users to: - Log out from their current session - Return to the login page - Select a different language - Log back in with credentials This workflow disruption made it impractical for operators to switch languages during their work sessions. The new language selector in the user dropdown allows users to: - Change language instantly from any page without logout - Switch between languages as needed during a single session - Maintain active sessions and current page context - Access all three supported languages (English, Russian, Georgian) The language preference persists across sessions via the Vuex store, so the selected language remains active after logout and login. This improvement is particularly valuable for: - Multilingual teams sharing the same BMC system - Operators who need to verify terminology in different languages - Training scenarios where instructors switch between languages - International deployments with diverse user bases Implementation includes: - Language dropdown in user menu (between Profile Settings and Log Out) - getAvailableLanguages() helper in i18n.js using Intl.DisplayNames to automatically generate language labels in "{English} - {Native}" format (e.g., "Russian - Русский", "US - English") - getRoutePageTitle() helper in i18n.js to eliminate duplicated route-to-title logic between App.vue and PageTitle.vue - Reactive translations via Vue i18n computed properties - Page title updates in both DOM (PageTitle component) and browser tab (App.vue document.title) - Component re-rendering triggered by routerKey increment - Centralized localStorage persistence in GlobalStore.js setLanguagePreference mutation - Translation keys added to en-US.json, ru-RU.json, and ka-GE.json (global.pageTitle.missing, appHeader.language) All interface text, navigation menus, and page titles update immediately when language is changed. Change-Id: Ie11523c5ff23fc1600aca2d8ee5adb542c5ce4b3 Signed-off-by: Aravinth Sri Krishna Raja Raghavan <aravinths@ami.com>
2026-05-27Add privilege check for firmware update pageAravinth S5-0/+83
Disables firmware update page buttons for users with "Read-only" privileges to improve user experience. This helps users understand when they lack permissions to perform firmware updates based on their current session role. This is a UI-only improvement. Backend (bmcweb) validates all operations according to Redfish privilege rules regardless of UI state. Changes: - Created reusable usePrivilegeCheck() composable - Added privilege check to disable firmware update controls for read-only users - Added info banner to notify "The attempted action is not accessible from the logged in account. Contact your system administrator to check your privilege role". - Follows Vue 3 Composition API patterns Tested-by: Manual testing with Administrator, Operator, and ReadOnly roles Change-Id: I7e6e28267b094ab04f7dcc4b1e0cc609dc7f5e28 Signed-off-by: Aravinth Sri Krishna Raja Raghavan <aravinths@ami.com>
2026-05-19Show image name during virtual media redirectionAravinth S6-9/+128
Previously, when a user started virtual media redirection and navigated to another page, the image name was not shown upon returning. This update retains the image name on the Virtual Media page during Single Page Application (SPA) navigation. **Implementation:** - Active file and nbd objects are preserved in Vuex store state during SPA routing; the filename is displayed using the File.name property. - Proxy device objects are consistently shaped with file and nbd fields initialized to null in all construction paths. - Virtual media store is cleared on logout via a new clearDevices mutation, ensuring stale state is not retained across sessions. - When the BMC reports a device as Inserted but no browser-owned NBD connection exists (e.g. another UI session), the UI shows an informational label and a Stop button that ejects via Redfish EjectMedia instead of assuming a local NbdServer is present. **Limitations:** The image name is only retained during in-app navigation and is lost on: - Browser refresh (F5) - WebSocket connection cannot survive page reload - Duplicate tabs - each tab maintains independent state **Testing:** 1. Image name displays when starting virtual media redirection 2. Image name persists when navigating between pages 3. Image name clears when stopping redirection 4. Second tab with active redirection shows informational state; Stop ejects via Redfish and both tabs return to idle 5. Logout clears virtual media state; new session starts clean 6. Multiple proxy devices maintain independent state Change-Id: I5568025382a18adf89b18d3e81026c3112ae1e7e Signed-off-by: Aravinth Sri Krishna Raja Raghavan <aravinths@ami.com>
2026-05-19Add screenshot capture button to KVM consoleHariharan Rangasamy4-1/+36
Add new "Capture Screenshot" button in KVM toolbar. Button only appears when KVM is connected. Downloads KVM canvas as PNG image with timestamp filename. The screenshot functionality captures the current state of the KVM display. Tested: 1. Launch KVM from web. 2. Click on Capture Screenshot. 3. The PNG image is downloaded. Change-Id: Ie9a0062c0f6ca9878955b2c558cbc866849f77ef Signed-off-by: Hariharan Rangasamy <hariharanr@ami.com>
2026-05-14OWNERS: Promote Jason Westover to maintainerJason Westover1-1/+1
I propose myself (Jason Westover) for promotion from reviewer to maintainer. I have been actively contributing commits and reviews to webui-vue. I would like to help drive test integration into webui-vue and to help improve the developer experience (DX). Current focus is around Redfish OpenAPI schema integration, and integrating vue-query invalidation with SSE updates. I have proposed some new design docs and have more planned: docs: Add design doc for Redfish privilege checking: https://gerrit.openbmc.org/c/openbmc/webui-vue/+/87153 docs: Add SSE integration design document: https://gerrit.openbmc.org/c/openbmc/webui-vue/+/87161 These are my commits so far: https://gerrit.openbmc.org/q/owner:jwestover@nvidia.com These are my reviews so far: https://gerrit.openbmc.org/q/reviewer:jwestover@nvidia.com Change-Id: If8afdbf39efb7e5b5e8c142d3c6c23e67aa85b5d Signed-off-by: Jason Westover <jwestover@nvidia.com>
2026-05-14ProfileSettings: show current session privilegeAravinth S5-5/+282
Show the current session privilege on the Profile Settings page. The displayed privilege is derived from the active Redfish session, not from the user account definition, so label it as Session privilege and present it with semantic description list markup. Also add a unit test covering the profile info list structure and session privilege display. Change-Id: I6cf539c29366dc0a9752f9994ebcf4a3c45cf6b8 Signed-off-by: Aravinth Sri Krishna Raja Raghavan <aravinths@ami.com>
2026-05-12Prevent root user from bulk selectionAravinth S6-13/+103
Exclude root user from bulk operations to prevent accidental deletion, enabling, or disabling of the critical root account. This addresses community security concerns where administrators could accidentally perform bulk operations on the root user, potentially locking themselves out of the system. - Disable root user's checkbox in the user table and show a reason tooltip - Exclude root from "select all" header checkbox selection - Add centralized root detection in userManagement store with env fallback (VITE_ROOT_USERNAME/ROOT_USERNAME, default: root) - Simplify delete action enable logic to !isSelf && !isRoot - Restore mixin-compatible onChangeHeaderCheckbox behavior (filteredItems, pagination window, post-select reconciliation) - Keep header potentially indeterminate after select-all by design when root is excluded - Do not clear bulk selection on single-user delete - Implement cross-browser tooltip behavior for disabled root checkbox (wrapper-based trigger with improved placement and readability) Testing: 1. Navigate to Security & Access > User Management 2. Verify root checkbox is disabled (grayed out) and shows tooltip 3. Click "Select All" - only non-root users are selected 4. Verify header can remain indeterminate when root exists 5. Perform single-user delete and verify existing bulk selection is preserved 6. Perform delete/enable/disable on test users and verify bulk operations work normally 7. Verify tooltip visibility/readability on Chrome, Edge, and Firefox Change-Id: Iffc9356ee6f5771bed381255173bbde08efd85e1 Signed-off-by: Aravinth Sri Krishna Raja Raghavan <aravinths@ami.com>
2026-03-31Removed Unwanted filesNikhil Ashoka2-186/+0
- vue.config.js - Webpack/Vue CLI configuration - .browserslistrc - Deleted (Not needed with Vite) Change-Id: I5a83fd1a93437f24cc3f5b69a995f955410d5b2a Signed-off-by: Nikhil Ashoka <a.nikhil@ibm.com>
2026-03-30Fix build output filenames for bmcweb compatibilityJason Westover1-3/+5
bmcweb's webassets.hpp remaps any file starting with "index." to its parent directory path (intended for index.html -> / mapping). After the Vite migration, entry chunks are named "index.[hash].js/css" instead of webpack's "app.[hash].js/css", causing bmcweb to register them at the wrong route and return 404 for the actual asset URLs. Rename entry output files from "index" to "app" to avoid triggering bmcweb's index file detection logic. Tested: Verified production build outputs js/app.[hash].js and css/app.[hash].css with correct references in index.html. Change-Id: I83c36d3ff9d45a05adefd841372c4d64583b0a88 Signed-off-by: Jason Westover <jwestover@nvidia.com>
2026-03-18Dumps: fix action to delete all dumpsTan Siewert1-1/+1
`dumps` does not exist as computed property, only `allDumps` is available which was meant to be used. Tested: Remove single, multiple and all available dumps and ensured that the actions ran successfully. Change-Id: Id809b1a286d0eb345848481a69f2b796301c0fc9 Signed-off-by: Tan Siewert <tan.siewert@9elements.com>
2026-03-09Implemented dynamic fetching of the sensorsNishant Tiwari2-14/+7
This commit updates the implementation to dynamically discover all chassis and fetch sensors from each. Changes include: - Updated useSensors to use /redfish/v1/Chassis collection endpoint - Fixed discoverParentsWithSubResource to properly check individual chassis members for Sensors sub-resource The implementation now automatically discovers all chassis, fetches sensors from each, and deduplicates results by @odata.id. Tested: Verified sensors display from all chassis in multi-chassis systems Change-Id: Idadaef1be1b019cdded52ce7debe6f5f795e985e Signed-off-by: Nishant Tiwari <tiwari.nishant@ibm.com>
2026-03-05Implemented styling changesVedangi Mittal35-6436/+7488
- Implemented styling changes to restore UI appearance, behavior, margins, and sizing consistent with Vue 2. - Fixed broken styling across the search bar, filters, buttons, pagination, app navigation, cards, badges, and toast messages. Change-Id: If4aa37635136d94ebd3ad0a7533260bd788c2436 Signed-off-by: Vedangi Mittal <vedangimittal3004@gmail.com>
2026-02-24Implement Bootstrap 5 confirm modal dialogJason Westover8-161/+322
Replace window.confirm() shim with proper Bootstrap 5 modal using b-modal component from bootstrap-vue-next. This provides a consistent, themeable dialog experience matching the Vue 2 $bvModal.msgBoxConfirm() appearance across the application. Key changes: - ConfirmModal.vue: Full BS5 modal with request queue, ESC key support, optional processing state, and proper cleanup in beforeUnmount - All original Bootstrap 4 parameters preserved for consistent behavior The modal supports: - Multiple simultaneous confirm requests via queue - Custom titles and button text with i18n integration - Multi-line message support: `messageLines` - Variant styling (primary default, danger, secondary) - Auto-focus control for safer UX on destructive actions - Full theme customization via CSS variables - Modal positioned at top (not centered) matching Vue 2 behavior - No header close button for controlled dismiss behavior - Optional checkbox confirmation via confirmationText parameter Keyboard and focus enhancements: - Auto-focus configurable button when modal opens (cancel by default) - ESC key cancels dialog - $confirm() accepts optional second parameter for extra options - Added aria properties and removed unused refs Files using dialogs to test: - Logs: Dumps, EventLogs, PostCodeLogs - Operations: ServerPowerOperations - Security: Sessions, Certificates, Ldap, UserManagement - Settings: Network (IPv4/IPv6), SnmpAlerts Testing: - Manually tested most confirmation dialogs across the application - Verified keyboard-only interaction from Dumps page delete dialog Change-Id: I03fed8d79f40f47b43bc4b2c788396cf183b3e99 Signed-off-by: Jason Westover <jwestover@nvidia.com>
2026-02-24Fix spelling mistakes using codespellGeorge Liu3-3/+3
Change-Id: Iefb20fbf212f11d104aa1cff4f050e9ce6c60200 Signed-off-by: George Liu <liuxiwei@ieisystem.com>
2026-02-13Implemented Sensors page with VueQuery and Composition APINishant Tiwari18-6229/+15378
Introduce reusable Redfish API infrastructure and modernize the Sensors page to use Vue 3 Composition API with TanStack Query, eliminating the need for Vuex store patterns for server state management. This change provides a foundation for migrating other hardware status pages (Memory, Processors, Drives, etc.) to a more maintainable and performant architecture. Key changes: 1. Generic Redfish composables (src/api/composables/): - useRedfishRoot.ts: Caches ServiceRoot and detects OData support - useRedfishCollection.ts: Smart collection fetcher with OData $expand/$select support and graceful fallback - useAllSubResources.ts: Generic pattern for fetching nested resources from parent collections 2. Sensors page modernization: - Migrated from Vuex store to TanStack Query (Vue Query) - Created useSensors.ts composable for data fetching - Removed legacy Thermal and PowerSubsystem endpoints - Now uses only modern /Chassis/{id}/Sensors collection - Maintains existing UI/UX with Bootstrap Vue table 3. TypeScript support: - Added tsconfig.json and webpack ts-loader configuration - Created required Redfish type definitions - Preserves Redfish PascalCase property names 4. Performance optimizations: - Auto-detects and uses OData $expand for fewer API calls - Implements automatic caching and deduplication - Smart retry logic with exponential backoff - 30-second stale time with 5-minute garbage collection Benefits for future development: - The generic composables are designed for reuse across components: // Fetch all Memory from all Systems useAllSubResources<Memory>('/redfish/v1/Systems', 'Memory') // Fetch all Drives from all Storage useAllSubResources<Drive>('/redfish/v1/Storage', 'Drives') - Implemented TypeScript types - Reuses existing Bootstrap table components - Preserves existing UI/UX - Focuses on infrastructure reusability This pattern eliminates boilerplate Vuex store code and provides better developer experience with automatic loading states, error handling, and background refetching. Tested-by: Manual testing on development server - Sensors page loads correctly - OData optimization works when supported - Graceful fallback when OData unavailable - All table functionality preserved (sorting, filtering, export, cancel and searching) Change-Id: Id605319140f607b295d24085f3681f09ac0d5ebd Signed-off-by: Nishant Tiwari <tiwari.nishant@ibm.com>
2026-01-23Migrate unit tests from Jest to VitestJason Westover35-10927/+9777
Replace Jest test runner with Vitest for native ES modules support and faster test execution. This migration aligns the test tooling with the Vite build system and eliminates CommonJS compatibility issues. Why Vitest over Jest? While Jest is a mature ecosystem with broader adoption (45.5k GitHub stars vs Vitest's 15.7k), Vitest is the recommended testing framework for Vue 3 + Vite projects: 1. **Native ESM Support**: Vitest runs tests directly as ESM without transformation, while Jest requires Babel/transformation layers that add complexity and slow down test execution. 2. **Vite Integration**: Shares the same configuration, plugins, and resolvers as the Vite build system. This eliminates the dual-config maintenance burden (vite.config.js + jest.config.js). 3. **Vue 3 Ecosystem Alignment**: Vitest is created by the Vue team and is the official recommendation in Vue 3 documentation. It has first-class Vue component testing support via @vue/test-utils. 4. **Performance**: Cold start is significantly faster due to Vite's on-demand compilation. HMR for tests provides instant feedback during test-driven development. 5. **API Compatibility**: Vitest intentionally matches Jest's API, making migration straightforward and allowing developers to leverage existing Jest knowledge. ESLint 9 Upgrade: - Upgrade ESLint from 8.57.1 to 9.18.0 - Migrate from .eslintrc.cjs to eslint.config.js (flat config) - Upgrade eslint-plugin-vue from 9.2.0 to 10.0.0 - Replace eslint-plugin-vitest with @vitest/eslint-plugin@1.1.43 - Replace @vue/eslint-config-prettier with eslint-config-prettier - Add globals package for flat config environment definitions - Update lint-staged from 13.0.3 to 16.0.0 - Update prettier from 3.2.5 to 3.4.2 - Disable stricter vue rules for follow-up PR: vue/no-reserved-component-names, vue/no-unused-components, vue/no-deprecated-delete-set, vue/no-required-prop-with-default Pre-commit Hooks: - Add simple-git-hooks and lint-staged for automatic linting - Run eslint --fix on JS/Vue files before commit - Run prettier --write on markdown files before commit - Add .prettierrc.yaml matching CI configuration - Include .cjs/.mjs files in prettier JS override Documentation: - Update unit testing guide for Vitest - Update coding standards with pre-commit hook details References: - Vitest official comparison: https://vitest.dev/guide/comparisons.html#jest - Vue 3 testing guide: https://vuejs.org/guide/scaling-up/testing.html#unit-testing - Vite ecosystem recommendations: https://vitejs.dev/guide/features.html#testing Test Results: - 19 test files, 123 tests passing - No warnings or deprecation messages - Test execution: ~3.1s (on par with Jest) Changes: - Replace jest.config.js with Vitest config in vite.config.js - Create tests/vitest.setup.js with Vitest-compatible mocks - Update package.json scripts for Vitest - Add vue3-snapshot-serializer for cleaner snapshots - Use happy-dom and real i18n instance for faster tests Dependency Updates: - Remove @vue/cli-plugin-unit-jest, @vue/vue3-jest, babel-jest, jest - Add vitest, @vitest/coverage-v8, jsdom, happy-dom, vue3-snapshot-serializer Test File Migrations: - Replace jest.fn() with vi.fn() - Replace jest.spyOn() with vi.spyOn() - Replace jest.mock() with vi.mock() - Replace jest.resetModules() with vi.resetModules() - Replace jest.unmock() with vi.unmock() - Replace require() with dynamic import() for ESM compatibility - Add explicit Vitest imports (vi, describe, it, expect, etc.) Snapshot Improvements: - Use vue3-snapshot-serializer to strip data-v-* scoped style attributes from snapshots for cleaner, more stable output - Add SVG component stubs for logo assets to avoid verbose path data in snapshots (logo-header.svg, login-company-logo.svg, built-on-openbmc-logo.svg) - Updated all snapshot files for Vitest format - Removed obsolete Jest snapshot entries Performance Optimizations: - Use happy-dom instead of jsdom (17% faster environment setup) - Use real i18n instance instead of mock (eliminates redundant dynamic imports, 55% faster test execution) Tested: - npm run test:unit runs 19 test files, 123 tests, and passed them all with 0 warnings. Change-Id: Iaf04335db54a5ceeff09bcd43675a488828dc44f Signed-off-by: Jason Westover <jwestover@nvidia.com>
2026-01-20Migrate build system from Vue-CLI to ViteJason Westover54-6041/+3365
"Vue CLI is in Maintenance Mode!" https://cli.vuejs.org/ Vite is created by Vue's creator and is the recommended build tool for Vue 3. It supports most of the configured conventions in Vue CLI. Dev Server startup is 60X faster and HMR is noticeably faster ~50ms. Better Tree-shaking support and modern ESM support. This migration preserves all existing functionality while eliminating Vue 2 legacy dependencies. Build Output Comparison (gzipped): Master (Webpack) Vite Delta CSS: 39 KB 45 KB +6 KB (+15%) JS: 505 KB 483 KB -22 KB (-4.4%) Total dist: 556 KB 544 KB -12 KB (-2.2%) Build time: ~29s ~7s ~4x faster Build System Changes: - Replace vue.config.js with vite.config.js - Remove babel.config.js (Vite uses esbuild) - Remove postcss.config.js (Vite handles PostCSS internally) - Add index.html to project root with ESM module entry point - Add custom Vite plugin for directory import resolution - Rename .eslintrc.js to .eslintrc.cjs (ESM compatibility) Dependency Updates: - Remove @vue/cli-* packages and webpack-related dependencies - Add vite, @vitejs/plugin-vue, @vitejs/plugin-basic-ssl - Add vite-svg-loader, vite-plugin-compression - Upgrade Bootstrap to 5.3.8 - Upgrade Sass to 1.97.2 (supports quietDeps option) - Upgrade xterm to @xterm/xterm v6 (new package name) - Upgrade xterm-addon-* to @xterm/addon-* packages - Upgrade vue-i18n to v11 - Upgrade eslint to 8.57.1 - Upgrade axios-cache-interceptor to latest Environment Variable Migration: - Change VUE_APP_* prefix to VITE_* (Vite convention) - Replace process.env with import.meta.env in source files - Update .env.ibm, .env.intel example files - Update documentation with new variable names ESM Module Compatibility: - Replace require('@/eventBus') with ESM imports (~23 files) - Ensure event bus listeners are registered/unregistered with stable handler references to prevent leaks - Replace require.context with import.meta.glob in i18n.js - Convert SVG inline loader to vite-svg-loader component imports SCSS/Sass Updates: - Remove tilde (~) prefix from node_modules imports - Add silenceDeprecations and quietDeps for Bootstrap warnings - Fix color() function syntax for Sass 2.0 compatibility xterm.js v6 Migration: - Update imports to @xterm/xterm, @xterm/addon-attach, @xterm/addon-fit - Replace deprecated setOption() with constructor options - Add CSS fix for helper textarea visibility Dev Server: - Configure HTTPS with @vitejs/plugin-basic-ssl - Preserve proxy configuration for BMC backend - Add WebSocket proxy auth token forwarding for /console, /kvm, /vm - Configure HMR on separate WebSocket path (/ws_hmr) X-Auth-Token Persistence (opt-in): - Add VITE_STORE_SESSION env flag for non-cookie auth backends - Persist X-Auth-Token to session cookie when enabled - Enables direct browser navigation to Redfish endpoints Follow-on: CI/testing updates (unit test runner + run-ci alignment) Some Jest config changes skipped here since this follow-on commit switches to Vitest. follow-up change is here: https://gerrit.openbmc.org/c/openbmc/webui-vue/+/86511 Tested: Sanity tested most navigational screens in the default UI, including many different types of API calls. Tested most build options. Tested the new i18n:report and it is working correctly. Change-Id: Ie84d1ed6121ffe7d2ddb379084d833b8d5a6fccf Signed-off-by: Jason Westover <jwestover@nvidia.com>
2026-01-14Fix Unit tests and useI18n() misusejason westover109-1203/+1143
Vue 3's vue-i18n requires useI18n() to be called within setup() or reactive contexts. Calling it in Options API data() creates disconnected i18n instances that cannot resolve linked messages. Component fixes: - Enable globalInjection in i18n.js for automatic $t injection - Remove explicit useI18n() imports from 84 components that incorrectly called useI18n().t in their data() functions Unit test fixes: - Mock @/i18n module in jest.setup.js because Webpack's require.context() does not work in Jest, leaving the real module with no locale messages loaded - Re-export real createI18nInstance so i18n unit tests work - Update snapshots to reflect real translated text instead of raw translation keys - Fix b-form-radio/checkbox stubs to wrap content in div for proper data-test-id attribute inheritance - Remove duplicate i18n plugin installations from individual test files that caused 'already registered' warnings - Suppress expected missing-key warning in vendor overlay test Tested: - Sanity testing on webui, ensured translations work. - All Unit tests pass (19/19) with no Errors or Warnings. Change-Id: I9789acd823261eccc7affde0957dd22e8fec06b1 Signed-off-by: Jason Westover <jwestover@nvidia.com>
2026-01-12Fix boot source override handlingNikhil Ashoka1-1/+1
Add optional chaining to avoid errors when BootSourceOverrideTarget is missing. Change-Id: I176119ac115d92749722ed74aabd84ebd2dae384 Signed-off-by: Nikhil Ashoka <a.nikhil@ibm.com>
2026-01-12Migrate Vuelidate from v1 to v2 APIJason Westover30-538/+1268
Complete the migration from Vuelidate v1 (vuelidate 0.7.7) to v2 (@vuelidate/core 2.0.3 and @vuelidate/validators 2.0.4). Changes include: - Replace imports from 'vuelidate/lib/validators' with '@vuelidate/validators' - Convert static 'validations:' objects to 'validations()' methods which return the validation rules object - Update helpers.regex() syntax from v1 two-arg format helpers.regex('name', pattern) to v2 single-arg helpers.regex(pattern) - Create custom macAddress validator using regex since macAddress is not included in @vuelidate/validators v2 - Remove deprecated vuelidate 0.7.7 package from dependencies - Add unit tests for Vuelidate v2 migration verification - Fix DateTime store to continue with DateTime update even if NTP settings update fails - Fix Network Table components (IPv4, IPv6, DNS) missing @ok event handlers for Add modal dialogs - Fix CSR country dropdown by restoring COUNTRY_LIST data and moving useI18n() call to setup() function - Fix disconnected modals in Network page by using eventBus to communicate between child components and parent (hostname, MAC address, default gateway edit buttons) Tested: - npm run build completes successfully - npm run test:unit passes 66 new Vuelidate validation tests: - VuelidateMixin.spec.js: getValidationState method tests - TableDateFilter.spec.js: Date range validation tests - ModalHostname.spec.js: Hostname validation tests - ModalMacAddress.spec.js: MAC address validation tests - ModalUser.spec.js: User form validation tests - Manual testing performed: - User Management: Create/edit user with password confirmation - LDAP: Enable/disable with conditional field requirements - Date/Time: Switch between NTP and manual modes - Factory Reset: Confirm checkbox validation when server is on - Network Settings: Add IPv4, IPv6, DNS addresses via modals - Network Settings: Edit hostname, MAC address, default gateway - Certificates: Generate CSR with country dropdown working Change-Id: I0f6b5d89d1791b36977f1a3c16cbd10bca6a484a Signed-off-by: Jason Westover <jwestover@nvidia.com>
2026-01-08VirtualMedia: fix incorrect NBD export size encodingTroy Lee1-3/+3
The NBD export size is encoded as a 64-bit value (MSB/LSB) in NBDServer.js. The previous implementation relied on JavaScript bitwise operations (e.g. size >>> 32), which is incorrect because all bitwise operators coerce values to 32-bit integers. This resulted in an incorrect export size for large files, causing the kernel to detect an invalidly large NBD device and leading nbd_client to fail with: "Exported device is too big for me. Get 64-bit machine :-(" Fix the MSB calculation by using arithmetic division instead of bitwise shifts so the exported size is encoded correctly. Fixes: d36ac8a8be86 ("Migrate to Bootstrap 5 and remove Vue compat plugin") Tested: VirtualMedia on evb-ast2600. Change-Id: I18d8cdd05cf149907d31d79cfd5308c0943ef83e Signed-off-by: Troy Lee <troy_lee@aspeedtech.com> Signed-off-by: Vince Chang <vince_chang@aspeedtech.com>
2025-12-18Fix Vue 3 @change event bindings for formsJason Westover9-38/+112
In Bootstrap-Vue-Next (Vue 3), the @change event on BFormCheckbox and BFormRadio passes an Event object instead of the boolean value. This caused malformed API payloads like: {"LocationIndicatorActive": {"isTrusted": true, "_vts": 1765562875420}} instead of: {"LocationIndicatorActive": true} Replace @change with @update:model-value which correctly passes the new value in Vue 3/Bootstrap-Vue-Next. Components fixed: - OverviewInventory.vue: LED toggle - InventoryServiceIndicator.vue: LED toggle - InventoryTableSystem.vue: LED toggle - NetworkGlobalSettings.vue: 6 network switches - Policies.vue: 4 policy switches (SSH, IPMI, vTPM, RTAD) - TableIpv4.vue: DHCP switch - TableIpv6.vue: DHCPv6 switch - Ldap.vue: LDAP auth and service type controls Also adds safety net in api.js: - Request interceptor to strip Vue reactivity from payloads - Detects and warns about Event objects in API payloads - Improved response error handling with null safety - Conditional debug logging (development mode only) Change-Id: I180d9143087284e28c5066a6ffc141cd7f7038c6 Signed-off-by: jason westover <jwestover@nvidia.com>
2025-12-18Fix Vue 3 v-model and form event handlingJason Westover11-29/+181
Add proper Vue 3 v-model support to components that are used with v-model bindings from parent components: - FormFile: Add modelValue prop with computed getter/setter, emit both update:modelValue and input events for backward compatibility, maintain internal state when parent uses @input instead of v-model - Modal components: Add modelValue prop and isModalVisible computed property for proper two-way binding with bootstrap-vue-next Fix form validation event handling by changing @input to @change for select, radio, and checkbox elements. In Vue 3 with bootstrap-vue-next, these elements do not fire @input correctly on first selection. Components updated: - FormFile.vue - ModalConfigureConnection.vue - ModalAddDestination.vue - ModalUser.vue - ModalSettings.vue - ModalAddRoleGroup.vue - FirmwareModalUpdateFirmware.vue - FactoryResetModal.vue - ModalGenerateCsr.vue - ModalUploadCertificate.vue - DumpsModalConfirmation.vue Change-Id: Ib7376fdff8e9ab5e764f5fae80ac05a761b70312 Signed-off-by: Jason Westover <jwestover@nvidia.com>