├── src
├── app
│ ├── app.component.scss
│ ├── configs
│ │ ├── configs.component.scss
│ │ └── config-detail
│ │ │ └── config-detail.component.scss
│ ├── devices
│ │ ├── tls
│ │ │ ├── tls.component.scss
│ │ │ ├── tls.component.ts
│ │ │ ├── tls.component.spec.ts
│ │ │ └── tls.component.html
│ │ ├── alarms
│ │ │ ├── alarms.component.scss
│ │ │ └── alarms.component.spec.ts
│ │ ├── explorer
│ │ │ ├── explorer.component.scss
│ │ │ └── explorer.component.html
│ │ ├── general
│ │ │ ├── general.component.scss
│ │ │ └── general.component.spec.ts
│ │ ├── edit-tags
│ │ │ ├── edit-tags.component.css
│ │ │ └── edit-tags.component.html
│ │ ├── certificates
│ │ │ ├── certificates.component.scss
│ │ │ ├── add-cert-dialog
│ │ │ │ ├── add-cert-dialog.component.scss
│ │ │ │ ├── add-cert-dialog.component.html
│ │ │ │ └── add-cert-dialog.component.ts
│ │ │ └── certificates.component.html
│ │ ├── device-cert-dialog
│ │ │ ├── device-cert-dialog.component.scss
│ │ │ └── device-cert-dialog.component.ts
│ │ ├── device-enable-kvm
│ │ │ ├── device-enable-kvm.component.scss
│ │ │ ├── device-enable-kvm.component.html
│ │ │ ├── device-enable-kvm.component.ts
│ │ │ └── device-enable-kvm.component.spec.ts
│ │ ├── device-enable-sol
│ │ │ ├── device-enable-sol.component.scss
│ │ │ ├── device-enable-sol.component.html
│ │ │ ├── device-enable-sol.component.ts
│ │ │ └── device-enable-sol.component.spec.ts
│ │ ├── network-settings
│ │ │ ├── network-settings.component.scss
│ │ │ ├── network-settings.component.spec.ts
│ │ │ └── network-settings.component.ts
│ │ ├── hardware-information
│ │ │ └── hardware-information.component.scss
│ │ ├── device-toolbar
│ │ │ ├── pba-boot-dialog
│ │ │ │ ├── pba-boot-dialog.component.scss
│ │ │ │ └── pba-boot-dialog.component.html
│ │ │ ├── http-boot-dialog
│ │ │ │ ├── http-boot-dialog.component.scss
│ │ │ │ └── http-boot-dialog.component.html
│ │ │ └── device-toolbar.component.scss
│ │ ├── device-user-consent-dialog
│ │ │ ├── device-user-consent-dialog.component.scss
│ │ │ └── device-user-consent-dialog.component.html
│ │ ├── event-log
│ │ │ └── event-log.component.scss
│ │ ├── audit-log
│ │ │ ├── audit-log.component.scss
│ │ │ ├── audit-log.component.spec.ts
│ │ │ └── audit-log.component.html
│ │ ├── sol
│ │ │ ├── sol.component.scss
│ │ │ └── sol.component.html
│ │ ├── kvm
│ │ │ └── kvm.component.scss
│ │ ├── device-detail
│ │ │ └── device-detail.component.scss
│ │ ├── devices.component.scss
│ │ ├── device-log.service.spec.ts
│ │ └── device-log.service.ts
│ ├── domains
│ │ ├── domains.component.scss
│ │ └── domain-detail
│ │ │ └── domain-detail.component.scss
│ ├── login
│ │ └── login.component.scss
│ ├── ieee8021x
│ │ ├── ieee8021x.component.scss
│ │ ├── ieee8021x-detail
│ │ │ └── ieee8021x-detail.component.scss
│ │ └── ieee8021x.constants.ts
│ ├── profiles
│ │ ├── profiles.component.scss
│ │ ├── export-dialog
│ │ │ └── export-dialog.component.scss
│ │ ├── key-display-dialog
│ │ │ ├── key-display-dialog.component.scss
│ │ │ ├── key-display-dialog.component.html
│ │ │ ├── key-display-dialog.component.spec.ts
│ │ │ └── key-display-dialog.component.ts
│ │ ├── profile-detail
│ │ │ └── profile-detail.component.scss
│ │ └── profiles.constants.ts
│ ├── wireless
│ │ ├── wireless.component.scss
│ │ ├── wireless-detail
│ │ │ └── wireless-detail.component.scss
│ │ └── wireless.constants.ts
│ ├── event-channel
│ │ ├── event-channel.component.scss
│ │ └── event-channel.component.spec.ts
│ ├── proxy-configs
│ │ ├── proxy-configs.component.scss
│ │ └── proxy-config-detail
│ │ │ └── proxy-config-detail.component.scss
│ ├── shared
│ │ ├── are-you-sure
│ │ │ ├── are-you-sure.component.scss
│ │ │ ├── are-you-sure.component.html
│ │ │ ├── are-you-sure.component.ts
│ │ │ └── are-you-sure.component.spec.ts
│ │ ├── dialog-content
│ │ │ ├── dialog-content.component.scss
│ │ │ ├── dialog-content.component.html
│ │ │ ├── dialog-content.component.ts
│ │ │ └── dialog-content.component.spec.ts
│ │ ├── power-up-alert
│ │ │ ├── power-up-alert.component.scss
│ │ │ ├── power-up-alert.component.html
│ │ │ ├── power-up-alert.component.ts
│ │ │ └── power-up-alert.component.spec.ts
│ │ ├── add-device-enterprise
│ │ │ └── add-device-enterprise.component.scss
│ │ ├── static-cira-warning
│ │ │ ├── static-cira-warning.component.scss
│ │ │ ├── static-cira-warning.component.html
│ │ │ ├── static-cira-warning.component.ts
│ │ │ └── static-cira-warning.component.spec.ts
│ │ ├── random-pass-alert
│ │ │ ├── random-pass-alert.component.scss
│ │ │ ├── random-pass-alert.component.html
│ │ │ ├── random-pass-alert.component.ts
│ │ │ └── random-pass-alert.component.spec.ts
│ │ ├── add-device
│ │ │ ├── add-device.component.scss
│ │ │ └── add-device.component.html
│ │ ├── pipes
│ │ │ ├── date-formatter.pipe.ts.pipe.ts
│ │ │ ├── time-ago-formatter.pipe.ts.pipe.ts
│ │ │ ├── toolkit.pipe.ts
│ │ │ ├── date-formatter.pipe.ts.pipe.spec.ts
│ │ │ ├── time-ago-formatter.pipe.ts.pipe.spec.ts
│ │ │ └── toolkit.pipe.spec.ts
│ │ ├── auth-guard.service.ts
│ │ ├── config
│ │ │ └── snackBarDefault.ts
│ │ └── auth-guard.service.spec.ts
│ ├── core
│ │ ├── about
│ │ │ ├── about.component.scss
│ │ │ ├── about.component.spec.ts
│ │ │ ├── about.component.html
│ │ │ └── about.component.ts
│ │ ├── navbar
│ │ │ ├── navbar.component.scss
│ │ │ ├── navbar.component.ts
│ │ │ ├── navbar.component.spec.ts
│ │ │ └── navbar.component.html
│ │ └── toolbar
│ │ │ ├── toolbar.component.scss
│ │ │ └── toolbar.component.html
│ ├── app.component.html
│ ├── dashboard
│ │ ├── dashboard.component.scss
│ │ ├── dashboard.component.spec.ts
│ │ └── dashboard.component.ts
│ ├── authorize.interceptor.ts
│ ├── error-handling.interceptor.ts
│ └── app.component.ts
├── favicon.ico
├── assets
│ ├── logo.png
│ ├── kJEhBvYX7BgnkSrUwT8OhrdQw4oELdPIeeII9v6oFsI.woff2
│ └── i18n
│ │ └── translate-paginator-intl.ts
├── index.html
├── environments
│ ├── environment.prod.ts
│ ├── environment.enterprise.dev.ts
│ ├── environment.enterprise.ts
│ └── environment.ts
├── constants.ts
├── utils.ts
├── styles
│ ├── css2.css
│ ├── _variables.scss
│ └── styles.scss
└── test.ts
├── .gitattributes
├── .vscode
├── settings.json
├── launch.json
└── tasks.json
├── tsconfig.eslint.json
├── init.sh
├── license-header.js
├── .prettierrc.js
├── docker-compose.yml
├── cypress
├── support
│ └── e2e.ts
├── tsconfig.json
├── e2e
│ ├── fixtures
│ │ ├── formEntry
│ │ │ ├── paging.ts
│ │ │ ├── device.ts
│ │ │ ├── domain.ts
│ │ │ ├── wireless.ts
│ │ │ ├── urls.ts
│ │ │ ├── eventlogs.ts
│ │ │ ├── auditLogs.ts
│ │ │ ├── ieee8021x.ts
│ │ │ └── cira.ts
│ │ └── api
│ │ │ ├── stats.ts
│ │ │ ├── httpCodes.ts
│ │ │ ├── tags.ts
│ │ │ ├── general.ts
│ │ │ ├── networkConfig.ts
│ │ │ └── ieee8021x.ts
│ └── integration
│ │ ├── eventchannellogs
│ │ └── get.spec.ts
│ │ ├── dashboard
│ │ └── devicecount.spec.ts
│ │ ├── domain
│ │ ├── exipiration.spec.ts
│ │ ├── vault-read-certificate.spec.ts
│ │ ├── delete.spec.ts
│ │ └── create.spec.ts
│ │ ├── login
│ │ └── ensureEmpty.spec.ts
│ │ ├── profile
│ │ └── delete.spec.ts
│ │ ├── wireless
│ │ ├── delete.spec.ts
│ │ ├── create-error.spec.ts
│ │ └── create.spec.ts
│ │ ├── cira
│ │ ├── delete.spec.ts
│ │ └── create-error.spec.ts
│ │ ├── ieee8021x
│ │ └── delete.spec.ts
│ │ └── device
│ │ └── device.spec.ts
└── README.md
├── docker-compose.debug.yml
├── tsconfig.app.json
├── .dockerignore
├── .editorconfig
├── SECURITY.md
├── tsconfig.spec.json
├── .github
├── copilot-instructions.md
├── commitlint.config.cjs
├── PULL_REQUEST_TEMPLATE.md
├── workflows
│ ├── projectsSync.yaml
│ ├── semantic.yml
│ ├── dependency-review.yml
│ ├── docker.yaml
│ ├── trivy-scan.yaml
│ ├── nodejs.yaml
│ ├── cypress.yaml
│ └── release.yml
├── ISSUE_TEMPLATE.md
└── dependabot.yml
├── nginx.conf
├── .pre-commit-config.yaml
├── Dockerfile
├── Makefile
├── .releaserc.json
├── .devcontainer
└── devcontainer.json
├── tsconfig.json
├── .gitignore
└── karma.conf.js
/src/app/app.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | init.sh text eol=lf
--------------------------------------------------------------------------------
/src/app/configs/configs.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/devices/tls/tls.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/domains/domains.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/login/login.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/ieee8021x/ieee8021x.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/profiles/profiles.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/wireless/wireless.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/devices/alarms/alarms.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/devices/explorer/explorer.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/devices/general/general.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/devices/edit-tags/edit-tags.component.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/event-channel/event-channel.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/proxy-configs/proxy-configs.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/configs/config-detail/config-detail.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/devices/certificates/certificates.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/domains/domain-detail/domain-detail.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/shared/are-you-sure/are-you-sure.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/profiles/export-dialog/export-dialog.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/shared/dialog-content/dialog-content.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/shared/power-up-alert/power-up-alert.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/wireless/wireless-detail/wireless-detail.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/devices/device-cert-dialog/device-cert-dialog.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/devices/device-enable-kvm/device-enable-kvm.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/devices/device-enable-sol/device-enable-sol.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/devices/network-settings/network-settings.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/ieee8021x/ieee8021x-detail/ieee8021x-detail.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/devices/hardware-information/hardware-information.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/profiles/key-display-dialog/key-display-dialog.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/shared/add-device-enterprise/add-device-enterprise.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/shared/static-cira-warning/static-cira-warning.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/devices/certificates/add-cert-dialog/add-cert-dialog.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/devices/device-toolbar/pba-boot-dialog/pba-boot-dialog.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/proxy-configs/proxy-config-detail/proxy-config-detail.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "cSpell.words": [
3 | "CIRA"
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/src/app/devices/device-toolbar/http-boot-dialog/http-boot-dialog.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/devices/device-user-consent-dialog/device-user-consent-dialog.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/shared/random-pass-alert/random-pass-alert.component.scss:
--------------------------------------------------------------------------------
1 | a {
2 | color: #fff;
3 | }
4 |
--------------------------------------------------------------------------------
/src/app/shared/add-device/add-device.component.scss:
--------------------------------------------------------------------------------
1 | .mat-mdc-form-field {
2 | margin-top: 12px;
3 | }
4 |
--------------------------------------------------------------------------------
/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/device-management-toolkit/sample-web-ui/HEAD/src/favicon.ico
--------------------------------------------------------------------------------
/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/device-management-toolkit/sample-web-ui/HEAD/src/assets/logo.png
--------------------------------------------------------------------------------
/tsconfig.eslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "include": [
4 | "**/*.ts"
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------
/src/app/devices/event-log/event-log.component.scss:
--------------------------------------------------------------------------------
1 | ::ng-deep .mat-mdc-paginator-range-label {
2 | display: none;
3 | }
4 |
--------------------------------------------------------------------------------
/src/app/devices/audit-log/audit-log.component.scss:
--------------------------------------------------------------------------------
1 | .mat-column-Description {
2 | white-space: pre-line;
3 | padding: 6px 0;
4 | }
5 |
--------------------------------------------------------------------------------
/src/app/devices/device-toolbar/device-toolbar.component.scss:
--------------------------------------------------------------------------------
1 | .pad-15 {
2 | margin-left: 15px;
3 | //margin-inline-start: 15px;
4 | }
5 |
--------------------------------------------------------------------------------
/src/app/core/about/about.component.scss:
--------------------------------------------------------------------------------
1 | label {
2 | padding-right: 10px;
3 | }
4 |
5 | p {
6 | color: black;
7 | }
8 |
9 | h3 {
10 | color: black;
11 | }
12 |
--------------------------------------------------------------------------------
/src/assets/kJEhBvYX7BgnkSrUwT8OhrdQw4oELdPIeeII9v6oFsI.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/device-management-toolkit/sample-web-ui/HEAD/src/assets/kJEhBvYX7BgnkSrUwT8OhrdQw4oELdPIeeII9v6oFsI.woff2
--------------------------------------------------------------------------------
/src/app/devices/sol/sol.component.scss:
--------------------------------------------------------------------------------
1 | @import '@xterm/xterm/css/xterm.css';
2 |
3 | .spinner {
4 | position: absolute;
5 | top: 50%;
6 | left: 50%;
7 | }
8 | .xterm {
9 | text-align: left;
10 | }
11 |
--------------------------------------------------------------------------------
/init.sh:
--------------------------------------------------------------------------------
1 | sed -i \
2 | -e "s|##RPS_SERVER##|$RPS_SERVER|g" \
3 | -e "s|##MPS_SERVER##|$MPS_SERVER|g" \
4 | -e "s|##VAULT_SERVER##|$VAULT_SERVER|g" \
5 | -e "s|##AUTH_MODE_ENABLED##|$AUTH_MODE_ENABLED|g" \
6 | /usr/share/nginx/html/*.js
--------------------------------------------------------------------------------
/src/app/devices/kvm/kvm.component.scss:
--------------------------------------------------------------------------------
1 | .canvas {
2 | background-color: black;
3 | }
4 | .spinner {
5 | position: absolute;
6 | top: 50%;
7 | left: 50%;
8 | }
9 | .stop-ider-button {
10 | margin-inline-start: 8px;
11 | }
12 |
--------------------------------------------------------------------------------
/license-header.js:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
--------------------------------------------------------------------------------
/src/app/core/navbar/navbar.component.scss:
--------------------------------------------------------------------------------
1 | .mdc-list-item--with-leading-icon .mdc-list-item__start {
2 | margin-right: 12px;
3 | }
4 | .mat-mdc-list-item.active {
5 | color: #fff;
6 | background-color: rgba(255, 255, 255, 0.1);
7 | width: calc(100%);
8 | }
9 |
--------------------------------------------------------------------------------
/src/app/shared/dialog-content/dialog-content.component.html:
--------------------------------------------------------------------------------
1 | {{ data.name }}
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | "configurations": [
3 | {
4 | "name": "Docker Node.js Launch",
5 | "type": "docker",
6 | "request": "launch",
7 | "preLaunchTask": "docker-run: debug",
8 | "platform": "node"
9 | }
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/src/app/devices/device-detail/device-detail.component.scss:
--------------------------------------------------------------------------------
1 | .mdc-list-item--with-leading-icon .mdc-list-item__start {
2 | margin-right: 12px;
3 | }
4 |
5 | a.mat-mdc-list-item.active {
6 | color: #fff;
7 | background-color: rgba(0, 0, 0, 0.1);
8 | width: calc(100%);
9 | }
10 |
--------------------------------------------------------------------------------
/.prettierrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | ...require('prettier-config-standard'),
3 | plugins: ['prettier-plugin-multiline-arrays'],
4 | printWidth: 120,
5 | singleAttributePerLine: false,
6 | bracketSameLine: true,
7 | trailingComma: 'none',
8 | multilineArraysWrapThreshold: 2
9 | }
10 |
--------------------------------------------------------------------------------
/src/app/core/toolbar/toolbar.component.scss:
--------------------------------------------------------------------------------
1 | .version {
2 | margin-right: 16px;
3 | }
4 | mat-divider {
5 | height: 30px;
6 | margin-right: 16px;
7 | }
8 |
9 | .lang-scroll {
10 | max-height: 200px;
11 | overflow-y: auto;
12 | }
13 |
14 | .lang-menu {
15 | min-width: 180px;
16 | }
17 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | services:
2 | sample-web-ui:
3 | image: sample-web-ui
4 | build:
5 | context: .
6 | dockerfile: ./Dockerfile
7 | environment:
8 | NODE_ENV: production
9 | ports:
10 | - 8089:80
11 | volumes:
12 | - ./nginx.conf:/etc/nginx/conf.d/default.conf
13 |
--------------------------------------------------------------------------------
/cypress/support/e2e.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | // Import commands.js using ES2015 syntax:
7 | import './commands'
8 |
--------------------------------------------------------------------------------
/cypress/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "noEmit": true,
5 | // be explicit about types included
6 | // to avoid clashing with Jest types
7 | "types": ["cypress"]
8 | },
9 | "include": [
10 | "../node_modules/cypress",
11 | "**/*.ts"
12 | ]
13 | }
14 |
--------------------------------------------------------------------------------
/cypress/e2e/fixtures/formEntry/paging.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | const paging = {
7 | totalCount: 100
8 | }
9 | export { paging }
10 |
--------------------------------------------------------------------------------
/docker-compose.debug.yml:
--------------------------------------------------------------------------------
1 | version: '3.4'
2 |
3 | services:
4 | sample-web-ui:
5 | image: sample-web-ui
6 | build:
7 | context: .
8 | dockerfile: ./Dockerfile
9 | environment:
10 | NODE_ENV: development
11 | ports:
12 | - 80:80
13 | - 9229:9229
14 | command: ["node", "--inspect=0.0.0.0:9229", "index.js"]
15 |
--------------------------------------------------------------------------------
/cypress/e2e/fixtures/formEntry/device.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | const deviceFixtures = {
7 | totalCount: 100
8 | }
9 |
10 | export { deviceFixtures }
11 |
--------------------------------------------------------------------------------
/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/app",
6 | "types": [
7 | "@angular/localize"
8 | ]
9 | },
10 | "files": [
11 | "src/main.ts"
12 | ],
13 | "include": [
14 | "src/**/*.d.ts"
15 | ]
16 | }
17 |
--------------------------------------------------------------------------------
/src/app/devices/devices.component.scss:
--------------------------------------------------------------------------------
1 | .mat-column-actions {
2 | width: 275px;
3 | flex: 0 0 275px;
4 | }
5 | .mat-column-notification {
6 | width: 75px;
7 | flex: 0 0 75px;
8 | }
9 |
10 | mat-icon.addTag {
11 | visibility: hidden;
12 | }
13 |
14 | mat-icon.alwaysHidden {
15 | visibility: hidden;
16 | }
17 |
18 | mat-cell:hover mat-icon.addTag {
19 | visibility: visible;
20 | }
21 |
--------------------------------------------------------------------------------
/src/app/app.component.html:
--------------------------------------------------------------------------------
1 |
2 | @if (isLoggedIn) {
3 |
4 |
5 |
6 | }
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/cypress/e2e/fixtures/formEntry/domain.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | const domainFixtures = {
7 | default: {
8 | profileName: 'happyPath'
9 | }
10 | }
11 |
12 | export { domainFixtures }
13 |
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
1 | **/.classpath
2 | **/.dockerignore
3 | **/.env
4 | **/.git
5 | **/.gitignore
6 | **/.project
7 | **/.settings
8 | **/.toolstarget
9 | **/.vs
10 | **/.vscode
11 | **/*.*proj.user
12 | **/*.dbmdl
13 | **/*.jfm
14 | **/azds.yaml
15 | **/charts
16 | **/docker-compose*
17 | **/Dockerfile*
18 | **/node_modules
19 | **/npm-debug.log
20 | **/obj
21 | **/secrets.dev.yaml
22 | **/values.dev.yaml
23 | README.md
24 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see https://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.html]
12 | indent_size = 2
13 | max_line_length = 240
14 |
15 | [*.ts]
16 | quote_type = single
17 |
18 | [*.md]
19 | max_line_length = off
20 | trim_trailing_whitespace = false
21 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 | # Security Policy
2 |
3 | Intel is committed to rapidly addressing security vulnerabilities affecting our customers and providing clear guidance on the solution, impact, severity and mitigation.
4 |
5 | ## Reporting a Vulnerability
6 |
7 | Please report any security vulnerabilities in this project utilizing the guidelines [here](https://www.intel.com/content/www/us/en/security-center/vulnerability-handling-guidelines.html).
8 |
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Device Management Toolkit
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/spec",
6 | "types": [
7 | "jasmine",
8 | "@angular/localize"
9 | ]
10 | },
11 | "files": [
12 | "src/test.ts"
13 | ],
14 | "include": [
15 | "src/**/*.spec.ts",
16 | "src/**/*.d.ts"
17 | ]
18 | }
19 |
--------------------------------------------------------------------------------
/cypress/e2e/fixtures/api/stats.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | const stats = {
7 | get: {
8 | success: {
9 | response: { totalCount: 10, connectedCount: 5, disconnectedCount: 5 }
10 | }
11 | }
12 | }
13 |
14 | export default stats
15 |
--------------------------------------------------------------------------------
/src/app/devices/device-enable-sol/device-enable-sol.component.html:
--------------------------------------------------------------------------------
1 | {{ 'sol.title.value' | translate }}
2 | {{ 'sol.enable.value' | translate }}
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/cypress/e2e/fixtures/api/httpCodes.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | const httpCodes = {
7 | SUCCESS: 200,
8 | CREATED: 201,
9 | NO_CONTENT: 204,
10 | BAD_REQUEST: 400,
11 | UNAUTHORIZED: 401,
12 | INTERNAL_SERVER_ERROR: 500
13 | }
14 | export { httpCodes }
15 |
--------------------------------------------------------------------------------
/src/app/shared/power-up-alert/power-up-alert.component.html:
--------------------------------------------------------------------------------
1 | {{ 'powerUp.title.value' | translate }}
2 | {{ 'powerUp.message.value' | translate }}
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/src/app/devices/device-enable-kvm/device-enable-kvm.component.html:
--------------------------------------------------------------------------------
1 | {{ 'kvm.title.value' | translate }}
2 | {{ 'kvm.enable.value' | translate }}
3 |
4 |
5 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/.github/copilot-instructions.md:
--------------------------------------------------------------------------------
1 | use Angular 20
2 | Do not use semicolons
3 | use single quotes for typescript
4 | use control flow syntax
5 | use signals if applicable
6 | use reactive forms
7 | don't use deprecated APIs like HttpTestingModule or RouterTestingModule in unit tests
8 | prefer zoneless change detection
9 | use angular material components
10 | use standalone components
11 | Always ensure components and its associated HTML are working
12 | Always ensure unit tests pass 100%
13 | run `npm run lint` when complete
14 |
--------------------------------------------------------------------------------
/src/environments/environment.prod.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | export const environment = {
7 | production: true,
8 | cloud: true,
9 | useOAuth: false, // for use with console
10 | mpsServer: '##MPS_SERVER##',
11 | rpsServer: '##RPS_SERVER##',
12 | vault: '##VAULT_SERVER##',
13 | auth: {}
14 | }
15 |
--------------------------------------------------------------------------------
/nginx.conf:
--------------------------------------------------------------------------------
1 | server {
2 | listen 80 default_server;
3 | listen [::]:80 default_server;
4 | server_name _;
5 |
6 |
7 | location / {
8 | root /usr/share/nginx/html;
9 | index index.html index.htm;
10 | }
11 |
12 | error_page 404 /index.html;
13 |
14 | # redirect server error pages to the static page /50x.html
15 | #
16 | error_page 500 502 503 504 /50x.html;
17 | location = /50x.html {
18 | root /usr/share/nginx/html;
19 | }
20 | }
21 |
22 |
--------------------------------------------------------------------------------
/src/app/shared/are-you-sure/are-you-sure.component.html:
--------------------------------------------------------------------------------
1 | {{ 'delete.question.value' | translate }}
2 | {{ 'delete.questionRecord.value' | translate }}
3 |
4 |
5 |
8 |
9 |
--------------------------------------------------------------------------------
/src/app/shared/pipes/date-formatter.pipe.ts.pipe.ts:
--------------------------------------------------------------------------------
1 | import { Pipe, PipeTransform } from '@angular/core'
2 | import { format, isValid } from 'date-fns'
3 |
4 | @Pipe({
5 | name: 'amDateFormatter'
6 | })
7 | export class AmDateFormatterPipe implements PipeTransform {
8 | transform(date: Date | string | number, useFormat = 'MMMM d, yyyy h:mma'): string {
9 | if (!date) return ''
10 | const parsedDate = new Date(date)
11 | if (!isValid(parsedDate)) return 'Invalid Date'
12 | return format(parsedDate, useFormat)
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/.pre-commit-config.yaml:
--------------------------------------------------------------------------------
1 | repos:
2 | - repo: https://github.com/gitleaks/gitleaks
3 | rev: v8.16.3
4 | hooks:
5 | - id: gitleaks
6 | - repo: https://github.com/jumanjihouse/pre-commit-hooks
7 | rev: 3.0.0
8 | hooks:
9 | - id: shellcheck
10 | - repo: https://github.com/pre-commit/mirrors-eslint
11 | rev: v8.38.0
12 | hooks:
13 | - id: eslint
14 | - repo: https://github.com/pre-commit/pre-commit-hooks
15 | rev: v4.4.0
16 | hooks:
17 | - id: end-of-file-fixer
18 | - id: trailing-whitespace
19 |
--------------------------------------------------------------------------------
/cypress/e2e/fixtures/api/tags.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | const tags = {
7 | getAll: {
8 | success: {
9 | response: [
10 | 'Windows',
11 | 'Linux',
12 | 'NUC',
13 | 'Dell',
14 | 'Store #123',
15 | 'Store #456'
16 | ]
17 | }
18 | }
19 | }
20 |
21 | export { tags }
22 |
--------------------------------------------------------------------------------
/src/app/shared/static-cira-warning/static-cira-warning.component.html:
--------------------------------------------------------------------------------
1 | {{ 'staticCira.title.value' | translate }}
2 | {{ 'staticCira.message.value' | translate }}
3 |
4 |
5 |
8 |
9 |
--------------------------------------------------------------------------------
/src/app/shared/pipes/time-ago-formatter.pipe.ts.pipe.ts:
--------------------------------------------------------------------------------
1 | import { Pipe, PipeTransform } from '@angular/core'
2 | import { formatDistanceToNow, isValid } from 'date-fns'
3 |
4 | @Pipe({
5 | name: 'amTimeAgoFormatter'
6 | })
7 | export class AmTimeAgoFormatterPipe implements PipeTransform {
8 | transform(date: Date | string | number, addSuffix = true): string {
9 | if (!date) return ''
10 | const parsedDate = new Date(date)
11 | if (!isValid(parsedDate)) return 'Invalid Date'
12 | return formatDistanceToNow(parsedDate, { addSuffix: addSuffix })
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/cypress/e2e/fixtures/formEntry/wireless.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | const wirelessFixtures = {
7 | happyPath: {
8 | profileName: 'happyPath',
9 | authenticationMethod: 'WPA2 PSK',
10 | encryptionMethod: 'CCMP',
11 | linkPolicy: [14, 16]
12 | },
13 | wrong: {
14 | profileName: 'wireless config'
15 | }
16 | }
17 |
18 | export { wirelessFixtures }
19 |
--------------------------------------------------------------------------------
/src/constants.ts:
--------------------------------------------------------------------------------
1 | export const availableLangs = [
2 | { code: 'en', label: 'English' },
3 | { code: 'fr', label: 'Français' },
4 | { code: 'de', label: 'Deutsch' },
5 | { code: 'es', label: 'Español' },
6 | { code: 'nl', label: 'Nederlands' },
7 | { code: 'it', label: 'Italiano' },
8 | { code: 'ja', label: '日本語' },
9 | { code: 'ar', label: 'العربية' },
10 | { code: 'fi', label: 'Suomi' },
11 | { code: 'he', label: 'עברית' },
12 | { code: 'ru', label: 'Русский' },
13 | { code: 'sv', label: 'Svenska' }
14 | ]
15 |
16 | export const rtlLangs = [
17 | 'ar',
18 | 'he'
19 | ]
20 |
--------------------------------------------------------------------------------
/src/utils.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | import { Direction } from '@angular/cdk/bidi'
7 | import { rtlLangs } from './constants'
8 |
9 | export const caseInsensitiveCompare = (s1: string, s2: string): number => {
10 | return s1.localeCompare(s2)
11 | }
12 |
13 | export const getDirection = (langCode: string): Direction => {
14 | return rtlLangs.includes(langCode) ? 'rtl' : 'ltr'
15 | }
16 |
--------------------------------------------------------------------------------
/.github/commitlint.config.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | extends: ['@commitlint/config-conventional'],
3 | rules: {
4 | 'body-max-line-length': [2, 'always', 200],
5 | 'subject-case': [
6 | 1,
7 | 'never',
8 | ['sentence-case', 'start-case', 'pascal-case', 'upper-case'],
9 | ],
10 | 'scope-enum': [
11 | 2,
12 | 'always',
13 | ['core', 'dashboard', 'devices', 'domains', 'profiles', '8021x', 'login', 'wireless', 'docker', 'deps', 'deps-dev', 'gh-actions', 'config', 'e2e', 'i18n']
14 | ]
15 | }
16 | }
--------------------------------------------------------------------------------
/cypress/e2e/fixtures/api/general.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | const badRequest = {
7 | response: {
8 | error: 'string',
9 | message: 'string'
10 | }
11 | }
12 | const empty = {
13 | response: {
14 | data: [],
15 | totalCount: 0
16 | }
17 | }
18 | const error = {
19 | response: {
20 | error: 'string',
21 | message: 'string'
22 | }
23 | }
24 | export { badRequest, error, empty }
25 |
--------------------------------------------------------------------------------
/cypress/e2e/fixtures/formEntry/urls.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | const urlFixtures = {
7 | base: 'http://localhost:4200/',
8 |
9 | page: {
10 | login: 'login',
11 | domain: 'domains',
12 | cira: 'ciraconfigs',
13 | profile: 'profiles',
14 | device: 'devices',
15 | wireless: 'wireless',
16 | ieee8021x: 'ieee8021x'
17 | },
18 |
19 | extensions: {
20 | creation: 'new'
21 | }
22 | }
23 | export { urlFixtures }
24 |
--------------------------------------------------------------------------------
/src/styles/css2.css:
--------------------------------------------------------------------------------
1 | /* fallback */
2 | @font-face {
3 | font-family: 'Material Icons';
4 | font-style: normal;
5 | font-weight: 100 700;
6 | src: url(../assets/kJEhBvYX7BgnkSrUwT8OhrdQw4oELdPIeeII9v6oFsI.woff2) format('woff2');
7 | }
8 |
9 | .material-icons {
10 | font-family: 'Material Icons';
11 | font-weight: normal;
12 | font-style: normal;
13 | font-size: 24px;
14 | line-height: 1;
15 | letter-spacing: normal;
16 | text-transform: none;
17 | display: inline-block;
18 | white-space: nowrap;
19 | word-wrap: normal;
20 | direction: ltr;
21 | -webkit-font-feature-settings: 'liga';
22 | -webkit-font-smoothing: antialiased;
23 | }
24 |
--------------------------------------------------------------------------------
/src/styles/_variables.scss:
--------------------------------------------------------------------------------
1 | // Import material theming functions
2 | @use '@angular/material' as mat;
3 |
4 | // Define the palettes for your theme using the Material Design palettes available in palette.scss
5 | // (imported above). For each palette, you can optionally specify a default, lighter, and darker
6 | // hue. Available color palettes: https://material.io/design/color/
7 | $samplewebui-primary: mat.m2-define-palette(mat.$m2-light-blue-palette);
8 | $samplewebui-accent: mat.m2-define-palette(mat.$m2-blue-grey-palette, A200, A100, A400);
9 |
10 | // The warn palette is optional (defaults to red).
11 | $samplewebui-warn: mat.m2-define-palette(mat.$m2-red-palette);
12 |
--------------------------------------------------------------------------------
/src/environments/environment.enterprise.dev.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | export const environment = {
7 | production: false,
8 | cloud: false,
9 | useOAuth: false, // for use with console
10 | mpsServer: 'http://localhost:8181',
11 | rpsServer: 'http://localhost:8181',
12 | vault: '',
13 | auth: {
14 | clientId: '##CLIENTID##',
15 | issuer: '##ISSUER##',
16 | redirectUri: '##REDIRECTURI##',
17 | scope: '##SCOPE##',
18 | responseType: 'code',
19 | requireHttps: false
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ## PR Checklist
2 |
3 |
4 |
5 | - [ ] Unit Tests have been added for new changes
6 | - [ ] API tests have been updated if applicable
7 | - [ ] All commented code has been removed
8 | - [ ] If you've added a dependency, you've ensured license is compatible with Apache 2.0 and clearly outlined the added dependency.
9 |
10 | ## What are you changing?
11 |
12 |
13 |
14 | ## Anything the reviewer should know when reviewing this PR?
15 |
16 | ### If the there are associated PRs in other repositories, please link them here (i.e. device-management-toolkit/repo#365 )
17 |
--------------------------------------------------------------------------------
/.github/workflows/projectsSync.yaml:
--------------------------------------------------------------------------------
1 | name: Adds all issues to project board
2 |
3 | on:
4 | issues:
5 | types:
6 | - opened
7 |
8 | permissions:
9 | contents: read
10 |
11 | jobs:
12 | add-to-project:
13 | name: Add issue to project
14 | runs-on: ubuntu-latest
15 | steps:
16 | - name: Harden Runner
17 | uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
18 | with:
19 | egress-policy: audit
20 |
21 | - uses: actions/add-to-project@244f685bbc3b7adfa8466e08b698b5577571133e # v1.0.2
22 | with:
23 | project-url: https://github.com/orgs/device-management-toolkit/projects/10
24 | github-token: ${{ secrets.PROJECTS_PAT }}
25 |
--------------------------------------------------------------------------------
/src/app/shared/random-pass-alert/random-pass-alert.component.html:
--------------------------------------------------------------------------------
1 | {{ 'randomPassword.title.value' | translate }}
2 |
3 | {{ 'randomPassword.message.value' | translate }}
4 |
5 | {{ 'randomPassword.learnMore.value' | translate }}.
7 |
8 |
9 |
10 |
13 |
14 |
--------------------------------------------------------------------------------
/src/app/shared/pipes/toolkit.pipe.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | import { Pipe, PipeTransform } from '@angular/core'
7 | import { FormOption } from 'src/models/models'
8 |
9 | @Pipe({
10 | name: 'toolkit',
11 | standalone: true
12 | })
13 | export class ToolkitPipe implements PipeTransform {
14 | transform(value: number, ...args: unknown[]): string | null {
15 | const values = args[0] as FormOption[]
16 | const method = values.find((method) => method.value === value)
17 | return method ? method.label : null
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/styles/styles.scss:
--------------------------------------------------------------------------------
1 | html,
2 | body,
3 | mat-drawer-container,
4 | mat-sidenav-container {
5 | margin: 0;
6 | width: 100%;
7 | height: 100%;
8 | overflow: auto; //font-size: 14px;
9 | }
10 | // adjust mat-checkbox to align
11 | // at the top of the label text
12 | // (needed for multiple line labels)
13 | /*TODO(mdc-migration): The following rule targets internal classes of checkbox that may no longer apply for the MDC version.*/
14 | .mat-checkbox-inner-container {
15 | margin-top: 5px !important;
16 | }
17 |
18 | .error-messages-container.mat-mdc-list-item.mdc-list-item--with-leading-icon.mdc-list-item--with-one-line {
19 | height: auto;
20 | padding: 10px 0;
21 | }
22 |
23 | .error-messages.mdc-list-item__primary-text {
24 | white-space: break-spaces;
25 | }
26 |
--------------------------------------------------------------------------------
/src/app/shared/auth-guard.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable, inject } from '@angular/core'
2 | import { AuthService } from '../auth.service'
3 | import { ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router'
4 | import { Observable, tap } from 'rxjs'
5 |
6 | @Injectable()
7 | export class AuthGuard {
8 | private authService = inject(AuthService)
9 | private router = inject(Router)
10 |
11 | // eslint-disable-next-line @typescript-eslint/no-unused-vars
12 | canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable {
13 | return this.authService.canActivateProtectedRoutes$.pipe(
14 | tap((x) => {
15 | if (!x) {
16 | this.router.navigate(['/login'])
17 | }
18 | })
19 | )
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/app/profiles/key-display-dialog/key-display-dialog.component.html:
--------------------------------------------------------------------------------
1 | {{ 'keyDisplayDialog.title.value' | translate }}
2 |
3 |
4 | {{ 'keyDisplayDialog.description.value' | translate }}
5 |
6 | {{ 'keyDisplayDialog.keyLabel.value' | translate }}
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/src/environments/environment.enterprise.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | export const environment = {
7 | production: true,
8 | cloud: false,
9 | useOAuth: false, // for use with console
10 | mpsServer: '##CONSOLE_SERVER_API##',
11 | rpsServer: '##CONSOLE_SERVER_API##',
12 | vault: '##VAULT_SERVER##',
13 | auth: {
14 | clientId: '##CLIENTID##',
15 | issuer: '##ISSUER##',
16 | redirectUri: '##REDIRECTURI##',
17 | scope: '##SCOPE##',
18 | responseType: 'code',
19 | requireHttps: true, // set to false when local
20 | strictDiscoveryDocumentValidation: true
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/cypress/e2e/integration/eventchannellogs/get.spec.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | describe('Test eventchannellogs', () => {
7 | beforeEach('', () => {
8 | cy.setup()
9 | })
10 |
11 | // it('check default values', () => {
12 | // cy.goToPage('MQTT Events')
13 | // cy.get('input[name="hostname"]').invoke('val').should('eq', 'localhost')
14 | // cy.get('input[name="path"]').invoke('val').should('eq', '/mosquitto/mqtt')
15 | // })
16 |
17 | // it('load all the eventchannelogs', () => {
18 | // cy.goToPage('MQTT Events')
19 | // cy.get('h3').should('have.text', 'No Events')
20 | // })
21 | })
22 |
--------------------------------------------------------------------------------
/cypress/e2e/fixtures/formEntry/eventlogs.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | const eventLogFixtures = {
7 | happyPath: {
8 | DeviceAddress: 255,
9 | EventSensorType: 15,
10 | EventType: 'Sensor specific event',
11 | EventOffset: 2,
12 | EventSourceType: 104,
13 | EventSeverity: 8,
14 | SensorNumber: 255,
15 | Entity: 34,
16 | EntityInstance: 0,
17 | EventData: [
18 | 64,
19 | 19,
20 | 0,
21 | 0,
22 | 0,
23 | 0,
24 | 0,
25 | 0
26 | ],
27 | Time: '2021-09-08T16:31:02.000Z',
28 | EntityStr: 'BIOS',
29 | Desc: 'Starting operating system boot process'
30 | }
31 | }
32 | export { eventLogFixtures }
33 |
--------------------------------------------------------------------------------
/cypress/e2e/fixtures/formEntry/auditLogs.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | const auditLogFixtures = {
7 | happyPath: {
8 | totalCnt: 1,
9 | records: [
10 | {
11 | AuditAppID: 16,
12 | EventID: 11,
13 | InitiatorType: 0,
14 | AuditApp: 'Security Admin',
15 | Event: 'KVM enabled',
16 | Initiator: 'admin',
17 | Time: '2021-09-08T16:31:02.000Z',
18 | MCLocationType: 0,
19 | NetAddress: '127.0.0.1',
20 | Ex: '\u0004`g\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000',
21 | ExStr: null
22 | }
23 | ]
24 | }
25 | }
26 | export { auditLogFixtures as eventLogFixtures }
27 |
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0.0",
3 | "tasks": [
4 | {
5 | "type": "docker-build",
6 | "label": "docker-build",
7 | "platform": "node",
8 | "dockerBuild": {
9 | "dockerfile": "${workspaceFolder}/Dockerfile",
10 | "context": "${workspaceFolder}",
11 | "pull": true
12 | }
13 | },
14 | {
15 | "type": "docker-run",
16 | "label": "docker-run: release",
17 | "dependsOn": [
18 | "docker-build"
19 | ],
20 | "platform": "node"
21 | },
22 | {
23 | "type": "docker-run",
24 | "label": "docker-run: debug",
25 | "dependsOn": [
26 | "docker-build"
27 | ],
28 | "dockerRun": {
29 | "env": {
30 | "DEBUG": "*",
31 | "NODE_ENV": "development"
32 | }
33 | },
34 | "node": {
35 | "enableDebugging": true
36 | }
37 | }
38 | ]
39 | }
40 |
--------------------------------------------------------------------------------
/src/app/wireless/wireless.constants.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | import { FormOption } from '../../models/models'
7 |
8 | // https://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide/HTMLDocuments/WS-Management_Class_Reference/CIM_WiFiEndpointSettings.htm
9 |
10 | export const AuthenticationMethods: FormOption[] = [
11 | { value: 4, mode: 'PSK', label: 'WPA PSK' },
12 | { value: 5, mode: '802.1x', label: 'WPA IEEE 802.1x' },
13 | { value: 6, mode: 'PSK', label: 'WPA2 PSK' },
14 | { value: 7, mode: '802.1x', label: 'WPA2 IEEE 802.1x' }
15 | ]
16 |
17 | export const EncryptionMethods: FormOption[] = [
18 | { value: 3, label: 'TKIP' },
19 | { value: 4, label: 'CCMP' }
20 | ]
21 |
--------------------------------------------------------------------------------
/src/app/dashboard/dashboard.component.scss:
--------------------------------------------------------------------------------
1 | @use '@angular/material' as mat;
2 | @use 'src/styles/_variables.scss' as vars;
3 |
4 | h1,
5 | .mat-headline-4,
6 | .mat-headline-3 {
7 | margin-bottom: 12px;
8 | padding-bottom: 0;
9 | }
10 |
11 | .mat-headline-2 {
12 | margin: 12px;
13 | }
14 |
15 | .mat-icon {
16 | font-size: 48px;
17 | height: 48px;
18 | line-height: 1;
19 | width: 48px;
20 | color: mat.m2-get-color-from-palette(vars.$samplewebui-primary, A200);
21 | }
22 |
23 | .mat-mdc-icon-button {
24 | width: 100px;
25 | height: 100px;
26 | border: 2px solid mat.m2-get-color-from-palette(vars.$samplewebui-accent, A100);
27 | }
28 |
29 | .mat-mdc-card {
30 | background-color: mat.m2-get-color-from-palette(vars.$samplewebui-accent, A100);
31 | }
32 |
33 | mat-divider {
34 | margin: 24px 0;
35 | }
36 |
37 | h3 {
38 | margin-top: 24px;
39 | text-align: center;
40 | }
41 |
42 | .pointer {
43 | cursor: pointer;
44 | }
45 |
--------------------------------------------------------------------------------
/src/test.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files
7 |
8 | import { NgModule, provideZonelessChangeDetection } from '@angular/core'
9 | import { getTestBed } from '@angular/core/testing'
10 | import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing'
11 | @NgModule({
12 | providers: [provideZonelessChangeDetection()]
13 | })
14 | export class ZonelessTestModule {}
15 | // First, initialize the Angular testing environment.
16 | getTestBed().initTestEnvironment([BrowserDynamicTestingModule, ZonelessTestModule], platformBrowserDynamicTesting(), {
17 | teardown: { destroyAfterEach: false }
18 | })
19 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | #*********************************************************************
2 | # Copyright (c) Intel Corporation 2021
3 | # SPDX-License-Identifier: Apache-2.0
4 | #*********************************************************************/
5 | ### STAGE 1: Build ###
6 | FROM node:25-bullseye-slim@sha256:7e6104f4086bd04c44bd62f6b7469422865c19342ab1073ddf9de0936d43f207 AS build
7 | WORKDIR /usr/src/app
8 | COPY package.json package-lock.json ./
9 | RUN npm ci
10 | COPY . .
11 | RUN npm run build -- --configuration=production
12 |
13 | ### STAGE 2: Run ###
14 | FROM nginx:mainline-alpine-slim@sha256:a5459dbb9ed17c9f1eff5448a5dfb22ea3eb386a356e26fc16871dc426ac5383
15 |
16 | LABEL license='SPDX-License-Identifier: Apache-2.0' \
17 | copyright='Copyright (c) 2021: Intel'
18 |
19 | RUN apk update && apk upgrade --no-cache
20 |
21 | COPY --from=build /usr/src/app/dist/samplewebui/browser /usr/share/nginx/html
22 | COPY --from=build /usr/src/app/init.sh /docker-entrypoint.d/init.sh
23 | EXPOSE 80
--------------------------------------------------------------------------------
/cypress/e2e/fixtures/api/networkConfig.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | const networkConfigs = {
7 | getAll: {
8 | success: {
9 | response: [
10 | {
11 | profileName: 'happyPath',
12 | dhcpEnabled: true
13 | }
14 | ]
15 | }
16 | },
17 | create: {
18 | success: {
19 | response: {
20 | profileName: 'profile6',
21 | dhcpEnabled: true
22 | }
23 | }
24 | },
25 | update: {
26 | success: {
27 | response: {
28 | profileName: 'profile6',
29 | dhcpEnabled: true
30 | }
31 | }
32 | },
33 | get: {
34 | success: {
35 | response: {
36 | profileName: 'profile6',
37 | dhcpEnabled: true
38 | }
39 | }
40 | }
41 | }
42 |
43 | export { networkConfigs }
44 |
--------------------------------------------------------------------------------
/src/app/shared/are-you-sure/are-you-sure.component.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | import { Component } from '@angular/core'
7 | import { MatButton } from '@angular/material/button'
8 | import { CdkScrollable } from '@angular/cdk/scrolling'
9 | import { MatDialogTitle, MatDialogContent, MatDialogActions, MatDialogClose } from '@angular/material/dialog'
10 | import { TranslateModule } from '@ngx-translate/core'
11 | @Component({
12 | selector: 'app-are-you-sure',
13 | templateUrl: './are-you-sure.component.html',
14 | styleUrls: ['./are-you-sure.component.scss'],
15 | imports: [
16 | MatDialogTitle,
17 | CdkScrollable,
18 | MatDialogContent,
19 | MatDialogActions,
20 | MatButton,
21 | MatDialogClose,
22 | TranslateModule
23 | ]
24 | })
25 | export class AreYouSureDialogComponent {}
26 |
--------------------------------------------------------------------------------
/src/app/shared/power-up-alert/power-up-alert.component.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | import { Component } from '@angular/core'
7 | import { MatButton } from '@angular/material/button'
8 | import { CdkScrollable } from '@angular/cdk/scrolling'
9 | import { MatDialogTitle, MatDialogContent, MatDialogActions, MatDialogClose } from '@angular/material/dialog'
10 | import { TranslateModule } from '@ngx-translate/core'
11 |
12 | @Component({
13 | selector: 'app-power-up-alert',
14 | templateUrl: './power-up-alert.component.html',
15 | styleUrls: ['./power-up-alert.component.scss'],
16 | imports: [
17 | MatDialogTitle,
18 | CdkScrollable,
19 | MatDialogContent,
20 | MatDialogActions,
21 | MatButton,
22 | TranslateModule,
23 | MatDialogClose
24 | ]
25 | })
26 | export class PowerUpAlertComponent {}
27 |
--------------------------------------------------------------------------------
/src/app/shared/random-pass-alert/random-pass-alert.component.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | import { Component } from '@angular/core'
7 | import { MatButton } from '@angular/material/button'
8 | import { CdkScrollable } from '@angular/cdk/scrolling'
9 | import { MatDialogTitle, MatDialogContent, MatDialogActions, MatDialogClose } from '@angular/material/dialog'
10 | import { TranslateModule } from '@ngx-translate/core'
11 |
12 | @Component({
13 | selector: 'app-random-pass-alert',
14 | templateUrl: './random-pass-alert.component.html',
15 | styleUrls: ['./random-pass-alert.component.scss'],
16 | imports: [
17 | MatDialogTitle,
18 | CdkScrollable,
19 | MatDialogContent,
20 | MatDialogActions,
21 | MatButton,
22 | TranslateModule,
23 | MatDialogClose
24 | ]
25 | })
26 | export class RandomPassAlertComponent {}
27 |
--------------------------------------------------------------------------------
/src/app/shared/dialog-content/dialog-content.component.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | import { Component, inject } from '@angular/core'
7 | import { MAT_DIALOG_DATA, MatDialogContent, MatDialogActions, MatDialogClose } from '@angular/material/dialog'
8 | import { MatButton } from '@angular/material/button'
9 | import { CdkScrollable } from '@angular/cdk/scrolling'
10 | import { TranslateModule } from '@ngx-translate/core'
11 |
12 | @Component({
13 | selector: 'app-dialog-content',
14 | templateUrl: './dialog-content.component.html',
15 | styleUrls: ['./dialog-content.component.scss'],
16 | imports: [
17 | CdkScrollable,
18 | MatDialogContent,
19 | MatDialogActions,
20 | MatButton,
21 | TranslateModule,
22 | MatDialogClose
23 | ]
24 | })
25 | export class DialogContentComponent {
26 | data = inject(MAT_DIALOG_DATA)
27 | }
28 |
--------------------------------------------------------------------------------
/src/app/shared/static-cira-warning/static-cira-warning.component.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | import { Component } from '@angular/core'
7 | import { MatButton } from '@angular/material/button'
8 | import { CdkScrollable } from '@angular/cdk/scrolling'
9 | import { MatDialogTitle, MatDialogContent, MatDialogActions, MatDialogClose } from '@angular/material/dialog'
10 | import { TranslateModule } from '@ngx-translate/core'
11 |
12 | @Component({
13 | selector: 'app-static-cira-warning',
14 | templateUrl: './static-cira-warning.component.html',
15 | styleUrls: ['./static-cira-warning.component.scss'],
16 | imports: [
17 | MatDialogTitle,
18 | CdkScrollable,
19 | MatDialogContent,
20 | MatDialogActions,
21 | MatButton,
22 | TranslateModule,
23 | MatDialogClose
24 | ]
25 | })
26 | export class StaticCIRAWarningComponent {}
27 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | cy:
2 | @read -r -p "Isolate the front end? (y/n): " isolate;\
3 | read -r -p "Enter the target url: " targetUrl;\
4 | npm run cypress -- --env ISOLATED=$$isolate,BASEURL=$$targetUrl
5 |
6 | runner:
7 | @read -r -p "Isolate the front end? (y/n): " isolate;\
8 | read -r -p "Enter the target url: " targetUrl;\
9 | npm run cy-runner -- --env ISOLATED=$$isolate,BASEURL=$$targetUrl
10 |
11 | # container:
12 | # docker run -d -p 4200:80 vprodemo.azurecr.ui/samplewebui:latest
13 |
14 | # test-container:
15 | # docker run -d -p 4201:80 vprodemo.azurecr.ui/samplewebui:latest
16 |
17 | #npm run start
18 |
19 | e2e-runner:
20 | #prep
21 | npx cypress run --spec "cypress/integration/login/*"
22 | #create
23 | npx cypress run --spec "cypress/integration/cira/create.*"
24 | npx cypress run --spec "cypress/integration/profile/create.*"
25 | #test
26 | npx cypress run --spec "cypress/integration/**/create-error.*,cypress/integration/domain/* "
27 | #delete
28 | npx cypress run --spec "cypress/integration/profile/delete.*"
29 | npx cypress run --spec "cypress/integration/cira/delete.*"
30 |
--------------------------------------------------------------------------------
/.releaserc.json:
--------------------------------------------------------------------------------
1 | {
2 | "branches": [
3 | "main",
4 | "next"
5 | ],
6 | "plugins": [
7 | [
8 | "@semantic-release/commit-analyzer",
9 | {
10 | "releaseRules": [
11 | {
12 | "type": "chore",
13 | "release": "patch"
14 | }
15 | ]
16 | }
17 | ],
18 | "@semantic-release/changelog",
19 | [
20 | "@semantic-release/npm",
21 | {
22 | "npmPublish": false
23 | }
24 | ],
25 | "@semantic-release/release-notes-generator",
26 | "@semantic-release/github",
27 | [
28 | "@semantic-release/exec",
29 | {
30 | "publishCmd": "docker buildx build --platform linux/amd64,linux/arm64 --push -t vprodemo.azurecr.io/webui:v${nextRelease.version} -t vprodemo.azurecr.io/webui:latest -t docker.io/intel/oact-webui:v${nextRelease.version} -t docker.io/intel/oact-webui:latest -t docker.io/intel/device-mgmt-toolkit-web-ui:v${nextRelease.version} -t docker.io/intel/device-mgmt-toolkit-web-ui:latest ."
31 | }
32 | ],
33 | "@semantic-release/git"
34 | ]
35 | }
36 |
--------------------------------------------------------------------------------
/.github/workflows/semantic.yml:
--------------------------------------------------------------------------------
1 | name: "Semantic Pull Request"
2 |
3 | on:
4 | pull_request:
5 | types: ["opened", "edited", "reopened", "synchronize"]
6 |
7 | permissions:
8 | contents: read
9 |
10 | jobs:
11 | main:
12 | name: Validate PR and Commits
13 | runs-on: ubuntu-latest
14 | steps:
15 | - name: Harden Runner
16 | uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
17 | with:
18 | egress-policy: audit
19 |
20 | - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
21 | with:
22 | fetch-depth: 0
23 | - uses: wagoid/commitlint-github-action@b948419dd99f3fd78a6548d48f94e3df7f6bf3ed # v6.2.1
24 | with:
25 | configFile: .github/commitlint.config.cjs
26 | - name: Install Dependencies
27 | run: npm install @commitlint/config-conventional@18.5
28 | - uses: JulienKode/pull-request-name-linter-action@4fb4c2773193ad7ae5fe105c98ab30778abb1536 # v20.1.0
29 | with:
30 | configuration-path: ./.github/commitlint.config.cjs
31 |
--------------------------------------------------------------------------------
/cypress/e2e/integration/dashboard/devicecount.spec.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | import { httpCodes } from 'cypress/e2e/fixtures/api/httpCodes'
7 |
8 | describe('Dashboard Test', () => {
9 | beforeEach(() => {
10 | cy.setup()
11 | })
12 |
13 | it('shows stats on dashboard', () => {
14 | cy.wait('@stats-request').then((response) => {
15 | if (response.response) {
16 | expect(response.response.statusCode).to.eq(httpCodes.SUCCESS)
17 | const totalCount = response.response.body.totalCount
18 | const connectedCount = response.response.body.connectedCount
19 | cy.get('[data-cy="totalCount"]').should('have.text', totalCount)
20 | cy.get('[data-cy="connectedCount"]').should('have.text', connectedCount)
21 | cy.get('[data-cy="disconnectedCount"]').should('have.text', totalCount - connectedCount)
22 | }
23 | })
24 | })
25 | })
26 |
--------------------------------------------------------------------------------
/.github/workflows/dependency-review.yml:
--------------------------------------------------------------------------------
1 | # Dependency Review Action
2 | #
3 | # This Action will scan dependency manifest files that change as part of a Pull Request,
4 | # surfacing known-vulnerable versions of the packages declared or updated in the PR.
5 | # Once installed, if the workflow run is marked as required,
6 | # PRs introducing known-vulnerable packages will be blocked from merging.
7 | #
8 | # Source repository: https://github.com/actions/dependency-review-action
9 | name: 'Dependency Review'
10 | on: [pull_request]
11 |
12 | permissions:
13 | contents: read
14 |
15 | jobs:
16 | dependency-review:
17 | runs-on: ubuntu-latest
18 | steps:
19 | - name: Harden Runner
20 | uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
21 | with:
22 | egress-policy: audit
23 |
24 | - name: 'Checkout Repository'
25 | uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
26 | - name: 'Dependency Review'
27 | uses: actions/dependency-review-action@3c4e3dcb1aa7874d2c16be7d79418e9b7efd6261 # v4.8.2
28 |
--------------------------------------------------------------------------------
/src/app/devices/device-enable-kvm/device-enable-kvm.component.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | import { Component, inject } from '@angular/core'
7 | import {
8 | MatDialogRef,
9 | MatDialogTitle,
10 | MatDialogActions,
11 | MatDialogClose,
12 | MatDialogContent
13 | } from '@angular/material/dialog'
14 | import { MatButton } from '@angular/material/button'
15 | import { TranslateModule } from '@ngx-translate/core'
16 |
17 | @Component({
18 | selector: 'app-device-enable-kvm',
19 | templateUrl: './device-enable-kvm.component.html',
20 | styleUrls: ['./device-enable-kvm.component.scss'],
21 | imports: [
22 | MatDialogTitle,
23 | MatDialogContent,
24 | MatDialogActions,
25 | MatButton,
26 | TranslateModule,
27 | MatDialogClose
28 | ]
29 | })
30 | export class DeviceEnableKvmComponent {
31 | dialogRef = inject>(MatDialogRef)
32 | }
33 |
--------------------------------------------------------------------------------
/src/app/devices/device-enable-sol/device-enable-sol.component.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | import { Component, inject } from '@angular/core'
7 | import { MatDialogRef, MatDialogTitle, MatDialogActions, MatDialogClose } from '@angular/material/dialog'
8 | import { MatButton } from '@angular/material/button'
9 | import { MatCardContent } from '@angular/material/card'
10 | import { TranslateModule } from '@ngx-translate/core'
11 |
12 | @Component({
13 | selector: 'app-device-enable-sol',
14 | templateUrl: './device-enable-sol.component.html',
15 | styleUrls: ['./device-enable-sol.component.scss'],
16 | imports: [
17 | MatDialogTitle,
18 | MatCardContent,
19 | MatDialogActions,
20 | MatButton,
21 | TranslateModule,
22 | MatDialogClose
23 | ]
24 | })
25 | export class DeviceEnableSolComponent {
26 | dialogRef = inject>(MatDialogRef)
27 | }
28 |
--------------------------------------------------------------------------------
/.devcontainer/devcontainer.json:
--------------------------------------------------------------------------------
1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the
2 | // README at: https://github.com/devcontainers/templates/tree/main/src/go
3 | {
4 | "name": "Node",
5 | // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
6 | "image": "mcr.microsoft.com/devcontainers/typescript-node:22-bullseye",
7 | // Features to add to the dev container. More info: https://containers.dev/features.
8 | // "features": {},
9 | // Use 'forwardPorts' to make a list of ports inside the container available locally.
10 | "forwardPorts": [
11 | 4200
12 | ],
13 | "portsAttributes": {
14 | "4200": {
15 | "label": "Angular Dev Server",
16 | "onAutoForward": "notify"
17 | }
18 | },
19 | // Use 'postCreateCommand' to run commands after the container is created.
20 | "postCreateCommand": "npm install"
21 | // Configure tool-specific properties.
22 | // "customizations": {},
23 | // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
24 | // "remoteUser": "root"
25 | }
26 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "compileOnSave": false,
4 | "compilerOptions": {
5 | "baseUrl": "./",
6 | "outDir": "./dist/out-tsc",
7 | "forceConsistentCasingInFileNames": true,
8 | "esModuleInterop": true,
9 | "strict": true,
10 | "strictBindCallApply": true,
11 | "noImplicitReturns": true,
12 | "noFallthroughCasesInSwitch": true,
13 | "noImplicitAny": true,
14 | "sourceMap": false,
15 | "declaration": false,
16 | "experimentalDecorators": true,
17 | "moduleResolution": "bundler",
18 | "importHelpers": true,
19 | "target": "ES2022",
20 | "module": "es2020",
21 | "lib": [
22 | "es2022",
23 | "dom"
24 | ],
25 | "useDefineForClassFields": false,
26 | "types": [
27 | "jasmine",
28 | "@angular/localize"
29 | ]
30 | },
31 | "angularCompilerOptions": {
32 | "strictInjectionParameters": true,
33 | "strictInputAccessModifiers": true,
34 | "strictTemplates": true,
35 | "strictMetadataEmit": true
36 | },
37 | "include": [
38 | "src"
39 | ]
40 | }
41 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # compiled output
4 | /dist
5 | /ui
6 | /tmp
7 | /out-tsc
8 | *.exe
9 | # Only exists if Bazel was run
10 | /bazel-out
11 |
12 | # dependencies
13 | /node_modules
14 |
15 | # profiling files
16 | chrome-profiler-events*.json
17 | speed-measure-plugin*.json
18 |
19 | # IDEs and editors
20 | /.idea
21 | .project
22 | .classpath
23 | .c9/
24 | *.launch
25 | .settings/
26 | *.sublime-workspace
27 |
28 | # IDE - VSCode
29 | .vscode/*
30 | !.vscode/settings.json
31 | !.vscode/tasks.json
32 | !.vscode/launch.json
33 | !.vscode/extensions.json
34 | .history/*
35 |
36 | # misc
37 | /.angular/cache
38 | /.sass-cache
39 | /connect.lock
40 | /coverage
41 | /libpeerconnection.log
42 | npm-debug.log
43 | yarn-error.log
44 | testem.log
45 | /typings
46 | *.mp4
47 | *.png
48 | *.log
49 | !src/assets/*
50 |
51 | # env file to override CI/CD environment variables
52 | # for cypress tests in dev/local environment
53 | cypress.env.*
54 | cypress.config.dev.ts
55 | cypress-ui-test-output*
56 |
57 | TESTS-*
58 | # System Files
59 | .DS_Store
60 | Thumbs.db
61 | update-angular.sh
62 |
--------------------------------------------------------------------------------
/src/app/authorize.interceptor.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | import { inject } from '@angular/core'
7 | import { HttpInterceptorFn } from '@angular/common/http'
8 | import { AuthService } from './auth.service'
9 |
10 | export const authorizationInterceptor: HttpInterceptorFn = (request, next) => {
11 | const authService = inject(AuthService)
12 |
13 | if (request.url.toString().includes('/authorize') && !request.url.toString().includes('/authorize/redirection')) {
14 | // Skip adding authorization headers for specific routes
15 | return next(request)
16 | }
17 |
18 | const headers: any = {
19 | Authorization: `Bearer ${authService.getLoggedUserToken()}`
20 | }
21 |
22 | if ((request.body as any)?.version != null && (request.body as any)?.version !== '') {
23 | headers['if-match'] = (request.body as any).version
24 | }
25 |
26 | request = request.clone({
27 | setHeaders: headers
28 | })
29 |
30 | return next(request)
31 | }
32 |
--------------------------------------------------------------------------------
/src/app/devices/device-user-consent-dialog/device-user-consent-dialog.component.html:
--------------------------------------------------------------------------------
1 | {{ 'deviceUserConsent.title.value' | translate }}
2 |
27 |
--------------------------------------------------------------------------------
/src/app/devices/sol/sol.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | @if (deviceState() === 0 && isLoading() !== false) {
5 |
8 | } @else if (deviceState() !== 2 && isLoading()) {
9 |
12 | } @else {
13 |
16 | }
17 |
18 |
19 | @if (readyToLoadSol) {
20 |
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/cypress/e2e/fixtures/api/ieee8021x.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | import { wiredConfigs, wirelessConfigs } from '../formEntry/ieee8021x'
7 |
8 | export const wiredConfigsResponse = {
9 | data: wiredConfigs,
10 | totalCount: wiredConfigs.length
11 | }
12 |
13 | export const wirelessConfigsResponse = {
14 | data: wirelessConfigs,
15 | totalCount: wirelessConfigs.length
16 | }
17 |
18 | export const noConfigsResponse = {
19 | data: [],
20 | totalCount: 0
21 | }
22 |
23 | export function interceptGetAll(statusCode: number, body: any): Cypress.Chainable {
24 | return cy.myIntercept('GET', 'ieee8021xconfigs?*$count=true', { statusCode, body })
25 | }
26 |
27 | export function interceptPost(statusCode: number, body: any): Cypress.Chainable {
28 | return cy.myIntercept('POST', 'ieee8021xconfigs', { statusCode, body })
29 | }
30 |
31 | export function interceptDelete(statusCode: number, body: any): Cypress.Chainable {
32 | return cy.myIntercept('DELETE', /.*ieee8021x.*/, { statusCode, body })
33 | }
34 |
--------------------------------------------------------------------------------
/cypress/e2e/integration/domain/exipiration.spec.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | import { domains } from 'cypress/e2e/fixtures/api/domain'
7 | import { httpCodes } from 'cypress/e2e/fixtures/api/httpCodes'
8 |
9 | // ---------------------------- Test section ----------------------------
10 |
11 | describe('Test Domain Page', () => {
12 | beforeEach('before', () => {
13 | cy.setup()
14 | })
15 |
16 | it('checks the expiration date ui functionality', () => {
17 | cy.myIntercept('GET', 'domains?$top=25&$skip=0&$count=true', {
18 | statusCode: httpCodes.SUCCESS,
19 | body: domains.getThree.success.response
20 | }).as('get-domains')
21 |
22 | cy.goToPage('Domains')
23 | cy.wait('@get-domains')
24 |
25 | for (let i = 0; i < 3; i++) {
26 | cy.get('mat-cell').contains(domains.getThree.success.response.data[i].profileName)
27 | cy.get('mat-cell').contains(domains.getThree.success.response.data[i].domainSuffix)
28 | }
29 |
30 | cy.get('simple-snack-bar').contains('expired').should('exist')
31 | })
32 | })
33 |
--------------------------------------------------------------------------------
/src/app/profiles/key-display-dialog/key-display-dialog.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { ComponentFixture, TestBed } from '@angular/core/testing'
2 |
3 | import { KeyDisplayDialogComponent } from './key-display-dialog.component'
4 | import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog'
5 | import { provideNoopAnimations } from '@angular/platform-browser/animations'
6 | import { TranslateModule } from '@ngx-translate/core'
7 |
8 | describe('KeyDisplayDialogComponent', () => {
9 | let component: KeyDisplayDialogComponent
10 | let fixture: ComponentFixture
11 |
12 | beforeEach(() => {
13 | TestBed.configureTestingModule({
14 | providers: [
15 | provideNoopAnimations(),
16 | {
17 | provide: MAT_DIALOG_DATA,
18 | useValue: { key: 'test' }
19 | }
20 | ],
21 | imports: [
22 | KeyDisplayDialogComponent,
23 | MatDialogModule,
24 | TranslateModule.forRoot()
25 | ]
26 | })
27 |
28 | fixture = TestBed.createComponent(KeyDisplayDialogComponent)
29 | component = fixture.componentInstance
30 | fixture.detectChanges()
31 | })
32 |
33 | it('should create', () => {
34 | expect(component).toBeTruthy()
35 | })
36 | })
37 |
--------------------------------------------------------------------------------
/src/app/profiles/key-display-dialog/key-display-dialog.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, inject } from '@angular/core'
2 | import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog'
3 | import { MatFormFieldModule } from '@angular/material/form-field'
4 | import { Clipboard, ClipboardModule } from '@angular/cdk/clipboard'
5 | import { MatInputModule } from '@angular/material/input'
6 | import { MatButtonModule } from '@angular/material/button'
7 | import { MatIconModule } from '@angular/material/icon'
8 | import { TranslateModule } from '@ngx-translate/core'
9 |
10 | @Component({
11 | selector: 'app-key-display-dialog',
12 | imports: [
13 | MatDialogModule,
14 | MatFormFieldModule,
15 | MatInputModule,
16 | MatButtonModule,
17 | ClipboardModule,
18 | MatIconModule,
19 | TranslateModule
20 | ],
21 | templateUrl: './key-display-dialog.component.html',
22 | styleUrl: './key-display-dialog.component.scss'
23 | })
24 | export class KeyDisplayDialogComponent {
25 | private readonly data = inject(MAT_DIALOG_DATA)
26 | private readonly clipboard = inject(Clipboard)
27 |
28 | public key = ''
29 |
30 | constructor() {
31 | const data = this.data
32 | this.key = data.key
33 | }
34 |
35 | copyKey() {
36 | this.clipboard.copy(this.key)
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
6 |
7 | **Describe the bug** 🪲
8 | A clear and concise description of what the bug is.
9 |
10 | **To Reproduce** 🪜
11 | Steps to reproduce the behavior:
12 |
13 | 1. Go to '...'
14 | 2. Click on '....'
15 | 3. Scroll down to '....'
16 | 4. See error
17 |
18 | **Expected behavior**
19 | A clear and concise description of what you expected to happen.
20 |
21 | **Screenshots** 🖼️
22 | If applicable, add screenshots to help explain your problem.
23 |
24 | **Browser Information (please complete the following information):** 🖥️
25 |
26 | - OS: [e.g. Windows 10 build 21H1, Ubuntu 20.04 LTS]
27 | - Browser and Version: [e.g. IE Edge 95.0.1020.40 ]
28 |
29 | **Server Side Deployment (please complete the following information):** ⛈️
30 |
31 | - Deployment Type: [e.g. Azure, Docker, K8s]
32 | - Node Version: [e.g. LTS 14]
33 | - Component & Version: [e.g. RPS 2.0.0]
34 |
35 | **Additional context**
36 | Add any other context about the problem here.
37 |
--------------------------------------------------------------------------------
/src/app/shared/config/snackBarDefault.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | import { MatSnackBarConfig } from '@angular/material/snack-bar'
7 |
8 | interface SnackbarConfigs {
9 | defaultWarn: MatSnackBarConfig
10 | defaultError: MatSnackBarConfig
11 | longError: MatSnackBarConfig
12 | quickError: MatSnackBarConfig
13 | defaultSuccess: MatSnackBarConfig
14 | longSuccess: MatSnackBarConfig
15 | quickSuccess: MatSnackBarConfig
16 | }
17 | const SnackbarDefaults: SnackbarConfigs = {
18 | defaultWarn: { duration: 3000, panelClass: ['warn', 'mat-elevation-z12'] },
19 | defaultError: { duration: 3000, panelClass: ['error', 'mat-elevation-z12'] },
20 | longError: { duration: 10000, panelClass: ['error', 'mat-elevation-z12'] },
21 | quickError: { duration: 1000, panelClass: ['error', 'mat-elevation-z12'] },
22 | defaultSuccess: { duration: 3000, panelClass: ['success', 'mat-elevation-z12'] },
23 | longSuccess: { duration: 10000, panelClass: ['success', 'mat-elevation-z12'] },
24 | quickSuccess: { duration: 1000, panelClass: ['success', 'mat-elevation-z12'] }
25 | }
26 |
27 | export default SnackbarDefaults
28 |
--------------------------------------------------------------------------------
/cypress/e2e/integration/login/ensureEmpty.spec.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | // Tests the login page with a multitude of fake accounts in
7 | // Checks to make sure that there are no domains, cira configs, or profiles present
8 | // This ensures that the e2e flow is in the proper state before beginning
9 |
10 | describe('Ensure the server is empty', () => {
11 | beforeEach('before', () => {
12 | cy.setup()
13 | })
14 |
15 | it('checks for domains', () => {
16 | if (Cypress.env('ISOLATE').charAt(0).toLowerCase() === 'n') {
17 | cy.goToPage('Domains')
18 | cy.contains('No Domains').should('be.visible')
19 | }
20 | })
21 |
22 | it('checks for cira configs', () => {
23 | if (Cypress.env('ISOLATE').charAt(0).toLowerCase() === 'n') {
24 | cy.goToPage('CIRA Configs')
25 | cy.contains('No CIRA Configs').should('be.visible')
26 | }
27 | })
28 |
29 | it('checks for profiles', () => {
30 | if (Cypress.env('ISOLATE').charAt(0).toLowerCase() === 'n') {
31 | cy.goToPage('Profiles')
32 | cy.contains('No Profiles').should('be.visible')
33 | }
34 | })
35 | })
36 |
--------------------------------------------------------------------------------
/src/app/shared/random-pass-alert/random-pass-alert.component.spec.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | import { ComponentFixture, TestBed } from '@angular/core/testing'
7 | import { MatDialogModule } from '@angular/material/dialog'
8 |
9 | import { RandomPassAlertComponent } from './random-pass-alert.component'
10 | import { TranslateModule } from '@ngx-translate/core'
11 |
12 | describe('RandomPassAlertComponent', () => {
13 | let component: RandomPassAlertComponent
14 | let fixture: ComponentFixture
15 |
16 | beforeEach(() => {
17 | TestBed.configureTestingModule({
18 | imports: [
19 | MatDialogModule,
20 | RandomPassAlertComponent,
21 | TranslateModule.forRoot()
22 | ]
23 | })
24 | })
25 |
26 | beforeEach(() => {
27 | fixture = TestBed.createComponent(RandomPassAlertComponent)
28 | component = fixture.componentInstance
29 | fixture.detectChanges()
30 | })
31 |
32 | afterEach(() => {
33 | TestBed.resetTestingModule()
34 | })
35 |
36 | it('should create', () => {
37 | expect(component).toBeTruthy()
38 | })
39 | })
40 |
--------------------------------------------------------------------------------
/src/app/devices/edit-tags/edit-tags.component.html:
--------------------------------------------------------------------------------
1 | {{ 'editTags.title.value' | translate }}
2 |
3 | {{ 'editTags.header.value' | translate }}
4 | {{ 'editTags.description.value' | translate }}
5 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/src/app/shared/static-cira-warning/static-cira-warning.component.spec.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | import { ComponentFixture, TestBed } from '@angular/core/testing'
7 | import { MatDialogModule } from '@angular/material/dialog'
8 |
9 | import { StaticCIRAWarningComponent } from './static-cira-warning.component'
10 | import { TranslateModule } from '@ngx-translate/core'
11 |
12 | describe('StaticCIRAWarningComponent', () => {
13 | let component: StaticCIRAWarningComponent
14 | let fixture: ComponentFixture
15 |
16 | beforeEach(() => {
17 | TestBed.configureTestingModule({
18 | imports: [
19 | MatDialogModule,
20 | StaticCIRAWarningComponent,
21 | TranslateModule.forRoot()
22 | ]
23 | })
24 | })
25 |
26 | beforeEach(() => {
27 | fixture = TestBed.createComponent(StaticCIRAWarningComponent)
28 | component = fixture.componentInstance
29 | fixture.detectChanges()
30 | })
31 |
32 | afterEach(() => {
33 | TestBed.resetTestingModule()
34 | })
35 |
36 | it('should create', () => {
37 | expect(component).toBeTruthy()
38 | })
39 | })
40 |
--------------------------------------------------------------------------------
/src/app/shared/power-up-alert/power-up-alert.component.spec.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | import { ComponentFixture, TestBed } from '@angular/core/testing'
7 | import { MatButtonModule } from '@angular/material/button'
8 | import { MatDialogModule } from '@angular/material/dialog'
9 |
10 | import { PowerUpAlertComponent } from './power-up-alert.component'
11 | import { TranslateModule } from '@ngx-translate/core'
12 |
13 | describe('PowerUpAlertComponent', () => {
14 | let component: PowerUpAlertComponent
15 | let fixture: ComponentFixture
16 |
17 | beforeEach(() => {
18 | TestBed.configureTestingModule({
19 | imports: [
20 | MatDialogModule,
21 | MatButtonModule,
22 | PowerUpAlertComponent,
23 | TranslateModule.forRoot()
24 | ]
25 | })
26 | })
27 |
28 | beforeEach(() => {
29 | fixture = TestBed.createComponent(PowerUpAlertComponent)
30 | component = fixture.componentInstance
31 | fixture.detectChanges()
32 | })
33 |
34 | afterEach(() => {
35 | TestBed.resetTestingModule()
36 | })
37 |
38 | it('should create', () => {
39 | expect(component).toBeTruthy()
40 | })
41 | })
42 |
--------------------------------------------------------------------------------
/src/app/shared/pipes/date-formatter.pipe.ts.pipe.spec.ts:
--------------------------------------------------------------------------------
1 | import { AmDateFormatterPipe } from './date-formatter.pipe.ts.pipe'
2 |
3 | describe('AmDateFormatterPipe', () => {
4 | let pipe: AmDateFormatterPipe
5 |
6 | beforeEach(() => {
7 | pipe = new AmDateFormatterPipe()
8 | })
9 |
10 | it('create an instance', () => {
11 | expect(pipe).toBeTruthy()
12 | })
13 |
14 | it('should format date correctly', () => {
15 | const date = new Date('2025-03-05T12:00:00Z')
16 | const result = pipe.transform(date, 'MMMM d, yyyy')
17 | expect(result).toBe('March 5, 2025')
18 | })
19 |
20 | it('should format date string correctly', () => {
21 | const date = '2025-03-05T12:00:00Z'
22 | const result = pipe.transform(date, 'MMMM d, yyyy')
23 | expect(result).toBe('March 5, 2025')
24 | })
25 |
26 | it('should format timestamp correctly', () => {
27 | const timestamp = Date.parse('2025-03-05T12:00:00Z')
28 | const result = pipe.transform(timestamp, 'MMMM d, yyyy')
29 | expect(result).toBe('March 5, 2025')
30 | })
31 |
32 | it('should return empty string if no date is provided', () => {
33 | const result = pipe.transform('')
34 | expect(result).toBe('')
35 | })
36 |
37 | it('should handle invalid date input gracefully', () => {
38 | const result = pipe.transform('invalid-date')
39 | expect(result).toBe('Invalid Date')
40 | })
41 | })
42 |
--------------------------------------------------------------------------------
/src/app/shared/are-you-sure/are-you-sure.component.spec.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | import { ComponentFixture, TestBed } from '@angular/core/testing'
7 | import { MatButtonModule } from '@angular/material/button'
8 | import { MatDialogModule } from '@angular/material/dialog'
9 |
10 | import { AreYouSureDialogComponent } from './are-you-sure.component'
11 | import { TranslateModule } from '@ngx-translate/core'
12 |
13 | describe('AreYouSureComponent', () => {
14 | let component: AreYouSureDialogComponent
15 | let fixture: ComponentFixture
16 |
17 | beforeEach(() => {
18 | TestBed.configureTestingModule({
19 | imports: [
20 | MatDialogModule,
21 | MatButtonModule,
22 | AreYouSureDialogComponent,
23 | TranslateModule.forRoot()
24 | ]
25 | })
26 | })
27 |
28 | beforeEach(() => {
29 | fixture = TestBed.createComponent(AreYouSureDialogComponent)
30 | component = fixture.componentInstance
31 | fixture.detectChanges()
32 | })
33 |
34 | afterEach(() => {
35 | TestBed.resetTestingModule()
36 | })
37 |
38 | it('should create', () => {
39 | expect(component).toBeTruthy()
40 | })
41 | })
42 |
--------------------------------------------------------------------------------
/src/environments/environment.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | // This file can be replaced during build by using the `fileReplacements` array.
7 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.
8 | // The list of file replacements can be found in `angular.json`.
9 |
10 | export const environment = {
11 | production: false,
12 | cloud: true,
13 | useOAuth: false, // for use with console
14 | mpsServer: 'http://localhost:3000',
15 | rpsServer: 'http://localhost:8081',
16 | vault: 'http://localhost/vault',
17 | auth: {
18 | clientId: '',
19 | issuer: '',
20 | redirectUri: 'http://localhost:4200/dashboard',
21 | scope: '',
22 | responseType: 'code',
23 | requireHttps: true // set to false when local
24 | }
25 | }
26 |
27 | /*
28 | * For easier debugging in development mode, you can import the following file
29 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
30 | *
31 | * This import should be commented out in production mode because it will have a negative impact
32 | * on performance if an error is thrown.
33 | */
34 | // import 'zone.js/plugins/zone-error'; // Included with Angular CLI.
35 |
--------------------------------------------------------------------------------
/src/app/profiles/profile-detail/profile-detail.component.scss:
--------------------------------------------------------------------------------
1 | fieldset {
2 | border: 1px solid #ccc;
3 | border-radius: 4px;
4 | padding: 10px;
5 | margin: 12px 0;
6 | }
7 | .mat-mdc-list {
8 | width: 100%;
9 | margin-bottom: 24px;
10 | }
11 | .drag-box {
12 | padding: 10px 10px;
13 | border-bottom: solid 1px #ccc;
14 | color: rgba(0, 0, 0, 0.87);
15 | line-height: 1.3;
16 | flex-direction: row;
17 | align-items: center;
18 | justify-content: space-between;
19 | box-sizing: border-box;
20 | cursor: move;
21 | background: white;
22 | font-size: 14px;
23 | }
24 | .cdk-drag-preview {
25 | button,
26 | .mat-icon {
27 | display: none;
28 | }
29 | box-sizing: border-box;
30 | border-radius: 4px;
31 | box-shadow:
32 | 0 5px 5px -3px rgba(0, 0, 0, 0.2),
33 | 0 8px 10px 1px rgba(0, 0, 0, 0.14),
34 | 0 3px 14px 2px rgba(0, 0, 0, 0.12);
35 | }
36 |
37 | .cdk-drag-placeholder {
38 | opacity: 0;
39 | }
40 |
41 | .cdk-drag-animating {
42 | transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
43 | }
44 |
45 | .drag-box:last-child {
46 | border: none;
47 | }
48 |
49 | .mat-mdc-list.cdk-drop-list-dragging .drag-box:not(.cdk-drag-placeholder) {
50 | transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
51 | width: 100%;
52 | }
53 |
54 | .no-results {
55 | pointer-events: none;
56 | }
57 |
58 | .like-mat-hint {
59 | font-size: 75%;
60 | color: rgba(0, 0, 0, 0.54);
61 | }
62 |
--------------------------------------------------------------------------------
/src/app/devices/network-settings/network-settings.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { ComponentFixture, TestBed } from '@angular/core/testing'
2 |
3 | import { NetworkSettingsComponent } from './network-settings.component'
4 | import { DevicesService } from '../devices.service'
5 | import { of } from 'rxjs'
6 | import { TranslateModule } from '@ngx-translate/core'
7 |
8 | describe('NetworkSettingsComponent', () => {
9 | let component: NetworkSettingsComponent
10 | let fixture: ComponentFixture
11 | let devicesServiceSpy: jasmine.SpyObj
12 |
13 | beforeEach(async () => {
14 | devicesServiceSpy = jasmine.createSpyObj('DevicesService', [
15 | 'getNetworkSettings'
16 | ])
17 | devicesServiceSpy.getNetworkSettings.and.returnValue(
18 | of({
19 | wired: { ieee8021x: {} },
20 | wireless: {
21 | wifiNetworks: [],
22 | ieee8021xSettings: []
23 | }
24 | } as any)
25 | )
26 | TestBed.configureTestingModule({
27 | imports: [NetworkSettingsComponent, TranslateModule.forRoot()],
28 | providers: [
29 | { provide: DevicesService, useValue: devicesServiceSpy }]
30 | })
31 |
32 | fixture = TestBed.createComponent(NetworkSettingsComponent)
33 | component = fixture.componentInstance
34 | fixture.detectChanges()
35 | })
36 |
37 | it('should create', () => {
38 | expect(component).toBeTruthy()
39 | })
40 | })
41 |
--------------------------------------------------------------------------------
/cypress/e2e/integration/domain/vault-read-certificate.spec.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | import { httpCodes } from 'cypress/e2e/fixtures/api/httpCodes'
7 | import { domainFixtures } from 'cypress/e2e/fixtures/formEntry/domain'
8 |
9 | // Test REST call to Vault to verify Provisioning Certificate and Password are present
10 |
11 | describe('REST API - Vault Test Suite', () => {
12 | it('REST API - Read Provisioning Certificate and Password from Vault test case', () => {
13 | if (Cypress.env('ISOLATE') === 'N') {
14 | const vaultAddress: string = Cypress.env('VAULT_ADDRESS')
15 | const vaultToken = Cypress.env('VAULT_TOKEN')
16 | const vaultURL = `${vaultAddress}/v1/secret/data/certs/${domainFixtures.default.profileName}`
17 | cy.request({
18 | auth: { bearer: vaultToken },
19 | method: 'GET',
20 | url: vaultURL
21 | }).should((response) => {
22 | expect(response.status).to.equal(httpCodes.SUCCESS)
23 | expect(JSON.stringify(response.body.data.data.CERT)).contains(Cypress.env('PROVISIONING_CERT'))
24 | expect(JSON.stringify(response.body.data.data.CERT_PASSWORD)).contains(
25 | Cypress.env('PROVISIONING_CERT_PASSWORD')
26 | )
27 | })
28 | }
29 | })
30 | })
31 |
--------------------------------------------------------------------------------
/src/app/shared/dialog-content/dialog-content.component.spec.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | import { ComponentFixture, TestBed } from '@angular/core/testing'
7 | import { MatDialogModule, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'
8 | import { DialogContentComponent } from './dialog-content.component'
9 | import { TranslateModule } from '@ngx-translate/core'
10 |
11 | describe('DialogContentComponent', () => {
12 | let component: DialogContentComponent
13 | let fixture: ComponentFixture
14 |
15 | beforeEach(() => {
16 | TestBed.configureTestingModule({
17 | imports: [
18 | MatDialogModule,
19 | DialogContentComponent,
20 | TranslateModule.forRoot()
21 | ],
22 | providers: [
23 | { provide: MAT_DIALOG_DATA, useValue: {} },
24 | { provide: MatDialogRef, useValue: {} }
25 | ]
26 | })
27 | })
28 |
29 | beforeEach(() => {
30 | fixture = TestBed.createComponent(DialogContentComponent)
31 | component = fixture.componentInstance
32 | fixture.detectChanges()
33 | })
34 |
35 | afterEach(() => {
36 | TestBed.resetTestingModule()
37 | })
38 |
39 | it('should create', () => {
40 | expect(component).toBeTruthy()
41 | })
42 | })
43 |
--------------------------------------------------------------------------------
/src/app/devices/device-log.service.spec.ts:
--------------------------------------------------------------------------------
1 | import { HttpClient } from '@angular/common/http'
2 | import { inject, Injectable } from '@angular/core'
3 | import { catchError, Observable } from 'rxjs'
4 | import { environment } from 'src/environments/environment'
5 | import { AuditLogResponse, EventLog } from 'src/models/models'
6 |
7 | @Injectable({
8 | providedIn: 'root'
9 | })
10 | export class DeviceLogService {
11 | private readonly http = inject(HttpClient)
12 |
13 | downloadAuditLog(deviceId: string): Observable {
14 | return this.http.get(`${environment.mpsServer}/api/v1/amt/log/audit/${deviceId}/download`, {
15 | responseType: 'blob'
16 | })
17 | }
18 |
19 | getAuditLog(deviceId: string, startIndex = 0): Observable {
20 | return this.http
21 | .get(`${environment.mpsServer}/api/v1/amt/log/audit/${deviceId}?startIndex=${startIndex}`)
22 | .pipe(
23 | catchError((err) => {
24 | throw err
25 | })
26 | )
27 | }
28 |
29 | downloadEventLog(deviceId: string): Observable {
30 | return this.http.get(`${environment.mpsServer}/api/v1/amt/log/event/${deviceId}/download`, {
31 | responseType: 'blob'
32 | })
33 | }
34 |
35 | getEventLog(deviceId: string): Observable {
36 | return this.http.get(`${environment.mpsServer}/api/v1/amt/log/event/${deviceId}`).pipe(
37 | catchError((err) => {
38 | throw err
39 | })
40 | )
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/cypress/e2e/fixtures/formEntry/ieee8021x.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | import { AuthenticationProtocols } from 'src/app/ieee8021x/ieee8021x.constants'
7 | import { IEEE8021xConfig } from 'src/models/models'
8 |
9 | export const wiredConfigs: IEEE8021xConfig[] = []
10 | AuthenticationProtocols.filter((x) => x.mode === 'wired').forEach((authProtocol) => {
11 | ;[0, 60 * 60 * 24].forEach((pxeTimeout) => {
12 | wiredConfigs.push({
13 | profileName: `8021xWiredProto${authProtocol.value}Pxe${pxeTimeout}`,
14 | wiredInterface: true,
15 | authenticationProtocol: authProtocol.value,
16 | pxeTimeout
17 | })
18 | })
19 | })
20 |
21 | export const wirelessConfigs: IEEE8021xConfig[] = []
22 | AuthenticationProtocols.filter((x) => x.mode === 'both').forEach((authProtocol) => {
23 | // at this release, only one protocol is supported, but would like to ensure
24 | // multiple wireless configurations can be created, so use a couple of names
25 | ;[
26 | 'cfg01',
27 | 'cfg02',
28 | 'cfg03'
29 | ].forEach((nameSuffix) => {
30 | wirelessConfigs.push({
31 | profileName: `8021xWirelessProto${authProtocol.value}${nameSuffix}`,
32 | wiredInterface: false,
33 | authenticationProtocol: authProtocol.value,
34 | pxeTimeout: 0
35 | })
36 | })
37 | })
38 |
--------------------------------------------------------------------------------
/.github/workflows/docker.yaml:
--------------------------------------------------------------------------------
1 | name: Docker Image CI
2 |
3 | on:
4 | workflow_dispatch:
5 | inputs:
6 | docker_registry:
7 | description: 'Registry URL'
8 | required: true
9 | default: 'docker.io/username'
10 | docker_tag_name:
11 | description: 'Tag you wish to use on the docker image'
12 | required: true
13 | default: 'webui:latest'
14 | permissions:
15 | contents: read
16 |
17 | jobs:
18 | build:
19 | runs-on: ubuntu-latest
20 |
21 | steps:
22 | - name: Harden Runner
23 | uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
24 | with:
25 | egress-policy: audit
26 |
27 | - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
28 | - name: Build the Docker image
29 | run: docker buildx build --platform linux/amd64,linux/arm64 . --file Dockerfile --tag ${{ github.event.inputs.docker_registry }}/${{ github.event.inputs.docker_tag_name }}
30 | - name: Docker Login
31 | uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
32 | with:
33 | registry: ${{ github.event.inputs.docker_registry }}
34 | username: ${{ secrets.DOCKER_USERNAME }}
35 | password: ${{ secrets.DOCKER_PASSWORD }}
36 | logout: true
37 | - name: Push the Docker image to ${{ github.event.inputs.docker_registry }}
38 | run: docker push ${{ github.event.inputs.docker_registry }}/${{ github.event.inputs.docker_tag_name }}
39 |
--------------------------------------------------------------------------------
/src/app/core/navbar/navbar.component.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | import { Component, inject } from '@angular/core'
7 | import { environment } from 'src/environments/environment'
8 | import { MatIcon } from '@angular/material/icon'
9 | import { RouterLink, RouterLinkActive } from '@angular/router'
10 | import { MatDivider } from '@angular/material/divider'
11 | import { MatNavList, MatListItem, MatListItemIcon } from '@angular/material/list'
12 | import { MatTooltip } from '@angular/material/tooltip'
13 | import { TranslateModule, TranslateService } from '@ngx-translate/core'
14 |
15 | @Component({
16 | selector: 'app-navbar',
17 | templateUrl: './navbar.component.html',
18 | styleUrls: ['./navbar.component.scss'],
19 | imports: [
20 | MatNavList,
21 | MatDivider,
22 | MatListItem,
23 | RouterLink,
24 | RouterLinkActive,
25 | MatIcon,
26 | MatListItemIcon,
27 | MatTooltip,
28 | TranslateModule
29 | ]
30 | })
31 | export class NavbarComponent {
32 | cloudMode = environment.cloud
33 | showSubNav = false
34 | private readonly translate = inject(TranslateService)
35 |
36 | get ciraTitle(): string {
37 | return this.cloudMode === false
38 | ? this.translate.instant('configs.header.noCiraTitle.value')
39 | : this.translate.instant('configs.header.ciraTitle.value')
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/app/devices/device-toolbar/pba-boot-dialog/pba-boot-dialog.component.html:
--------------------------------------------------------------------------------
1 |
2 | {{ 'devices.header.pbaBootTitle.value' | translate }}
3 |
4 |
5 | {{ 'devices.header.pbaBootDescription.value' | translate }}
6 |
26 |
27 |
28 |
29 |
32 |
33 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | # Maintain dependencies for npm modules
4 | - package-ecosystem: "npm"
5 | directory: "/"
6 | schedule:
7 | interval: "daily"
8 | # Group Angular ecosystem deps so they update together (reduces PR noise)
9 | groups:
10 | angular-stack:
11 | patterns:
12 | - '@angular/*' # covers core, cli, cdk, material, etc.
13 | - '@angular-devkit/*'
14 | - 'rxjs'
15 | - 'zone.js'
16 | - 'typescript'
17 | # Only create grouped PRs for safe patch & minor updates; majors handled manually with ng update
18 | update-types:
19 | - patch
20 | - minor
21 | # Ignore major version bumps so they don't auto-open without schematics migrations
22 | ignore:
23 | - dependency-name: '@angular/*'
24 | update-types:
25 | - version-update:semver-major
26 | - dependency-name: '@angular-devkit/*'
27 | update-types:
28 | - version-update:semver-major
29 | - dependency-name: 'rxjs'
30 | update-types:
31 | - version-update:semver-major
32 | - dependency-name: 'zone.js'
33 | update-types:
34 | - version-update:semver-major
35 | - dependency-name: 'typescript'
36 | update-types:
37 | - version-update:semver-major
38 |
39 | - package-ecosystem: github-actions
40 | directory: /
41 | schedule:
42 | interval: daily
43 |
44 | - package-ecosystem: docker
45 | directory: /
46 | schedule:
47 | interval: daily
48 |
--------------------------------------------------------------------------------
/src/app/core/about/about.component.spec.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | import { ComponentFixture, TestBed } from '@angular/core/testing'
7 | import { MatDialogModule } from '@angular/material/dialog'
8 | import { MatIconModule } from '@angular/material/icon'
9 | import { MatListModule } from '@angular/material/list'
10 |
11 | import { AboutComponent } from './about.component'
12 | import { TranslateModule } from '@ngx-translate/core'
13 |
14 | describe('AboutComponent', () => {
15 | let component: AboutComponent
16 | let fixture: ComponentFixture
17 |
18 | beforeEach(() => {
19 | TestBed.configureTestingModule({
20 | imports: [
21 | MatListModule,
22 | MatIconModule,
23 | MatDialogModule,
24 | AboutComponent,
25 | TranslateModule.forRoot()
26 | ]
27 | })
28 | })
29 |
30 | beforeEach(() => {
31 | fixture = TestBed.createComponent(AboutComponent)
32 | component = fixture.componentInstance
33 | fixture.detectChanges()
34 | })
35 |
36 | afterEach(() => {
37 | TestBed.resetTestingModule()
38 | })
39 |
40 | it('should create', () => {
41 | expect(component).toBeTruthy()
42 | })
43 |
44 | it('should initialize doNotShowAgain from localStorage', () => {
45 | spyOn(localStorage, 'getItem').and.returnValue('true')
46 | component.ngOnInit()
47 | expect(localStorage.getItem).toHaveBeenCalledWith('doNotShowAgain')
48 | })
49 | })
50 |
--------------------------------------------------------------------------------
/src/app/devices/device-enable-kvm/device-enable-kvm.component.spec.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | import { ComponentFixture, TestBed } from '@angular/core/testing'
7 | import { MatDialogRef } from '@angular/material/dialog'
8 | import { BrowserAnimationsModule } from '@angular/platform-browser/animations'
9 | import { DeviceEnableKvmComponent } from './device-enable-kvm.component'
10 | import { RouterModule } from '@angular/router'
11 | import { TranslateModule } from '@ngx-translate/core'
12 |
13 | describe('DeviceEnableKvmComponent', () => {
14 | let component: DeviceEnableKvmComponent
15 | let fixture: ComponentFixture
16 | const dialogMock = {
17 | close: jasmine.createSpy('close')
18 | }
19 |
20 | beforeEach(() => {
21 | TestBed.configureTestingModule({
22 | imports: [
23 | BrowserAnimationsModule,
24 | RouterModule,
25 | DeviceEnableKvmComponent,
26 | TranslateModule.forRoot()
27 | ],
28 | providers: [
29 | { provide: MatDialogRef, useValue: dialogMock }]
30 | })
31 | })
32 |
33 | beforeEach(() => {
34 | fixture = TestBed.createComponent(DeviceEnableKvmComponent)
35 | component = fixture.componentInstance
36 | fixture.detectChanges()
37 | dialogMock.close = jasmine.createSpy('close')
38 | })
39 |
40 | afterEach(() => {
41 | TestBed.resetTestingModule()
42 | })
43 |
44 | it('should create', () => {
45 | expect(component).toBeTruthy()
46 | })
47 | })
48 |
--------------------------------------------------------------------------------
/src/app/devices/device-enable-sol/device-enable-sol.component.spec.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | import { ComponentFixture, TestBed } from '@angular/core/testing'
7 | import { MatDialogRef } from '@angular/material/dialog'
8 | import { BrowserAnimationsModule } from '@angular/platform-browser/animations'
9 | import { DeviceEnableSolComponent } from './device-enable-sol.component'
10 | import { RouterModule } from '@angular/router'
11 | import { TranslateModule } from '@ngx-translate/core'
12 |
13 | describe('DeviceEnableSolComponent', () => {
14 | let component: DeviceEnableSolComponent
15 | let fixture: ComponentFixture
16 | const dialogMock = {
17 | close: jasmine.createSpy('close')
18 | }
19 |
20 | beforeEach(() => {
21 | TestBed.configureTestingModule({
22 | imports: [
23 | BrowserAnimationsModule,
24 | RouterModule,
25 | DeviceEnableSolComponent,
26 | TranslateModule.forRoot()
27 | ],
28 | providers: [
29 | { provide: MatDialogRef, useValue: dialogMock }]
30 | })
31 | })
32 |
33 | beforeEach(() => {
34 | fixture = TestBed.createComponent(DeviceEnableSolComponent)
35 | component = fixture.componentInstance
36 | fixture.detectChanges()
37 | dialogMock.close = jasmine.createSpy('close')
38 | })
39 |
40 | afterEach(() => {
41 | TestBed.resetTestingModule()
42 | })
43 |
44 | it('should create', () => {
45 | expect(component).toBeTruthy()
46 | })
47 | })
48 |
--------------------------------------------------------------------------------
/src/app/core/about/about.component.html:
--------------------------------------------------------------------------------
1 |
2 | @if (cloudMode === true) {
3 | warning
4 | {{ 'about.cloudMode.value' | translate }}
5 | } @else {
6 | {{ 'about.nonCloudMode.value' | translate }}
7 | }
8 |
9 |
10 | @if (cloudMode === true) {
11 |
12 |
13 | {{ 'about.referenceImplementation.value' | translate }}
14 |
15 |
16 |
17 | {{ 'about.sampleUI.value' | translate }}
18 |
19 | - {{ 'about.learn.value' | translate }}
20 | - {{ 'about.setUp.value' | translate }}
21 | -
22 | {{ 'about.understand.value' | translate }}
23 |
24 | - {{ 'about.howTo.value' | translate }}
25 |
26 | } @else {
27 |
28 | {{ 'about.description.value' | translate }}
29 |
30 |
31 |
32 | {{ 'about.consoleProvides.value' | translate }}
33 |
34 | - {{ 'about.remotePower.value' | translate }}
35 | - {{ 'about.redirection.value' | translate }}
36 | - {{ 'about.device.value' | translate }}
37 |
38 | }
39 |
40 |
41 | @if (cloudMode === true) {
42 |
45 | }
46 |
49 |
50 |
--------------------------------------------------------------------------------
/src/app/core/about/about.component.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | import { Component, OnDestroy, OnInit } from '@angular/core'
7 | import { environment } from 'src/environments/environment'
8 | import { MatButton } from '@angular/material/button'
9 | import { ReactiveFormsModule, FormsModule } from '@angular/forms'
10 | import { MatDivider } from '@angular/material/divider'
11 | import { CdkScrollable } from '@angular/cdk/scrolling'
12 | import { MatIcon } from '@angular/material/icon'
13 | import { MatDialogTitle, MatDialogContent, MatDialogActions, MatDialogClose } from '@angular/material/dialog'
14 | import { TranslateModule } from '@ngx-translate/core'
15 |
16 | @Component({
17 | selector: 'app-about',
18 | templateUrl: './about.component.html',
19 | styleUrls: ['./about.component.scss'],
20 | imports: [
21 | MatDialogTitle,
22 | MatIcon,
23 | CdkScrollable,
24 | MatDialogContent,
25 | MatDivider,
26 | MatDialogActions,
27 | ReactiveFormsModule,
28 | FormsModule,
29 | MatButton,
30 | MatDialogClose,
31 | TranslateModule
32 | ]
33 | })
34 | export class AboutComponent implements OnDestroy, OnInit {
35 | doNotShowAgain = false
36 | cloudMode: boolean = environment.cloud
37 | ngOnInit(): void {
38 | const storedValue = localStorage.getItem('doNotShowAgain')
39 | this.doNotShowAgain = storedValue ? JSON.parse(storedValue) : false
40 | }
41 |
42 | ngOnDestroy(): void {
43 | localStorage.setItem('doNotShowAgain', JSON.stringify(this.doNotShowAgain))
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/app/shared/pipes/time-ago-formatter.pipe.ts.pipe.spec.ts:
--------------------------------------------------------------------------------
1 | import { AmTimeAgoFormatterPipe } from './time-ago-formatter.pipe.ts.pipe'
2 |
3 | describe('AmTimeAgoFormatterPipe', () => {
4 | let pipe: AmTimeAgoFormatterPipe
5 |
6 | beforeEach(() => {
7 | pipe = new AmTimeAgoFormatterPipe()
8 | })
9 |
10 | it('create an instance', () => {
11 | expect(pipe).toBeTruthy()
12 | })
13 |
14 | it('should transform date to time ago format', () => {
15 | const date = new Date()
16 | const result = pipe.transform(date)
17 | expect(result).toContain('less than a minute ago')
18 | })
19 |
20 | it('should transform date string to time ago format', () => {
21 | const date = new Date().toISOString()
22 | const result = pipe.transform(date)
23 | expect(result).toContain('less than a minute ago')
24 | })
25 |
26 | it('should transform timestamp to time ago format', () => {
27 | const timestamp = Date.now()
28 | const result = pipe.transform(timestamp)
29 | expect(result).toContain('less than a minute ago')
30 | })
31 |
32 | it('should return empty string if no date is provided', () => {
33 | const result = pipe.transform('')
34 | expect(result).toBe('')
35 | })
36 |
37 | it('should add suffix if addSuffix is true', () => {
38 | const date = new Date(Date.now() - 60000) // 1 minute ago
39 | const result = pipe.transform(date, true)
40 | expect(result).toContain('minute ago')
41 | })
42 |
43 | it('should not add suffix if addSuffix is false', () => {
44 | const date = new Date(Date.now() - 60000) // 1 minute ago
45 | const result = pipe.transform(date, false)
46 | expect(result).toContain('minute')
47 | expect(result).not.toContain('ago')
48 | })
49 | })
50 |
--------------------------------------------------------------------------------
/src/app/shared/pipes/toolkit.pipe.spec.ts:
--------------------------------------------------------------------------------
1 | import { TestBed } from '@angular/core/testing'
2 | import { FormOption } from 'src/models/models'
3 | import { ToolkitPipe } from './toolkit.pipe'
4 | import { TranslateModule } from '@ngx-translate/core'
5 |
6 | describe('ToolkitPipe', () => {
7 | let pipe: ToolkitPipe
8 |
9 | beforeEach(() => {
10 | TestBed.configureTestingModule({
11 | imports: [TranslateModule.forRoot()],
12 | providers: [ToolkitPipe]
13 | })
14 | pipe = TestBed.inject(ToolkitPipe)
15 | })
16 |
17 | it('create an instance', () => {
18 | expect(pipe).toBeTruthy()
19 | })
20 |
21 | it('should return the correct label when value matches', () => {
22 | const options: FormOption[] = [
23 | { value: 1, label: 'Option 1' },
24 | { value: 2, label: 'Option 2' }
25 | ]
26 | expect(pipe.transform(1, options)).toBe('Option 1')
27 | })
28 |
29 | it('should return null when no value matches', () => {
30 | const options: FormOption[] = [
31 | { value: 1, label: 'Option 1' },
32 | { value: 2, label: 'Option 2' }
33 | ]
34 | expect(pipe.transform(3, options)).toBeNull()
35 | })
36 |
37 | it('should handle empty options array', () => {
38 | const options: FormOption[] = []
39 | expect(pipe.transform(1, options)).toBeNull()
40 | })
41 |
42 | it('should handle non-number values in options', () => {
43 | const options: FormOption[] = [
44 | { value: 'test', label: 'Option Test' },
45 | { value: true, label: 'Option True' }
46 | ]
47 | expect(pipe.transform('test' as unknown as number, options)).toBe('Option Test')
48 | })
49 | })
50 |
--------------------------------------------------------------------------------
/src/app/devices/certificates/add-cert-dialog/add-cert-dialog.component.html:
--------------------------------------------------------------------------------
1 |
2 | {{ 'devices.header.addCertificateTitle.value' | translate }}
3 |
4 |
5 | {{ 'devices.header.addCertificateDescription.value' | translate }}
6 |
7 |
8 |
9 |
12 |
13 |
14 |
15 | @if (certInfo.cert === '') {
16 |
17 | remove_circle
18 | {{ 'common.cetificateNotUploaded.value' | translate }}
19 |
20 | } @else {
21 |
22 | check_circle
23 | {{ 'common.cetificateUploaded.value' | translate }}
24 |
25 | }
26 |
27 |
28 |
29 | {{
30 | 'common.trustedRoot.value' | translate
31 | }}
32 |
33 |
34 |
35 |
38 |
39 |
--------------------------------------------------------------------------------
/src/assets/i18n/translate-paginator-intl.ts:
--------------------------------------------------------------------------------
1 | import { inject, Injectable } from '@angular/core'
2 | import { MatPaginatorIntl } from '@angular/material/paginator'
3 | import { TranslateService } from '@ngx-translate/core'
4 |
5 | @Injectable()
6 | export class TranslatePaginatorIntl extends MatPaginatorIntl {
7 | private readonly translate = inject(TranslateService)
8 | constructor() {
9 | super()
10 | this.translateLabels()
11 |
12 | this.translate.onLangChange.subscribe(() => {
13 | this.translateLabels()
14 | this.changes.next()
15 | })
16 | }
17 |
18 | private translateLabels(): void {
19 | this.itemsPerPageLabel = this.translate.instant('configs.paginator.itemsPerPageLabel.value')
20 | this.nextPageLabel = this.translate.instant('configs.paginator.nextPageLabel.value')
21 | this.previousPageLabel = this.translate.instant('configs.paginator.previousPageLabel.value')
22 | this.firstPageLabel = this.translate.instant('configs.paginator.firstPageLabel.value')
23 | this.lastPageLabel = this.translate.instant('configs.paginator.lastPageLabel.value')
24 |
25 | this.getRangeLabel = (page: number, pageSize: number, length: number): string => {
26 | if (length === 0 || pageSize === 0) {
27 | return this.translate.instant('configs.paginator.range.value', {
28 | startIndex: 0,
29 | endIndex: 0,
30 | length: length
31 | })
32 | }
33 | const startIndex = page * pageSize
34 | const endIndex = startIndex < length ? Math.min(startIndex + pageSize, length) : startIndex + pageSize
35 |
36 | return this.translate.instant('configs.paginator.range.value', {
37 | startIndex: startIndex + 1,
38 | endIndex: endIndex,
39 | length: length
40 | })
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/app/error-handling.interceptor.ts:
--------------------------------------------------------------------------------
1 | import { HttpErrorResponse, HttpInterceptorFn } from '@angular/common/http'
2 | import { catchError, of, throwError } from 'rxjs'
3 | import { DialogContentComponent } from './shared/dialog-content/dialog-content.component'
4 | import { MatSnackBar } from '@angular/material/snack-bar'
5 | import { MatDialog } from '@angular/material/dialog'
6 | import { AuthService } from './auth.service'
7 | import { inject } from '@angular/core'
8 | import { TranslateService } from '@ngx-translate/core'
9 |
10 | export const errorHandlingInterceptor: HttpInterceptorFn = (request, next) => {
11 | const authService = inject(AuthService)
12 | const dialog = inject(MatDialog)
13 | const snackbar = inject(MatSnackBar)
14 | const translate = inject(TranslateService)
15 |
16 | return next(request).pipe(
17 | catchError((error: any) => {
18 | if (error instanceof HttpErrorResponse) {
19 | if (error.status === 401) {
20 | if (error.error.exp === 'token expired') {
21 | dialog.open(DialogContentComponent, { data: { name: translate.instant('error.sessionTimedOut.value') } })
22 | }
23 | authService.logout()
24 | } else if (error.status === 412 || error.status === 409) {
25 | dialog.open(DialogContentComponent, {
26 | data: { name: translate.instant('error.itemModified.value') }
27 | })
28 | } else if (error.status === 504) {
29 | snackbar.open(
30 | translate.instant('error.deviceNotResponding.value'),
31 | translate.instant('common.dismiss.value'),
32 | {
33 | duration: 5000
34 | }
35 | )
36 | return of()
37 | }
38 | }
39 | return throwError(() => error)
40 | })
41 | )
42 | }
43 |
--------------------------------------------------------------------------------
/src/app/devices/tls/tls.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit, inject, signal, input } from '@angular/core'
2 | import { catchError, finalize, throwError } from 'rxjs'
3 | import SnackbarDefaults from 'src/app/shared/config/snackBarDefault'
4 | import { DevicesService } from '../devices.service'
5 | import { MatSnackBar } from '@angular/material/snack-bar'
6 | import { MatCardModule } from '@angular/material/card'
7 | import { MatDividerModule } from '@angular/material/divider'
8 | import { MatProgressBarModule } from '@angular/material/progress-bar'
9 | import { TranslateModule, TranslateService } from '@ngx-translate/core'
10 |
11 | @Component({
12 | selector: 'app-tls',
13 | imports: [
14 | MatCardModule,
15 | MatDividerModule,
16 | MatProgressBarModule,
17 | TranslateModule
18 | ],
19 | templateUrl: './tls.component.html',
20 | styleUrl: './tls.component.scss'
21 | })
22 | export class TLSComponent implements OnInit {
23 | // Dependency Injection
24 | private readonly snackBar = inject(MatSnackBar)
25 | private readonly devicesService = inject(DevicesService)
26 | private readonly translate = inject(TranslateService)
27 | public readonly deviceId = input('')
28 |
29 | public isLoading = signal(true)
30 | public tlsData?: any[] = []
31 |
32 | ngOnInit(): void {
33 | this.devicesService
34 | .getTLSSettings(this.deviceId())
35 | .pipe(
36 | catchError((err) => {
37 | const msg: string = this.translate.instant('tls.errorSettings.value')
38 | this.snackBar.open(msg, undefined, SnackbarDefaults.defaultError)
39 | return throwError(err)
40 | }),
41 | finalize(() => {
42 | this.isLoading.set(false)
43 | })
44 | )
45 | .subscribe((results) => {
46 | this.tlsData = results
47 | })
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/.github/workflows/trivy-scan.yaml:
--------------------------------------------------------------------------------
1 | name: Trivy Container Scan
2 |
3 | on:
4 | push:
5 | branches: [main]
6 | pull_request:
7 | # The branches below must be a subset of the branches above
8 | branches: [main]
9 | permissions:
10 | contents: read
11 | jobs:
12 | build:
13 | runs-on: ubuntu-latest
14 | permissions:
15 | security-events: write
16 | steps:
17 | - name: Harden Runner
18 | uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
19 | with:
20 | egress-policy: audit
21 |
22 | - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
23 | - name: Build the Docker image
24 |
25 | run: docker build . --file Dockerfile --tag vprodemo.azurecr.io/webui:${{ github.sha }} --tag vprodemo.azurecr.io/webui:latest
26 | - name: Run Trivy vulnerability scanner
27 | uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8 # master
28 | with:
29 | image-ref: 'vprodemo.azurecr.io/webui:${{ github.sha }}'
30 | format: 'sarif'
31 | output: 'webui-trivy-results.sarif'
32 | exit-code: '1'
33 | ignore-unfixed: true
34 | vuln-type: 'os,library'
35 | severity: 'UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL'
36 | - name: Upload Trivy scan results to GitHub Security tab
37 | uses: github/codeql-action/upload-sarif@cf1bb45a277cb3c205638b2cd5c984db1c46a412 # v3.29.5
38 | if: always()
39 | with:
40 | sarif_file: 'webui-trivy-results.sarif'
41 | - name: Upload Trivy Artifacts
42 | uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
43 | if: always()
44 | with:
45 | name: webui-trivy-results.sarif
46 | path: webui-trivy-results.sarif
47 |
--------------------------------------------------------------------------------
/src/app/core/toolbar/toolbar.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | @if (cloudMode === true) {
4 | {{ 'toolbar.header.cloudModeTitle.value' | translate }}
5 | } @else {
6 | {{ 'toolbar.header.consoleModeTitle.value' | translate }}
7 | @if (consoleVersion().current) {
8 | {{ consoleVersion().current }}
9 | }
10 | }
11 |
12 |
13 | @if (cloudMode === true) {
14 | @if (isLoggedIn === true) {
15 |
MPS: v{{ mpsVersions().serviceVersion }}
16 |
RPS: v{{ rpsVersions().serviceVersion }}
17 | }
18 |
19 | }
20 |
21 |
{{ 'toolbar.header.hello.value' | translate }}
22 |
23 |
26 |
35 |
36 | @if (isLoggedIn === true) {
37 |
40 | }
41 |
42 |
45 |
46 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/.github/workflows/nodejs.yaml:
--------------------------------------------------------------------------------
1 | # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
3 |
4 | name: Node.js CI
5 |
6 | on:
7 | push:
8 | branches: [main]
9 | pull_request:
10 | branches: [main]
11 | workflow_dispatch:
12 | permissions:
13 | contents: read
14 |
15 | jobs:
16 | build:
17 | runs-on: ubuntu-latest
18 |
19 | strategy:
20 | matrix:
21 | node-version: [22.x]
22 |
23 | steps:
24 | - name: Harden Runner
25 | uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
26 | with:
27 | egress-policy: audit
28 |
29 | - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
30 | - name: Use Node.js ${{ matrix.node-version }}
31 | uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
32 | with:
33 | node-version: ${{ matrix.node-version }}
34 | - run: npm install
35 | - run: npm run lint
36 | if: ${{ matrix.node-version == '22.x' }}
37 | - run: npm run lint:cypress
38 | if: ${{ matrix.node-version == '22.x' }}
39 | - run: npm run ci-prettify
40 | - run: npm run test-ci
41 | - uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2
42 | name: Upload Coverage Results
43 | if: ${{ matrix.node-version == '22.x' }}
44 | with:
45 | directory: ./coverage/samplewebui
46 | - name: Upload Karma Results
47 | uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
48 | with:
49 | name: sample-web-ui-unit-${{ matrix.node-version }}
50 | path: TESTS-Chrome-${{ matrix.node-version }}_*.xml
51 |
--------------------------------------------------------------------------------
/src/app/shared/auth-guard.service.spec.ts:
--------------------------------------------------------------------------------
1 | import { TestBed } from '@angular/core/testing'
2 | import { AuthGuard } from './auth-guard.service'
3 | import { AuthService } from '../auth.service'
4 | import { ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router'
5 | import { of } from 'rxjs'
6 |
7 | describe('AuthGuard', () => {
8 | let authGuard: AuthGuard
9 | let authService: jasmine.SpyObj
10 | let router: jasmine.SpyObj
11 |
12 | beforeEach(() => {
13 | const authServiceSpy = jasmine.createSpyObj('AuthService', ['canActivateProtectedRoutes$'])
14 | const routerSpy = jasmine.createSpyObj('Router', ['navigate'])
15 |
16 | TestBed.configureTestingModule({
17 | providers: [
18 | AuthGuard,
19 | { provide: AuthService, useValue: authServiceSpy },
20 | { provide: Router, useValue: routerSpy }]
21 | })
22 |
23 | authGuard = TestBed.inject(AuthGuard)
24 | authService = TestBed.inject(AuthService) as jasmine.SpyObj
25 | router = TestBed.inject(Router) as jasmine.SpyObj
26 | })
27 |
28 | it('should redirect to login if canActivateProtectedRoutes$ emits false', (done) => {
29 | authService.canActivateProtectedRoutes$ = of(false)
30 |
31 | authGuard.canActivate({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot).subscribe((result) => {
32 | expect(result).toBe(false)
33 | expect(router.navigate).toHaveBeenCalledWith(['/login'])
34 | done()
35 | })
36 | })
37 |
38 | it('should allow activation if canActivateProtectedRoutes$ emits true', (done) => {
39 | authService.canActivateProtectedRoutes$ = of(true)
40 |
41 | authGuard.canActivate({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot).subscribe((result) => {
42 | expect(result).toBe(true)
43 | expect(router.navigate).not.toHaveBeenCalled()
44 | done()
45 | })
46 | })
47 | })
48 |
--------------------------------------------------------------------------------
/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | import { Component, OnInit, inject } from '@angular/core'
7 | import { Router, RouterModule } from '@angular/router'
8 | import { AuthService } from './auth.service'
9 | import { ToolbarComponent } from './core/toolbar/toolbar.component'
10 | import { NavbarComponent } from './core/navbar/navbar.component'
11 | import { MatSidenavModule } from '@angular/material/sidenav'
12 | import { TranslateModule, TranslateService } from '@ngx-translate/core'
13 | import { BidiModule, Direction } from '@angular/cdk/bidi'
14 | import { getDirection } from 'src/utils'
15 |
16 | @Component({
17 | selector: 'app-root',
18 | templateUrl: './app.component.html',
19 | styleUrls: ['./app.component.scss'],
20 | imports: [
21 | RouterModule,
22 | ToolbarComponent,
23 | NavbarComponent,
24 | MatSidenavModule,
25 | BidiModule,
26 | TranslateModule
27 | ]
28 | })
29 | export class AppComponent implements OnInit {
30 | // Dependency Injection
31 | private readonly router = inject(Router)
32 | private readonly authService = inject(AuthService)
33 | public readonly translate = inject(TranslateService)
34 | public direction: Direction = 'ltr'
35 | public isLoggedIn = false
36 |
37 | ngOnInit(): void {
38 | this.authService.loggedInSubject$.subscribe((value: any) => {
39 | this.isLoggedIn = value
40 | })
41 |
42 | this.translate.setFallbackLang('en')
43 | this.setDirection(this.translate.getCurrentLang())
44 |
45 | this.translate.onLangChange.subscribe((event) => {
46 | this.setDirection(event.lang)
47 | })
48 | }
49 |
50 | private setDirection(lang: string): void {
51 | this.direction = getDirection(lang)
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/cypress/e2e/integration/profile/delete.spec.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | // Tests the creation of a profile
7 | import { empty } from 'cypress/e2e/fixtures/api/general'
8 | import { httpCodes } from 'cypress/e2e/fixtures/api/httpCodes'
9 | import { profiles } from 'cypress/e2e/fixtures/api/profile'
10 | import { amtProfiles } from '../../fixtures/formEntry/profile'
11 |
12 | // ---------------------------- Test section ----------------------------
13 |
14 | describe('Test Profile Page', () => {
15 | beforeEach(() => {
16 | cy.setup()
17 | // Stub the requests
18 | cy.myIntercept('DELETE', /.*profiles.*/, {
19 | statusCode: httpCodes.NO_CONTENT
20 | }).as('delete-profile')
21 | cy.myIntercept('GET', 'profiles?$top=25&$skip=0&$count=true', {
22 | statusCode: httpCodes.SUCCESS,
23 | body: profiles.getAll.success.response
24 | }).as('get-profiles')
25 | cy.goToPage('Profiles')
26 | cy.wait('@get-profiles')
27 | })
28 |
29 | it('should not delete when cancelled', () => {
30 | // Delete profile (but cancel)
31 | cy.get('mat-cell').contains('delete').click()
32 | cy.get('button').contains('No').click()
33 | })
34 |
35 | amtProfiles.forEach((profile: any) => {
36 | it(`should delete ${profile.profileName as string}`, () => {
37 | cy.myIntercept('GET', 'profiles?$top=25&$skip=0&$count=true', {
38 | statusCode: httpCodes.SUCCESS,
39 | body: empty.response
40 | }).as('get-profiles4')
41 | // Delete profile
42 | cy.get('mat-row').contains(profile.profileName).parent().contains('delete').click()
43 | cy.get('button').contains('Yes').click()
44 | cy.wait('@delete-profile')
45 | cy.wait('@get-profiles4')
46 | })
47 | })
48 | })
49 |
--------------------------------------------------------------------------------
/cypress/e2e/integration/wireless/delete.spec.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | import { empty } from 'cypress/e2e/fixtures/api/general'
7 | import { httpCodes } from 'cypress/e2e/fixtures/api/httpCodes'
8 | import { wirelessConfigs } from 'cypress/e2e/fixtures/api/wireless'
9 | import { wirelessFixtures } from 'cypress/e2e/fixtures/formEntry/wireless'
10 |
11 | describe('test wireless profiles page', () => {
12 | beforeEach('clear cache and login', () => {
13 | cy.setup()
14 | })
15 |
16 | it('deletes the default profile', () => {
17 | cy.myIntercept('DELETE', /.*wirelessconfigs.*/, {
18 | statusCode: httpCodes.NO_CONTENT
19 | }).as('delete-profile')
20 | cy.myIntercept('GET', 'wirelessconfigs?$top=25&$skip=0&$count=true', {
21 | statusCode: httpCodes.SUCCESS,
22 | body: wirelessConfigs.getAll.success.response
23 | }).as('get-wireless')
24 |
25 | cy.goToPage('Wireless')
26 | cy.wait('@get-wireless')
27 |
28 | cy.get('mat-cell').contains('delete').click()
29 | cy.get('button').contains('No').click()
30 |
31 | cy.get('mat-cell').contains(wirelessFixtures.happyPath.profileName)
32 | cy.get('mat-cell').contains(wirelessFixtures.happyPath.authenticationMethod)
33 | cy.get('mat-cell').contains(wirelessFixtures.happyPath.encryptionMethod)
34 |
35 | cy.myIntercept('GET', 'wirelessconfigs?$top=25&$skip=0&$count=true', {
36 | statusCode: httpCodes.SUCCESS,
37 | body: empty.response
38 | }).as('get-wireless2')
39 |
40 | cy.get('mat-cell').contains('delete').click()
41 | cy.get('button').contains('Yes').click()
42 | cy.wait('@delete-profile')
43 | cy.wait('@get-wireless2')
44 |
45 | cy.contains(wirelessFixtures.happyPath.profileName).should('not.exist')
46 | })
47 | })
48 |
--------------------------------------------------------------------------------
/src/app/devices/tls/tls.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { ComponentFixture, TestBed } from '@angular/core/testing'
2 | import { TLSComponent } from './tls.component'
3 | import { DevicesService } from '../devices.service'
4 | import { MatSnackBar } from '@angular/material/snack-bar'
5 | import { of } from 'rxjs'
6 | import { MatCardModule } from '@angular/material/card'
7 | import { MatDividerModule } from '@angular/material/divider'
8 | import { TranslateModule } from '@ngx-translate/core'
9 |
10 | describe('TLSComponent', () => {
11 | let component: TLSComponent
12 | let fixture: ComponentFixture
13 | let mockDevicesService: any
14 | let mockSnackBar: any
15 | const mockTLSData = [{}, {}]
16 |
17 | beforeEach(() => {
18 | mockDevicesService = jasmine.createSpyObj('DevicesService', ['getTLSSettings'])
19 | mockSnackBar = jasmine.createSpyObj('MatSnackBar', ['open'])
20 |
21 | TestBed.configureTestingModule({
22 | imports: [
23 | MatCardModule,
24 | MatDividerModule,
25 | TLSComponent,
26 | TranslateModule.forRoot()
27 | ],
28 | providers: [
29 | { provide: DevicesService, useValue: mockDevicesService },
30 | { provide: MatSnackBar, useValue: mockSnackBar }
31 | ]
32 | })
33 | })
34 |
35 | beforeEach(() => {
36 | fixture = TestBed.createComponent(TLSComponent)
37 | component = fixture.componentInstance
38 |
39 | fixture.componentRef.setInput('deviceId', 'test-device-id')
40 | mockDevicesService.getTLSSettings.and.returnValue(of(mockTLSData))
41 | })
42 |
43 | it('should create the component', () => {
44 | expect(component).toBeTruthy()
45 | })
46 |
47 | it('should call getTLSSettings on ngOnInit and set tlsData', () => {
48 | component.ngOnInit()
49 |
50 | expect(mockDevicesService.getTLSSettings).toHaveBeenCalledWith('test-device-id')
51 | expect(component.tlsData).toEqual(mockTLSData)
52 | expect(component.isLoading()).toBeFalse()
53 | })
54 | })
55 |
--------------------------------------------------------------------------------
/src/app/devices/device-cert-dialog/device-cert-dialog.component.ts:
--------------------------------------------------------------------------------
1 | import { DatePipe } from '@angular/common'
2 | import { Component, inject } from '@angular/core'
3 | import { MatButtonModule } from '@angular/material/button'
4 | import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog'
5 | import { MatListModule } from '@angular/material/list'
6 | import { DevicesService } from '../devices.service'
7 | import { MatSnackBar } from '@angular/material/snack-bar'
8 | import SnackbarDefaults from 'src/app/shared/config/snackBarDefault'
9 | import { TranslateModule } from '@ngx-translate/core'
10 |
11 | @Component({
12 | selector: 'app-device-cert-dialog',
13 | imports: [
14 | MatDialogModule,
15 | MatButtonModule,
16 | MatListModule,
17 | DatePipe,
18 | TranslateModule
19 | ],
20 | templateUrl: './device-cert-dialog.component.html',
21 | styleUrl: './device-cert-dialog.component.scss'
22 | })
23 | export class DeviceCertDialogComponent {
24 | // Dependency Injection
25 | private readonly deviceService = inject(DevicesService)
26 | private readonly snackBar = inject(MatSnackBar)
27 | private readonly dialogData = inject(MAT_DIALOG_DATA)
28 | private readonly ref = inject(MatDialogRef)
29 | public data: any = {}
30 | public isPinned = false
31 |
32 | constructor() {
33 | const dialogData = this.dialogData
34 |
35 | this.data = dialogData.certData
36 | this.isPinned = dialogData.isPinned
37 | }
38 |
39 | pin(): void {
40 | this.deviceService.pinDeviceCertificate(this.data.guid, this.data.sha256Fingerprint).subscribe(() => {
41 | this.snackBar.open('Certificate pinned', 'Close', SnackbarDefaults.defaultSuccess)
42 | this.ref.close(true)
43 | })
44 | }
45 |
46 | remove(): void {
47 | this.deviceService.deleteDeviceCertificate(this.data.guid).subscribe(() => {
48 | this.snackBar.open('Certificate removed', 'Close', SnackbarDefaults.defaultSuccess)
49 | this.ref.close(false)
50 | })
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/app/devices/device-log.service.ts:
--------------------------------------------------------------------------------
1 | import { HttpClient } from '@angular/common/http'
2 | import { inject, Injectable } from '@angular/core'
3 | import { catchError, Observable, tap, of } from 'rxjs'
4 | import { environment } from 'src/environments/environment'
5 | import { AuditLogResponse, EventLog, EventLogResponse } from 'src/models/models'
6 |
7 | const DEFAULT_TOP = 0
8 | const DEFAULT_SKIP = 120
9 |
10 | @Injectable({
11 | providedIn: 'root'
12 | })
13 | export class DeviceLogService {
14 | private readonly http = inject(HttpClient)
15 |
16 | downloadAuditLog(deviceId: string): Observable {
17 | return this.http.get(`${environment.mpsServer}/api/v1/amt/log/audit/${deviceId}/download`, {
18 | responseType: 'blob'
19 | })
20 | }
21 |
22 | getAuditLog(deviceId: string, startIndex = 0): Observable {
23 | return this.http
24 | .get(`${environment.mpsServer}/api/v1/amt/log/audit/${deviceId}?startIndex=${startIndex}`)
25 | .pipe(
26 | catchError((err) => {
27 | throw err
28 | })
29 | )
30 | }
31 |
32 | downloadEventLog(deviceId: string): Observable {
33 | return this.http.get(`${environment.mpsServer}/api/v1/amt/log/event/${deviceId}/download`, {
34 | responseType: 'blob'
35 | })
36 | }
37 |
38 | getEventLog(
39 | deviceId: string,
40 | startIndex: number = DEFAULT_TOP,
41 | maxReadRecords: number = DEFAULT_SKIP
42 | ): Observable {
43 | const url = `${environment.mpsServer}/api/v1/amt/log/event/${deviceId}?$skip=${startIndex}&$top=${maxReadRecords}`
44 |
45 | return this.http.get(url).pipe(
46 | tap((response) => {
47 | if (environment.cloud) {
48 | response = { hasMoreRecords: false, records: response as unknown as EventLog[] } as EventLogResponse
49 | }
50 | return of(response)
51 | }),
52 | catchError((err) => {
53 | throw err
54 | })
55 | )
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/app/devices/audit-log/audit-log.component.spec.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | import { ComponentFixture, TestBed } from '@angular/core/testing'
7 | import { NoopAnimationsModule } from '@angular/platform-browser/animations'
8 | import { ActivatedRoute, RouterModule } from '@angular/router'
9 | import { of } from 'rxjs'
10 | import { AuditLogComponent } from './audit-log.component'
11 | import { DeviceLogService } from '../device-log.service'
12 | import { TranslateModule } from '@ngx-translate/core'
13 |
14 | describe('AuditLogComponent', () => {
15 | let component: AuditLogComponent
16 | let fixture: ComponentFixture
17 | let getAuditLogSpy: jasmine.Spy
18 |
19 | beforeEach(() => {
20 | const devicesService = jasmine.createSpyObj('DeviceLogService', ['getAuditLog'])
21 | getAuditLogSpy = devicesService.getAuditLog.and.returnValue(of({ totalCnt: 0, records: [] }))
22 |
23 | TestBed.configureTestingModule({
24 | imports: [
25 | NoopAnimationsModule,
26 | RouterModule,
27 | AuditLogComponent,
28 | TranslateModule.forRoot()
29 | ],
30 | providers: [
31 | { provide: DeviceLogService, useValue: devicesService },
32 | {
33 | provide: ActivatedRoute,
34 | useValue: {
35 | params: of({ id: 'guid' })
36 | }
37 | }
38 | ]
39 | })
40 | })
41 |
42 | beforeEach(() => {
43 | fixture = TestBed.createComponent(AuditLogComponent)
44 | component = fixture.componentInstance
45 | fixture.detectChanges()
46 | })
47 |
48 | afterEach(() => {
49 | TestBed.resetTestingModule()
50 | })
51 |
52 | it('should create', () => {
53 | expect(component).toBeTruthy()
54 | expect(getAuditLogSpy.calls.any()).toBe(true, 'getAuditLog called')
55 | })
56 | })
57 |
--------------------------------------------------------------------------------
/src/app/devices/alarms/alarms.component.spec.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | import { ComponentFixture, TestBed } from '@angular/core/testing'
7 |
8 | import { AlarmsComponent } from './alarms.component'
9 | import { DevicesService } from '../devices.service'
10 | import { provideNativeDateAdapter } from '@angular/material/core'
11 | import { of } from 'rxjs'
12 | import { NoopAnimationsModule } from '@angular/platform-browser/animations'
13 | import { TranslateModule } from '@ngx-translate/core'
14 |
15 | describe('AlarmsComponent', () => {
16 | let component: AlarmsComponent
17 | let fixture: ComponentFixture
18 | let devicesServiceSpy: jasmine.SpyObj
19 |
20 | beforeEach(() => {
21 | devicesServiceSpy = jasmine.createSpyObj('DevicesService', [
22 | 'getDevices',
23 | 'updateDevice',
24 | 'getAlarmOccurrences',
25 | 'getTags',
26 | 'getPowerState',
27 | 'getAMTVersion',
28 | 'getAMTFeatures',
29 | 'getGeneralSettings',
30 | 'PowerStates',
31 | 'sendPowerAction',
32 | 'bulkPowerAction',
33 | 'sendDeactivate',
34 | 'sendBulkDeactivate',
35 | 'getWsmanOperations'
36 | ])
37 |
38 | devicesServiceSpy.getAlarmOccurrences.and.returnValue(of([{ StartTime: {} } as any]))
39 | TestBed.configureTestingModule({
40 | imports: [
41 | NoopAnimationsModule,
42 | AlarmsComponent,
43 | TranslateModule.forRoot()
44 | ],
45 | providers: [provideNativeDateAdapter(), { provide: DevicesService, useValue: devicesServiceSpy }]
46 | })
47 |
48 | fixture = TestBed.createComponent(AlarmsComponent)
49 | component = fixture.componentInstance
50 | fixture.detectChanges()
51 | })
52 |
53 | it('should create', () => {
54 | expect(component).toBeTruthy()
55 | })
56 | })
57 |
--------------------------------------------------------------------------------
/src/app/devices/device-toolbar/http-boot-dialog/http-boot-dialog.component.html:
--------------------------------------------------------------------------------
1 |
2 | {{ 'devices.header.httpsBootTitle.value' | translate }}
3 |
4 |
5 | {{ 'devices.header.httpsBootDescription.value' | translate }}
6 |
32 |
33 |
34 |
35 |
38 |
39 |
--------------------------------------------------------------------------------
/src/app/devices/network-settings/network-settings.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit, inject, signal, input } from '@angular/core'
2 | import { DevicesService } from '../devices.service'
3 | import { MatCardModule } from '@angular/material/card'
4 | import { catchError, finalize, throwError } from 'rxjs'
5 | import { MatSnackBar } from '@angular/material/snack-bar'
6 | import SnackbarDefaults from 'src/app/shared/config/snackBarDefault'
7 | import { MatListModule } from '@angular/material/list'
8 | import { MatIcon } from '@angular/material/icon'
9 | import { MatDivider } from '@angular/material/divider'
10 | import { MatProgressBarModule } from '@angular/material/progress-bar'
11 | import { NetworkConfig } from 'src/models/models'
12 | import { TranslateModule, TranslateService } from '@ngx-translate/core'
13 |
14 | @Component({
15 | selector: 'app-network-settings',
16 | imports: [
17 | MatCardModule,
18 | MatListModule,
19 | MatDivider,
20 | MatIcon,
21 | MatProgressBarModule,
22 | TranslateModule
23 | ],
24 | templateUrl: './network-settings.component.html',
25 | styleUrl: './network-settings.component.scss'
26 | })
27 | export class NetworkSettingsComponent implements OnInit {
28 | // Dependency Injection
29 | private readonly snackBar = inject(MatSnackBar)
30 | private readonly devicesService = inject(DevicesService)
31 | private readonly translate = inject(TranslateService)
32 | public readonly deviceId = input('')
33 |
34 | public isLoading = signal(true)
35 | public networkResults?: NetworkConfig
36 |
37 | ngOnInit(): void {
38 | this.devicesService
39 | .getNetworkSettings(this.deviceId())
40 | .pipe(
41 | catchError((err) => {
42 | const msg: string = this.translate.instant('network.errorNetworkSetting.value')
43 | this.snackBar.open(msg, undefined, SnackbarDefaults.defaultError)
44 | return throwError(err)
45 | }),
46 | finalize(() => {
47 | this.isLoading.set(false)
48 | })
49 | )
50 | .subscribe((results) => {
51 | this.networkResults = results
52 | })
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/cypress/e2e/integration/cira/delete.spec.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | // Tests the creation of a cira-config
7 |
8 | import { httpCodes } from 'cypress/e2e/fixtures/api/httpCodes'
9 | import { ciraFixtures } from '../../fixtures//formEntry/cira'
10 | import { ciraConfig } from 'cypress/e2e/fixtures/api/cira'
11 | import { empty } from 'cypress/e2e/fixtures/api/general'
12 |
13 | // ---------------------------- Test section ----------------------------
14 |
15 | describe('Test CIRA Config Page', () => {
16 | beforeEach('Clear cache and login', () => {
17 | cy.setup()
18 | })
19 |
20 | it('deletes the default cira config', () => {
21 | cy.myIntercept('DELETE', /.*ciraconfigs.*/, {
22 | statusCode: httpCodes.NO_CONTENT
23 | }).as('delete-config')
24 |
25 | cy.myIntercept('GET', 'ciraconfigs?$top=25&$skip=0&$count=true', {
26 | statusCode: httpCodes.SUCCESS,
27 | body: ciraConfig.getAll.success.response
28 | }).as('get-configs')
29 |
30 | // Delete CIRA Config (but cancel)
31 | cy.goToPage('CIRA Configs')
32 | cy.wait('@get-configs')
33 |
34 | cy.get('mat-cell').contains('delete').click()
35 | cy.get('button').contains('No').click()
36 |
37 | // Check that the config was not deleted
38 | cy.get('mat-cell').contains(ciraFixtures.default.name)
39 | cy.get('mat-cell').contains(Cypress.env('FQDN'))
40 | cy.get('mat-cell').contains(Cypress.env('MPS_USERNAME'))
41 |
42 | // Change api response
43 | cy.myIntercept('GET', 'ciraconfigs?$top=25&$skip=0&$count=true', {
44 | statusCode: httpCodes.SUCCESS,
45 | body: empty.response
46 | }).as('get-configs')
47 |
48 | // Delete CIRA Config
49 | cy.get('mat-cell').contains('delete').click()
50 | cy.get('button').contains('Yes').click()
51 | cy.wait('@delete-config')
52 |
53 | // Check that the config was deleted properly
54 | cy.contains(ciraFixtures.default.name).should('not.exist')
55 | })
56 | })
57 |
--------------------------------------------------------------------------------
/src/app/core/navbar/navbar.component.spec.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | import { ComponentFixture, TestBed } from '@angular/core/testing'
7 | import { MatDividerModule } from '@angular/material/divider'
8 | import { MatIconModule } from '@angular/material/icon'
9 | import { MatListModule } from '@angular/material/list'
10 | import { NavbarComponent } from './navbar.component'
11 | import { ActivatedRoute, RouterModule } from '@angular/router'
12 | import { of } from 'rxjs'
13 | import { provideHttpClient } from '@angular/common/http'
14 | import { provideHttpClientTesting } from '@angular/common/http/testing'
15 | import { TranslateModule, TranslateService } from '@ngx-translate/core'
16 | import { TRANSLATE_HTTP_LOADER_CONFIG } from '@ngx-translate/http-loader'
17 |
18 | describe('NavbarComponent', () => {
19 | let component: NavbarComponent
20 | let fixture: ComponentFixture
21 | let translate: TranslateService
22 |
23 | beforeEach(() => {
24 | TestBed.configureTestingModule({
25 | imports: [
26 | MatIconModule,
27 | MatDividerModule,
28 | MatListModule,
29 | RouterModule,
30 | NavbarComponent,
31 | TranslateModule.forRoot()
32 | ],
33 | providers: [
34 | { provide: ActivatedRoute, useValue: { params: of({ id: 'guid' }) } },
35 | { provide: TRANSLATE_HTTP_LOADER_CONFIG, useValue: { prefix: '/assets/i18n/', suffix: '.json' } },
36 | TranslateService,
37 | provideHttpClient(),
38 | provideHttpClientTesting()
39 | ]
40 | })
41 | fixture = TestBed.createComponent(NavbarComponent)
42 | component = fixture.componentInstance
43 | translate = TestBed.inject(TranslateService)
44 | translate.setFallbackLang('en')
45 | fixture.detectChanges()
46 | })
47 |
48 | afterEach(() => {
49 | TestBed.resetTestingModule()
50 | })
51 |
52 | it('should create', () => {
53 | expect(component).toBeTruthy()
54 | })
55 | })
56 |
--------------------------------------------------------------------------------
/cypress/e2e/integration/domain/delete.spec.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | import { domains } from 'cypress/e2e/fixtures/api/domain'
7 | import { empty } from 'cypress/e2e/fixtures/api/general'
8 | import { httpCodes } from 'cypress/e2e/fixtures/api/httpCodes'
9 | import { domainFixtures } from 'cypress/e2e/fixtures/formEntry/domain'
10 |
11 | // ---------------------------- Test section ----------------------------
12 |
13 | describe('Test Domain Page', () => {
14 | beforeEach('before', () => {
15 | cy.setup()
16 | })
17 |
18 | it('deletes the default domain', () => {
19 | // Stub requests
20 | cy.myIntercept('DELETE', /.*domains.*/, {
21 | statusCode: httpCodes.NO_CONTENT,
22 | body: domains.delete.success.response
23 | }).as('delete-domain')
24 |
25 | cy.myIntercept('GET', 'domains?$top=25&$skip=0&$count=true', {
26 | statusCode: httpCodes.SUCCESS,
27 | body: domains.getAll.success.response
28 | }).as('get-domains3')
29 |
30 | cy.goToPage('Domains')
31 | cy.wait('@get-domains3')
32 |
33 | // Delete Domain (but cancel)
34 | cy.get('mat-cell').contains('delete').click()
35 | cy.get('button').contains('No').click()
36 |
37 | // Check that the domain was not deleted
38 | cy.get('mat-cell').contains(domainFixtures.default.profileName)
39 | cy.get('mat-cell').contains(Cypress.env('DOMAIN_SUFFIX'))
40 |
41 | // Change api response
42 | cy.myIntercept('GET', 'domains?$top=25&$skip=0&$count=true', {
43 | statusCode: httpCodes.SUCCESS,
44 | body: empty.response
45 | }).as('get-domains4')
46 |
47 | // Delete Domain
48 | cy.get('mat-cell').contains('delete').click()
49 | cy.get('button').contains('Yes').click()
50 | cy.wait('@delete-domain')
51 | cy.wait('@get-domains4')
52 |
53 | // Check that the Domain was deleted properly
54 | cy.contains(domainFixtures.default.profileName).should('not.exist')
55 | cy.contains(Cypress.env('DOMAIN_SUFFIX')).should('not.exist')
56 | })
57 | })
58 |
--------------------------------------------------------------------------------
/src/app/devices/audit-log/audit-log.component.html:
--------------------------------------------------------------------------------
1 | @if (isLoading()) {
2 |
3 | }
4 |
5 |
6 | {{ 'auditLog.title.value' | translate }} ({{ auditLogData.totalCnt }})
7 | @if (!isCloudMode) {
8 |
11 | }
12 |
13 |
14 | @if (isNoData()) {
15 | {{ 'auditLog.missing.value' | translate }}
16 | } @else {
17 |
18 |
19 |
20 | {{ 'auditLog.event.value' | translate }}
21 | {{ element.Event }}
22 |
23 | @if (!isCloudMode) {
24 |
25 |
26 | {{ 'auditLog.description.value' | translate }}
27 | {{ element.ExStr }}
28 |
29 | }
30 |
31 |
32 | {{ 'auditLog.time.value' | translate }}
33 |
34 | {{ element.Time | amDateFormatter: 'MMMM d, yyyy h:mma' }} ({{ element.Time | amTimeAgoFormatter: true }})
35 |
36 |
37 |
38 |
39 |
40 | }
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/cypress/e2e/fixtures/formEntry/cira.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | const ciraFixtures = {
7 | default: {
8 | name: 'happyPath',
9 | format: 'FQDN',
10 | addr: '192.168.8.50',
11 | port: '4433',
12 | username: 'standalone',
13 | password: 'G@ppm0ym'
14 | },
15 |
16 | wrong: {
17 | name: 'asdf -%^7',
18 | format: 'IPV4',
19 | ip: '12345',
20 | port: '3',
21 | username: 'stand alone',
22 | password: 'password'
23 | },
24 |
25 | MpsCertificate:
26 | '-----BEGIN CERTIFICATE-----\nMIIEOzCCAqOgAwIBAgIDA5h4MA0GCSqGSIb3DQEBDAUAMD0xFzAVBgNVBAMTDk1Q\nU1Jvb3QtN2ZjN2NhMRAwDgYDVQQKEwd1bmtub3duMRAwDgYDVQQGEwd1bmtub3du\nMCAXDTIwMDExODAxNDAxMloYDzIwNTEwMTE4MDE0MDEyWjA9MRcwFQYDVQQDEw5N\nUFNSb290LTdmYzdjYTEQMA4GA1UEChMHdW5rbm93bjEQMA4GA1UEBhMHdW5rbm93\nbjCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBAMEOeTOVcOY3bnJ6wLK+\ngc5U/to401ggiWugdqo4y5lfT0zLkM2VGjd2974Pm98OsKZj3cGp7E7t4gjmS5wo\nJzaxJ9HZmsy5radbSW1NYMwCMettnvtknt95uQUxdfO8hi0u2/fgA/CttQYI+87y\nAlQTkNRfkGrD5rCCL0jTpOFiOiM3yM0dLXPmIJs6t84Lyu0mWlLoITdBPBYVFkN6\nmshoK1zXEzkhlT9PiOKkLKeQJfLq8VVv+olv41TfTijyY3HV/Pk+Tn2IXpuC1EdC\nwuuWW1CKmYnM+BmY5h/PwoSMQzGzrjoAL+TDi1RNNIkr6oae95MNo5IMrG/VnFrx\nfKpELGjWr0Y3E2ETiwjt8Ztz2kAflg4OLZ692Kmc6JkP7PZFM2KmxPcHUXE/FmZp\nMPRNKUzc5HBkQD64p3Q1j+RAntqwtz5WzL93K8GEjzdDi2uthP5P+s1WvJnGxEb0\ndRFGyS31eTugIfdGr2zPtMydkYCAGYOyHX3kwMc5tyE6rwIDAQABo0IwQDAMBgNV\nHRMEBTADAQH/MBEGCWCGSAGG+EIBAQQEAwIABzAdBgNVHQ4EFgQUf8fK7M9m+9EH\nFm1yvoOWau391WEwDQYJKoZIhvcNAQEMBQADggGBAE/+K9xaf5Ib+OGGhvyU4NxM\nkQeNsB/7BxEARG8jJ3a1Wr0L0xaABI/7TQzxk+FEwCstm/Z8Qos8GrXtLrEcZONR\nZWLNdTH2itX9eYvx8uPLGP89ILnavivlbQ8DvFnV8EXXOaqz3zzIDzp+HxVumXSG\n/YZWbQjyDCzthD/zuhlvXJca9/pZtqxLkBfT0ZBAGxzpBl82KytF/+LRw/wGBiI2\nqNiHIp2nZUfvpYkBWtRzlVrvLzwlOGpdptkGgrmvjyJ25lllfDOOrizZpIsYVlgQ\nQtulx4EAn1ZuC0jPBxBrYqdkapFdNMY8LC1MMcnX75pfaRaus45WN/ds4JHOfw56\ndkJZs9gmpWSocTeWHL85d1vLVruviQU5pJHUw8QyvLuXRxZef9+8reyoGBnmEVqk\noDOUjCYq53fLPH4czcMsZfh0lWuZc8oSg+rLEfozbSvxBNn2zn7cnFiRWrbFz6hE\ni0IG+SRRxPly82In20v8J4mF1WntTZTYHyuRb/NO7Q==\n-----END CERTIFICATE-----'
27 | }
28 | export { ciraFixtures }
29 |
--------------------------------------------------------------------------------
/karma.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration file, see link for more information
2 | // https://karma-runner.github.io/1.0/config/configuration-file.html
3 |
4 | module.exports = function (config) {
5 | const isCI = process.env.CI || process.env.GITHUB_ACTIONS
6 |
7 | config.set({
8 | basePath: '',
9 | frameworks: ['jasmine', '@angular-devkit/build-angular'],
10 | plugins: [
11 | require('karma-jasmine'),
12 | require('karma-junit-reporter'),
13 | require('karma-chrome-launcher'),
14 | require('karma-jasmine-html-reporter'),
15 | require('karma-coverage'),
16 | require('@angular-devkit/build-angular/plugins/karma')
17 | ],
18 | client: {
19 | jasmine: {
20 | // you can add configuration options for Jasmine here
21 | // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
22 | // for example, you can disable the random execution with `random: false`
23 | // or set a specific seed with `seed: 4321`
24 | },
25 | clearContext: false // leave Jasmine Spec Runner output visible in browser
26 | },
27 | jasmineHtmlReporter: {
28 | suppressAll: true // removes the duplicated traces
29 | },
30 | coverageReporter: {
31 | dir: require('path').join(__dirname, './coverage/samplewebui'),
32 | subdir: '.',
33 | reporters: [
34 | { type: 'html' },
35 | { type: 'text-summary' },
36 | { type: 'lcov' }]
37 | },
38 | reporters: [
39 | 'progress',
40 | 'coverage',
41 | 'junit',
42 | 'kjhtml'
43 | ],
44 | customLaunchers: {
45 | ChromeHeadlessCI: {
46 | base: 'ChromeHeadless',
47 | flags: [
48 | '--no-sandbox',
49 | '--disable-gpu',
50 | '--disable-dev-shm-usage',
51 | '--disable-web-security'
52 | ]
53 | }
54 | },
55 | port: 9876,
56 | colors: true,
57 | logLevel: config.LOG_INFO,
58 | autoWatch: true,
59 | browsers: ['ChromeHeadless'],
60 | singleRun: false,
61 | restartOnFileChange: true,
62 | // CI-specific configurations
63 | ...(isCI && {
64 | browsers: ['ChromeHeadlessCI'],
65 | concurrency: 1,
66 | singleRun: true
67 | })
68 | })
69 | }
70 |
--------------------------------------------------------------------------------
/cypress/e2e/integration/wireless/create-error.spec.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | import { httpCodes } from '../../fixtures/api/httpCodes'
7 | import { wirelessFixtures } from '../../fixtures/formEntry/wireless'
8 | import { urlFixtures } from '../../fixtures/formEntry/urls'
9 | import { badRequest, empty } from 'cypress/e2e/fixtures/api/general'
10 | import * as api8021x from '../../fixtures/api/ieee8021x'
11 |
12 | const baseUrl: string = Cypress.env('BASEURL')
13 |
14 | describe('Test wireless creation page', () => {
15 | beforeEach('clear cache and login', () => {
16 | cy.setup()
17 | api8021x.interceptGetAll(httpCodes.SUCCESS, api8021x.wirelessConfigsResponse).as('intercept8021xGetAll')
18 | })
19 |
20 | beforeEach('Set up the api stubs', () => {
21 | cy.myIntercept('GET', 'wirelessconfigs?$top=25&$skip=0&$count=true', {
22 | statuscode: httpCodes.SUCCESS,
23 | body: empty.response
24 | }).as('get-wireless3')
25 |
26 | cy.myIntercept('POST', 'wirelessconfigs', {
27 | statusCode: httpCodes.BAD_REQUEST,
28 | body: badRequest.response
29 | }).as('post-wireless')
30 |
31 | cy.goToPage('Wireless')
32 | cy.wait('@get-wireless3')
33 |
34 | cy.get('button').contains('Add New').click()
35 | cy.wait('@intercept8021xGetAll')
36 | })
37 |
38 | it('invalid profile name', () => {
39 | cy.enterWirelessInfo(
40 | wirelessFixtures.wrong.profileName,
41 | Cypress.env('WIFI_SSID'),
42 | Cypress.env('WIFI_PSK_PASSPHRASE'),
43 | wirelessFixtures.happyPath.authenticationMethod,
44 | wirelessFixtures.happyPath.encryptionMethod
45 | )
46 | })
47 |
48 | afterEach('Check for error', () => {
49 | cy.get('button[type=submit]').click()
50 |
51 | // Wait for requests to finish and check their responses
52 | cy.wait('@post-wireless').its('response.statusCode').should('eq', httpCodes.BAD_REQUEST)
53 |
54 | // Check that the wireless config creation failed
55 | cy.url().should('eq', baseUrl + urlFixtures.page.wireless + '/' + urlFixtures.extensions.creation)
56 | })
57 | })
58 |
--------------------------------------------------------------------------------
/src/app/devices/explorer/explorer.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{ 'explorer.WSMANExplorer.value' | translate }}
4 |
5 |
6 | {{ 'explorer.WSMANCall.value' | translate }}
7 |
15 |
16 | @for (item of filteredOptions | async; track item) {
17 | {{ item }}
18 | }
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | {{ 'common.input.value' | translate }}
29 |
30 |
31 |
35 |
36 |
37 |
38 |
39 |
40 |
41 | {{ 'common.output.value' | translate }}
42 |
43 |
44 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/cypress/e2e/integration/wireless/create.spec.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | import { empty } from 'cypress/e2e/fixtures/api/general'
7 | import { httpCodes } from 'cypress/e2e/fixtures/api/httpCodes'
8 | import { wirelessConfigs } from 'cypress/e2e/fixtures/api/wireless'
9 | import { wirelessFixtures } from 'cypress/e2e/fixtures/formEntry/wireless'
10 |
11 | describe('create a wireless profile', () => {
12 | beforeEach('clear cache and login', () => {
13 | cy.setup()
14 | })
15 |
16 | it('creates a default profile', () => {
17 | cy.myIntercept('GET', 'wirelessconfigs?$count=true', {
18 | statusCode: httpCodes.SUCCESS,
19 | body: wirelessConfigs.getAll.success.response
20 | }).as('wirelessconfigsGetAll')
21 |
22 | cy.myIntercept('POST', 'wirelessconfigs', {
23 | statusCode: httpCodes.CREATED,
24 | body: wirelessConfigs.create.success.response
25 | }).as('post-wireless')
26 |
27 | cy.myIntercept('GET', 'wirelessconfigs?$top=25&$skip=0&$count=true', {
28 | statusCode: httpCodes.SUCCESS,
29 | body: empty.response
30 | }).as('get-wireless')
31 |
32 | cy.goToPage('Wireless')
33 | cy.wait('@get-wireless')
34 |
35 | // change api response
36 | cy.myIntercept('GET', 'wirelessconfigs?$top=25&$skip=0&$count=true', {
37 | statusCode: httpCodes.SUCCESS,
38 | body: wirelessConfigs.getAll.success.response
39 | }).as('get-wireless2')
40 |
41 | cy.get('button').contains('Add New').click()
42 | cy.enterWirelessInfo(
43 | wirelessFixtures.happyPath.profileName,
44 | Cypress.env('WIFI_SSID'),
45 | Cypress.env('WIFI_PSK_PASSPHRASE'),
46 | wirelessFixtures.happyPath.authenticationMethod,
47 | wirelessFixtures.happyPath.encryptionMethod
48 | )
49 | cy.get('button[type=submit]').click()
50 |
51 | cy.wait('@post-wireless').then((req) => {
52 | cy.wrap(req).its('response.statusCode').should('eq', httpCodes.CREATED)
53 |
54 | // Check that the wireless config was successful
55 | cy.get('mat-cell').contains(wirelessFixtures.happyPath.profileName)
56 | })
57 | })
58 | })
59 |
--------------------------------------------------------------------------------
/src/app/profiles/profiles.constants.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | import { FormOption } from 'src/models/models'
7 |
8 | export const ActivationModes: FormOption[] = [
9 | { value: 'acmactivate', label: 'profileDetail.activationModeAdmin.value' },
10 | { value: 'ccmactivate', label: 'profileDetail.activationModeClient.value' }
11 | ]
12 |
13 | export const UserConsentModes: FormOption[] = [
14 | { value: 'All', label: 'userConsentModes.all.value' },
15 | { value: 'KVM', label: 'userConsentModes.kvmOnly.value' },
16 | { value: 'None', label: 'userConsentModes.none.value' }
17 | ]
18 |
19 | export const TlsModes: FormOption[] = [
20 | { value: 1, label: 'tlsModes.serverAuthOnly.value' },
21 | { value: 2, label: 'tlsModes.serverAndNonTls.value' },
22 | { value: 3, label: 'tlsModes.mutualTlsOnly.value' },
23 | { value: 4, label: 'tlsModes.mutualAndNonTls.value' }
24 | ]
25 |
26 | export const TlsSigningAuthorities: FormOption[] = [
27 | { value: 'SelfSigned', label: 'tlsAuthorities.selfSigned.value' },
28 | { value: 'MicrosoftCA', label: 'tlsAuthorities.microsoftCA.value' }
29 | ]
30 |
31 | // unfortunately wifiConfigs is what the REST interface expects
32 | // even though not really a wireless config
33 | export interface WiFiConfig {
34 | profileName: string
35 | priority: number
36 | }
37 |
38 | export interface proxyConfig {
39 | priority: number
40 | name: string
41 | }
42 |
43 | export interface Profile {
44 | proxyConfigs?: proxyConfig[]
45 | profileName: string
46 | activation: string
47 | iderEnabled: boolean
48 | kvmEnabled: boolean
49 | solEnabled: boolean
50 | userConsent: string
51 | generateRandomPassword: boolean
52 | amtPassword?: string
53 | generateRandomMEBxPassword: boolean
54 | mebxPassword?: string
55 | dhcpEnabled: boolean
56 | ipSyncEnabled: boolean
57 | localWifiSyncEnabled: boolean
58 | ieee8021xProfileName?: string
59 | wifiConfigs?: WiFiConfig[]
60 | tags: string[]
61 | tlsMode?: number
62 | tlsSigningAuthority?: string
63 | ciraConfigName?: string
64 | version?: string
65 | uefiWifiSyncEnabled: boolean
66 | }
67 |
--------------------------------------------------------------------------------
/cypress/e2e/integration/ieee8021x/delete.spec.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | import { Config } from '../../../../src/app/ieee8021x/ieee8021x.constants'
7 | import { httpCodes } from '../../fixtures/api/httpCodes'
8 | import * as api8021x from '../../fixtures/api/ieee8021x'
9 | import { wiredConfigs, wirelessConfigs } from '../../fixtures/formEntry/ieee8021x'
10 |
11 | describe('Test IEEE 8021x Page', () => {
12 | beforeEach(() => {
13 | cy.setup()
14 | api8021x.interceptDelete(httpCodes.NO_CONTENT, null)
15 | })
16 |
17 | it('should not delete when cancelled', () => {
18 | api8021x
19 | .interceptGetAll(httpCodes.SUCCESS, { data: allConfigs, totalCount: allConfigs.length })
20 | .as('interceptGetAll')
21 | cy.goToPage('IEEE 802.1x')
22 | cy.wait('@interceptGetAll')
23 | cy.get('mat-cell').contains('delete').click()
24 | cy.get('button').contains('No').click()
25 | })
26 |
27 | const allConfigs = [...wiredConfigs, ...wirelessConfigs]
28 | const remainingConfigs = [...allConfigs]
29 |
30 | allConfigs.forEach((config) => {
31 | it(`should delete ${config.profileName}`, () => {
32 | const initialNavConfigs: Config[] = []
33 | for (const cfg of remainingConfigs) {
34 | initialNavConfigs.push(cfg)
35 | }
36 | let i = remainingConfigs.length
37 | while (i--) {
38 | if (remainingConfigs[i].profileName === config.profileName) {
39 | remainingConfigs.splice(i, 1)
40 | break
41 | }
42 | }
43 | api8021x
44 | .interceptGetAll(httpCodes.SUCCESS, { data: initialNavConfigs, totalCount: initialNavConfigs.length })
45 | .as('getAllNumber01')
46 | cy.goToPage('IEEE 802.1x')
47 | cy.wait('@getAllNumber01')
48 | api8021x
49 | .interceptGetAll(httpCodes.SUCCESS, { data: remainingConfigs, totalCount: remainingConfigs.length })
50 | .as('getAllNumber02')
51 | // Delete profile
52 | cy.get('mat-row').contains(config.profileName).parent().contains('delete').click()
53 | cy.get('button').contains('Yes').click()
54 | cy.wait('@getAllNumber02')
55 | })
56 | })
57 | })
58 |
--------------------------------------------------------------------------------
/src/app/dashboard/dashboard.component.spec.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | import { ComponentFixture, TestBed } from '@angular/core/testing'
7 | import { of } from 'rxjs'
8 | import { DevicesService } from '../devices/devices.service'
9 | import { DashboardComponent } from './dashboard.component'
10 | import { ActivatedRoute, RouterModule } from '@angular/router'
11 | import { provideHttpClient } from '@angular/common/http'
12 | import { TranslateModule, TranslateService } from '@ngx-translate/core'
13 | import { TRANSLATE_HTTP_LOADER_CONFIG } from '@ngx-translate/http-loader'
14 | import { provideHttpClientTesting } from '@angular/common/http/testing'
15 |
16 | describe('DashboardComponent', () => {
17 | let component: DashboardComponent
18 | let fixture: ComponentFixture
19 | let getStatsSpy: jasmine.Spy
20 | let translate: TranslateService
21 |
22 | beforeEach(async () => {
23 | const devicesService = jasmine.createSpyObj('DevicesService', ['getStats'])
24 |
25 | getStatsSpy = devicesService.getStats.and.returnValue(of({}))
26 | TestBed.configureTestingModule({
27 | imports: [
28 | RouterModule,
29 | DashboardComponent,
30 | TranslateModule.forRoot()
31 | ],
32 | providers: [
33 | { provide: DevicesService, useValue: devicesService },
34 | {
35 | provide: ActivatedRoute,
36 | useValue: {}
37 | },
38 | { provide: TRANSLATE_HTTP_LOADER_CONFIG, useValue: { prefix: '/assets/i18n/', suffix: '.json' } },
39 | TranslateService,
40 | provideHttpClient(),
41 | provideHttpClientTesting()
42 | ]
43 | })
44 | })
45 |
46 | beforeEach(() => {
47 | fixture = TestBed.createComponent(DashboardComponent)
48 | component = fixture.componentInstance
49 | translate = TestBed.inject(TranslateService)
50 | translate.setFallbackLang('en')
51 | fixture.detectChanges()
52 | })
53 |
54 | afterEach(() => {
55 | TestBed.resetTestingModule()
56 | })
57 |
58 | it('should create', () => {
59 | expect(component).toBeTruthy()
60 | expect(getStatsSpy).toHaveBeenCalled()
61 | })
62 | })
63 |
--------------------------------------------------------------------------------
/cypress/e2e/integration/cira/create-error.spec.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | // Tests the creation of a cira-config
7 |
8 | import { badRequest, empty } from 'cypress/e2e/fixtures/api/general'
9 | import { httpCodes } from 'cypress/e2e/fixtures/api/httpCodes'
10 | import { ciraFixtures } from '../../fixtures/formEntry/cira'
11 | import { urlFixtures } from '../../fixtures/formEntry/urls'
12 | const baseUrl: string = Cypress.env('BASEURL')
13 |
14 | // ---------------------------- Test section ----------------------------
15 |
16 | describe('Test CIRA Config Page', () => {
17 | beforeEach('Clear cache and login', () => {
18 | cy.setup()
19 | })
20 |
21 | beforeEach('fills out the config', () => {
22 | cy.myIntercept('GET', 'ciracert', {
23 | statusCode: httpCodes.SUCCESS,
24 | body: ciraFixtures.MpsCertificate
25 | }).as('certificate1')
26 |
27 | cy.intercept('POST', 'ciraconfigs', {
28 | statusCode: httpCodes.BAD_REQUEST,
29 | body: badRequest.response
30 | }).as('post-config1')
31 |
32 | cy.intercept('GET', 'ciraconfigs?$top=25&$skip=0&$count=true', {
33 | statusCode: httpCodes.SUCCESS,
34 | body: empty.response
35 | }).as('get-configs')
36 |
37 | cy.goToPage('CIRA Configs')
38 | cy.wait('@get-configs')
39 |
40 | cy.get('button').contains('Add New').click()
41 | })
42 |
43 | it('invalid config name', () => {
44 | cy.enterCiraInfo(
45 | ciraFixtures.wrong.name,
46 | ciraFixtures.default.format,
47 | ciraFixtures.default.addr,
48 | Cypress.env('MPS_USERNAME')
49 | )
50 | })
51 |
52 | it('invalid username', () => {
53 | cy.enterCiraInfo(
54 | ciraFixtures.wrong.name,
55 | ciraFixtures.default.format,
56 | ciraFixtures.default.addr,
57 | ciraFixtures.wrong.username
58 | )
59 | })
60 |
61 | afterEach('Check that the error occured', () => {
62 | cy.get('button[type=submit]').click()
63 |
64 | cy.wait('@certificate1')
65 | cy.wait('@post-config1').its('response.statusCode').should('eq', 400)
66 |
67 | const url = baseUrl + urlFixtures.page.cira + '/' + urlFixtures.extensions.creation
68 | cy.url().should('eq', url)
69 | })
70 | })
71 |
--------------------------------------------------------------------------------
/.github/workflows/cypress.yaml:
--------------------------------------------------------------------------------
1 | # This workflow will do a clean install of node dependencies, build the sample web ui in a docker container and run tests on the ui isolated from mps and rps
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
3 |
4 | name: Cypress CI
5 |
6 | on:
7 | push:
8 | branches: [main]
9 | pull_request:
10 | branches: [main]
11 | workflow_dispatch:
12 | permissions:
13 | contents: read
14 | actions: read
15 |
16 | jobs:
17 | build:
18 | permissions:
19 | contents: read
20 | actions: read
21 | checks: write
22 |
23 | runs-on: ubuntu-latest
24 |
25 | strategy:
26 | matrix:
27 | node-version: [20.x]
28 |
29 | steps:
30 | - name: Harden Runner
31 | uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
32 | with:
33 | egress-policy: audit
34 |
35 | - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
36 | - name: Use Node.js ${{ matrix.node-version }}
37 | uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
38 | with:
39 | node-version: ${{ matrix.node-version }}
40 | - run: npm install cypress
41 | - run: docker build . --file Dockerfile --tag vprodemo.azurecr.ui/samplewebui:latest
42 | - run: docker run -d -p 4200:80 vprodemo.azurecr.ui/samplewebui:latest
43 | - run: npm run cy-runner
44 | - name: Publish Cypress Test Results
45 | uses: dorny/test-reporter@fe45e9537387dac839af0d33ba56eed8e24189e8 # v2.3.0
46 | if: always()
47 | with:
48 | name: Cypress Tests
49 | path: cypress-ui-test-output-*.xml
50 | reporter: java-junit
51 | fail-on-error: false
52 | - name: Upload Cypress UI Test Results
53 | uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
54 | if: always()
55 | with:
56 | name: sample-web-ui-ui-test
57 | path: cypress-ui-test-output-*.xml
58 | - name: Upload Cypress UI Images
59 | uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
60 | if: always()
61 | with:
62 | name: sample-web-ui-ui-test-screenshots
63 | path: /home/runner/work/sample-web-ui/sample-web-ui/cypress/screenshots/**/*.png
64 |
--------------------------------------------------------------------------------
/src/app/event-channel/event-channel.component.spec.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | // import { ComponentFixture, TestBed } from '@angular/core/testing'
7 | // import { BrowserAnimationsModule } from '@angular/platform-browser/animations'
8 | // // // import { EventChannelComponent } from './event-channel.component'
9 | // import { MQTTService } from './event-channel.service'
10 | // import { of } from 'rxjs'
11 |
12 | // describe('EventChannelComponent', () => {
13 | // let component: EventChannelComponent
14 | // let fixture: ComponentFixture
15 | // const eventChannelStub = {
16 | // mqttConfig: { hostname: 'test', port: '', path: 'test' },
17 | // connect: jasmine.createSpy('connect'),
18 | // subscribeToTopic: jasmine.createSpy('connect'),
19 | // messageSource: of(),
20 | // connectionStatusSubject: of(),
21 | // changeConnection: jasmine.createSpy('changeConnection'),
22 | // destroy: jasmine.createSpy('destroy')
23 | // }
24 | // beforeEach(async () => {
25 | // await TestBed.configureTestingModule({
26 | // imports: [BrowserAnimationsModule, RouterModule],
27 | // declarations: [EventChannelComponent],
28 | // providers: [{ provide: MQTTService, useValue: eventChannelStub }]
29 | // }).compileComponents()
30 | // })
31 |
32 | // beforeEach(() => {
33 | // fixture = TestBed.createComponent(EventChannelComponent)
34 | // component = fixture.componentInstance
35 | // fixture.detectChanges()
36 | // })
37 |
38 | // afterEach(() => {
39 | // TestBed.resetTestingModule()
40 | // })
41 |
42 | // it('should create', () => {
43 | // expect(component).toBeTruthy()
44 | // })
45 |
46 | // it('should call onSubmit', async () => {
47 | // component.onSubmit()
48 | // component.eventChannelService.changeConnection(component.eventChannelForm.value)
49 | // expect(component.eventChannelService.changeConnection).toHaveBeenCalled()
50 | // })
51 |
52 | // it('should test noData', () => {
53 | // component.dataSource.data = [{ message: 'Sent domains', methods: ['getAllDomains'], timestamp: 1634026109505, type: 'success' }]
54 | // expect(component.dataSource.data.length).toBe(1)
55 | // })
56 | // })
57 |
--------------------------------------------------------------------------------
/src/app/devices/certificates/add-cert-dialog/add-cert-dialog.component.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2025
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 | import { ChangeDetectorRef, Component, inject } from '@angular/core'
6 | import { MatSelectModule } from '@angular/material/select'
7 | import { FormsModule } from '@angular/forms'
8 | import { MatDialogContent, MatDialogActions, MatDialogRef, MatDialogModule } from '@angular/material/dialog'
9 | import { MatCardModule } from '@angular/material/card'
10 | import { MatButtonModule } from '@angular/material/button'
11 | import { CertInfo } from 'src/models/models'
12 | import { MatCheckboxModule } from '@angular/material/checkbox'
13 | import { MatIconModule } from '@angular/material/icon'
14 | import { TranslatePipe } from '@ngx-translate/core'
15 |
16 | @Component({
17 | selector: 'app-add-cert-dialog',
18 | imports: [
19 | MatDialogModule,
20 | MatDialogContent,
21 | MatDialogActions,
22 | MatSelectModule,
23 | MatButtonModule,
24 | FormsModule,
25 | MatCardModule,
26 | MatCheckboxModule,
27 | MatIconModule,
28 | TranslatePipe
29 | ],
30 | templateUrl: './add-cert-dialog.component.html',
31 | styleUrl: './add-cert-dialog.component.scss'
32 | })
33 | export class AddCertDialogComponent {
34 | private readonly dialogRef = inject(MatDialogRef)
35 | private readonly cdr = inject(ChangeDetectorRef)
36 |
37 | certInfo: CertInfo = {
38 | cert: '',
39 | isTrusted: false
40 | }
41 |
42 | onFileSelected(e: Event): void {
43 | if (typeof FileReader !== 'undefined') {
44 | const reader = new FileReader()
45 |
46 | reader.onload = (e2: ProgressEvent) => {
47 | const base64: string = e2.target?.result as string
48 | const index: number = base64.indexOf('base64,')
49 | const cert = base64.substring(index + 7, base64.length)
50 | this.certInfo.cert = cert
51 | this.cdr.detectChanges()
52 | }
53 | if (e.target != null) {
54 | const target = e.target as HTMLInputElement
55 | const files = target.files
56 | if (files != null && files.length > 0) {
57 | reader.readAsDataURL(files[0])
58 | }
59 | }
60 | }
61 | }
62 |
63 | onCancel(): void {
64 | this.dialogRef.close()
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/cypress/e2e/integration/domain/create.spec.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | import { domains } from 'cypress/e2e/fixtures/api/domain'
7 | import { empty } from 'cypress/e2e/fixtures/api/general'
8 | import { httpCodes } from 'cypress/e2e/fixtures/api/httpCodes'
9 | import { domainFixtures } from 'cypress/e2e/fixtures/formEntry/domain'
10 |
11 | // ---------------------------- Test section ----------------------------
12 |
13 | describe('Test Domain Page', () => {
14 | beforeEach('before', () => {
15 | cy.setup()
16 | })
17 |
18 | it('creates the default domain with cert from fixture file upload', () => {
19 | // Stub the get and post requests
20 | cy.myIntercept('GET', 'domains?$top=25&$skip=0&$count=true', {
21 | statusCode: httpCodes.SUCCESS,
22 | body: empty.response
23 | }).as('get-domains')
24 |
25 | cy.myIntercept('POST', 'domains', {
26 | statusCode: httpCodes.CREATED,
27 | body: domains.create.success.response
28 | }).as('post-domain')
29 |
30 | cy.goToPage('Domains')
31 | cy.wait('@get-domains')
32 |
33 | // Fill out the profile
34 | cy.get('button').contains('Add New').click({ force: true })
35 | // Change api response
36 | cy.myIntercept('GET', 'domains?$top=25&$skip=0&$count=true', {
37 | statusCode: httpCodes.SUCCESS,
38 | body: domains.getAll.success.response
39 | }).as('get-domains2')
40 |
41 | // handle file on disk or in-memory file
42 | const certFixtureData: Cypress.FileReference = {
43 | fileName: 'test-cert.pfx',
44 | contents: Cypress.Buffer.from(Cypress.env('PROVISIONING_CERT'), 'base64')
45 | }
46 |
47 | cy.enterDomainInfo(
48 | domainFixtures.default.profileName,
49 | Cypress.env('DOMAIN_SUFFIX'),
50 | certFixtureData,
51 | Cypress.env('PROVISIONING_CERT_PASSWORD')
52 | )
53 | cy.get('button').contains('SAVE').click({ force: true })
54 | cy.wait('@post-domain').its('response.statusCode').should('eq', httpCodes.CREATED)
55 | cy.wait('@get-domains2').its('response.statusCode').should('eq', httpCodes.SUCCESS)
56 | // Check that the config was successful
57 | cy.get('mat-cell').contains(domainFixtures.default.profileName)
58 | cy.get('mat-cell').contains(Cypress.env('DOMAIN_SUFFIX'))
59 | })
60 | })
61 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | #*********************************************************************
2 | # Copyright (c) Intel Corporation 2023
3 | # SPDX-License-Identifier: Apache-2.0
4 | #*********************************************************************/
5 |
6 | # This workflow will release new versions when required using semantic-release
7 |
8 | name: Semantic-Release CI
9 |
10 | on:
11 | push:
12 | branches: [main]
13 |
14 | permissions:
15 | contents: read
16 |
17 | jobs:
18 | release:
19 | permissions:
20 | contents: write # for Git to git push
21 | runs-on: ubuntu-latest
22 |
23 | steps:
24 | - name: Harden Runner
25 | uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
26 | with:
27 | egress-policy: audit
28 |
29 | - name: Checkout
30 | uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
31 | with:
32 | persist-credentials: false
33 | - name: Use Node.js 20.x
34 | uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
35 | with:
36 | node-version: '20.x'
37 | - name: Docker Setup Buildx
38 | uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
39 | - run: npm ci
40 | - run: npm run build
41 | - name: Docker Login
42 | uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
43 | with:
44 | registry: vprodemo.azurecr.io
45 | username: ${{ secrets.DOCKER_USERNAME }}
46 | password: ${{ secrets.DOCKER_PASSWORD }}
47 | logout: true
48 | - name: Docker Login DockerHub
49 | uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
50 | with:
51 | registry: docker.io
52 | username: ${{ secrets.INTC_DOCKER_USERNAME }}
53 | password: ${{ secrets.INTC_DOCKER_PASSWORD }}
54 | logout: true
55 | - name: Semantic Release
56 | uses: cycjimmy/semantic-release-action@b12c8f6015dc215fe37bc154d4ad456dd3833c90 # v6.0.0
57 | with:
58 | semantic_version:
59 | 19.0.5 # It is recommended to specify a version range
60 | # for semantic-release when using
61 | # semantic-release-action lower than @v3
62 | extra_plugins: |
63 | @semantic-release/exec@6.0.3
64 | env:
65 | GITHUB_TOKEN: ${{ secrets.ROSIE_TOKEN }}
66 |
--------------------------------------------------------------------------------
/src/app/core/navbar/navbar.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | home
9 | {{ 'dashboard.header.dashboardTitle.value' | translate }}
10 |
11 |
12 |
13 | security
14 | {{ 'ieee8021x.headerd.ieeeTitle.value' | translate }}
15 |
16 |
17 | wifi{{ 'wireless.header.wirelessTitle.value' | translate }}
19 |
20 |
26 | settings_ethernet{{ 'configs.header.ciraTitle.value' | translate }}
28 |
29 | @if (cloudMode === true) {
30 |
31 | router{{ 'proxyConfigs.header.proxyTitle.value' | translate }}
33 |
34 | }
35 |
36 |
37 | settings_system_daydream{{ 'profiles.header.profileTitle.value' | translate }}
39 |
40 |
41 | http{{ 'domains.header.domainsTitle.value' | translate }}
43 |
44 |
45 |
46 | devices{{ 'devices.headerd.devicesTitle.value' | translate }}
48 |
49 |
52 |
53 |
--------------------------------------------------------------------------------
/src/app/shared/add-device/add-device.component.html:
--------------------------------------------------------------------------------
1 | {{ 'addDevice.title.value' | translate }}
2 |
3 |
4 |
{{ 'addDevice.description.value' | translate }}
5 |
6 |
61 |
62 |
--------------------------------------------------------------------------------
/src/app/devices/tls/tls.component.html:
--------------------------------------------------------------------------------
1 | @if (isLoading()) {
2 |
3 | }
4 |
5 |
6 |
7 | {{ 'tls.title.value' | translate }}
8 |
9 |
10 |
11 |
12 | @for (setting of tlsData; track $index) {
13 |
14 |
{{ 'tls.elementName.label.value' | translate }}
15 |
16 |
17 | {{ setting.ElementName }}
18 |
19 |
20 |
{{ 'tls.instanceId.label.value' | translate }}
21 |
22 |
23 | {{ setting.InstanceID }}
24 |
25 |
26 |
{{ 'tls.mutualAuth.label.value' | translate }}
27 |
28 |
29 | {{
30 | setting.MutualAuthentication ? ('common.yes.value' | translate) : ('common.no.value' | translate)
31 | }}
32 |
33 |
34 |
{{ 'tls.enabled.label.value' | translate }}
35 |
36 |
37 | {{
38 | setting.Enabled ? ('common.yes.value' | translate) : ('common.no.value' | translate)
39 | }}
40 |
41 |
42 |
{{ 'tls.acceptNonSecure.label.value' | translate }}
43 |
44 |
45 | {{
46 | setting.AcceptNonSecureConnections ? ('common.yes.value' | translate) : ('common.no.value' | translate)
47 | }}
48 |
49 |
50 |
{{ 'tls.nonSecureSupported.label.value' | translate }}
51 |
52 |
53 | {{
54 | setting.NonSecureConnectionsSupported ? ('common.yes.value' | translate) : ('common.no.value' | translate)
55 | }}
56 |
57 |
58 | }
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/cypress/README.md:
--------------------------------------------------------------------------------
1 | # Cypress UI Validation Tool
2 |
3 | Visit the [documentation for Cypress](https://docs.cypress.io/guides/overview/why-cypress) for an in-depth look of all cypress features
4 |
5 | ## How to use
6 |
7 | ### Locally
8 |
9 | First spin up a local instance of the sample web ui using `npm run start`
10 |
11 | > You may need to configure `device-management-toolkit/docker-compose.yml` to prevent network errors
12 |
13 | Once the server is up on `http://localhost:4200/`, open a new terminal and run `npm run cypress`. This will start the cypress testing gui.
14 |
15 |
16 |
17 | From here you can choose to run any of the test cases stored in the integration folder.
18 |
19 | ### Through GitHub Actions
20 |
21 | In github click on the `Actions` tab and choose the `Cypress CI` workflow. Now simply click `Run workflow` and choose the branch you wish to test. This will spin up a container to run through all the UI tests in the integration folder sequentially and return a log reporting if the tests were successful or not. To change how this action is triggered or what it runs, go to `sample-web-ui/.github/workflows/cypress.yml`.
22 |
23 | ## Code Layout
24 |
25 | The core groupings of code within this cypress project are tests, fixtures, commands and enviornment variables.
26 |
27 | ### Tests
28 |
29 | `sample-web-ui/cypress/integartion/*.spec.js`
30 | This is where all of the test cases are stored. Currently each page of the ui has its own test file, which goes through a happy path use case of that page.
31 |
32 | ### Fixtures
33 |
34 | `sample-web-ui/cypress/fixtures/*.json`
35 | This is where data for filling out certain fields, verfiying urls and mocking api responses is stored.
36 |
37 | ### Commands
38 |
39 | `sample-web-ui/cypress/support/commands.js`
40 | This is where new functions can be added to cypress to help reduce redundancy within test cases. See [documentation](https://docs.cypress.io/api/cypress-api/custom-commands) for more information on this feature.
41 |
42 | ### Environment Variables
43 |
44 | `sample-web-ui/cypress.json`
45 | This is where important variables such as the base url of the server, passwords and whether cypress should mock api reponses are stored. You can add a new variable and call it in a test case with `Cypress.env("VARIABLE_NAME")`. If you wish to change an environment variable for a single instance of cypress, you can run `npm run cypress -- --env VAR_NAME=VALUE,VAR_NAME2=VALUE2` instead of the usual command.
46 |
--------------------------------------------------------------------------------
/src/app/devices/general/general.component.spec.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | import { ComponentFixture, TestBed } from '@angular/core/testing'
7 |
8 | import { GeneralComponent } from './general.component'
9 | import { ActivatedRoute } from '@angular/router'
10 | import { of } from 'rxjs'
11 | import { DevicesService } from '../devices.service'
12 | import { TranslateModule } from '@ngx-translate/core'
13 |
14 | describe('GeneralComponent', () => {
15 | let component: GeneralComponent
16 | let fixture: ComponentFixture
17 | let devicesServiceSpy: jasmine.SpyObj
18 |
19 | beforeEach(() => {
20 | devicesServiceSpy = jasmine.createSpyObj('DevicesService', [
21 | 'getDevices',
22 | 'updateDevice',
23 | 'getTags',
24 | 'getPowerState',
25 | 'getAMTVersion',
26 | 'getAMTFeatures',
27 | 'getGeneralSettings',
28 | 'PowerStates',
29 | 'sendPowerAction',
30 | 'bulkPowerAction',
31 | 'sendDeactivate',
32 | 'sendBulkDeactivate',
33 | 'getWsmanOperations'
34 | ])
35 | devicesServiceSpy.getAMTFeatures.and.returnValue(
36 | of({
37 | userConsent: 'ALL',
38 | KVM: true,
39 | SOL: true,
40 | IDER: true,
41 | redirection: true,
42 | optInState: 1,
43 | kvmAvailable: true,
44 | httpsBootSupported: true,
45 | ocr: true,
46 | winREBootSupported: true,
47 | localPBABootSupported: true,
48 | remoteErase: true,
49 | pbaBootFilesPath: [],
50 | winREBootFilesPath: {
51 | instanceID: '',
52 | biosBootString: '',
53 | bootString: ''
54 | }
55 | })
56 | )
57 | devicesServiceSpy.getGeneralSettings.and.returnValue(of({}))
58 | devicesServiceSpy.getAMTVersion.and.returnValue(of(['']))
59 | TestBed.configureTestingModule({
60 | imports: [GeneralComponent, TranslateModule.forRoot()],
61 | providers: [
62 | { provide: ActivatedRoute, useValue: { params: of({ id: 1 }) } },
63 | { provide: DevicesService, useValue: devicesServiceSpy }
64 | ]
65 | })
66 |
67 | fixture = TestBed.createComponent(GeneralComponent)
68 | component = fixture.componentInstance
69 | fixture.detectChanges()
70 | })
71 |
72 | it('should create', () => {
73 | expect(component).toBeTruthy()
74 | })
75 | })
76 |
--------------------------------------------------------------------------------
/cypress/e2e/integration/device/device.spec.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | // Tests the creation of a profile
7 | import { httpCodes } from '../../fixtures/api/httpCodes'
8 | import { devices } from '../../fixtures/api/device'
9 | import { tags } from 'cypress/e2e/fixtures/api/tags'
10 |
11 | // ---------------------------- Test section ----------------------------
12 |
13 | describe('Test Device Page', () => {
14 | beforeEach('', () => {
15 | cy.setup()
16 |
17 | cy.myIntercept('GET', /tags$/, {
18 | statusCode: httpCodes.SUCCESS,
19 | body: tags.getAll.success.response
20 | }).as('get-tags')
21 |
22 | cy.myIntercept('GET', 'devices?$top=25&$skip=0&$count=true', {
23 | statusCode: httpCodes.SUCCESS,
24 | body: devices.getAll.success.response
25 | }).as('get-devices')
26 |
27 | cy.myIntercept('GET', /.*power.*/, {
28 | statusCode: httpCodes.SUCCESS,
29 | body: { powerState: 2 }
30 | }).as('get-powerstate')
31 | })
32 |
33 | it('loads all the devices', () => {
34 | cy.goToPage('Devices')
35 | cy.wait('@get-devices').its('response.statusCode').should('eq', 200)
36 | cy.wait('@get-powerstate').its('response.statusCode').should('eq', 200)
37 | })
38 |
39 | // UI Only
40 | it('filters for windows devices', () => {
41 | if (Cypress.env('ISOLATE').charAt(0).toLowerCase() !== 'n') {
42 | cy.myIntercept('GET', '**/devices?tags=Windows&$top=25&$skip=0&$count=true', {
43 | statusCode: httpCodes.SUCCESS,
44 | body: devices.getAll.windows.response.data
45 | }).as('get-windows')
46 |
47 | cy.goToPage('Devices')
48 | cy.wait('@get-tags')
49 | cy.wait('@get-devices')
50 |
51 | // Filter for Windows devices
52 | cy.get('[data-cy="filterTags"]').click()
53 |
54 | cy.contains('mat-option', 'Windows').click()
55 |
56 | cy.wait('@get-windows').its('response.statusCode').should('eq', 200)
57 |
58 | // Remove Filter for Windows devices
59 | cy.contains('mat-option', 'Windows').click()
60 | cy.wait('@get-devices').its('response.statusCode').should('eq', 200)
61 | }
62 | })
63 |
64 | it('selects the first device', () => {
65 | cy.goToPage('Devices')
66 | cy.wait('@get-devices').its('response.statusCode').should('eq', 200)
67 | cy.wait('@get-tags').its('response.statusCode').should('eq', 200)
68 |
69 | cy.get('mat-table mat-row:first').click()
70 | })
71 | })
72 |
--------------------------------------------------------------------------------
/src/app/dashboard/dashboard.component.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | import { Component, OnInit, inject, signal } from '@angular/core'
7 | import { MatSnackBar } from '@angular/material/snack-bar'
8 | import { throwError } from 'rxjs'
9 | import { catchError, finalize } from 'rxjs/operators'
10 | import { DeviceStats } from 'src/models/models'
11 | import { DevicesService } from '../devices/devices.service'
12 | import SnackbarDefaults from '../shared/config/snackBarDefault'
13 | import { RouterLink } from '@angular/router'
14 | import { MatIconButton } from '@angular/material/button'
15 | import { MatTooltip } from '@angular/material/tooltip'
16 | import { MatDivider } from '@angular/material/divider'
17 | import { MatIcon } from '@angular/material/icon'
18 | import { MatCard } from '@angular/material/card'
19 | import { MatProgressBar } from '@angular/material/progress-bar'
20 | import { environment } from 'src/environments/environment'
21 | import { TranslateModule, TranslateService } from '@ngx-translate/core'
22 |
23 | @Component({
24 | selector: 'app-dashboard',
25 | templateUrl: './dashboard.component.html',
26 | styleUrls: ['./dashboard.component.scss'],
27 | imports: [
28 | MatProgressBar,
29 | MatCard,
30 | MatIcon,
31 | MatDivider,
32 | MatTooltip,
33 | MatIconButton,
34 | RouterLink,
35 | TranslateModule
36 | ]
37 | })
38 | export class DashboardComponent implements OnInit {
39 | // Dependency Injection
40 | private readonly snackBar = inject(MatSnackBar)
41 | private readonly devicesService = inject(DevicesService)
42 | private readonly translate = inject(TranslateService)
43 | public cloudMode = environment.cloud
44 | public isLoading = signal(true)
45 | public stats?: DeviceStats
46 |
47 | ngOnInit(): void {
48 | this.isLoading.set(true)
49 | this.devicesService
50 | .getStats()
51 | .pipe(
52 | catchError((err) => {
53 | // TODO: handle error better
54 | const msg: string = this.translate.instant('dashboard.error.value')
55 |
56 | this.snackBar.open(msg, undefined, SnackbarDefaults.defaultError)
57 | return throwError(err)
58 | }),
59 | finalize(() => {
60 | this.isLoading.set(false)
61 | })
62 | )
63 | .subscribe((data) => {
64 | this.stats = data
65 | })
66 | }
67 |
68 | navigateTo(url: string): void {
69 | window.open(url, '_blank')
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/app/devices/certificates/certificates.component.html:
--------------------------------------------------------------------------------
1 | @if (isLoading()) {
2 |
3 | }
4 |
5 |
6 |
7 | {{ 'certificates.title.value' | translate }}
8 | {{ 'certificates.list.value' | translate }}
9 |
10 |
13 |
14 |
15 |
16 | @if (isLoading()) {
17 | {{ 'certificates.loading.value' | translate }}
18 | } @else if (isCertEmpty()) {
19 | {{ 'certificates.empty.value' | translate }}
20 | } @else {
21 | @for (cert of certInfo.certificates?.publicKeyCertificateItems; track cert) {
22 |
23 | {{ cert.displayName }}
24 |
25 | {{ 'certificates.type.value' | translate }}:
26 | {{
27 | cert.trustedRootCertificate
28 | ? ('certificates.typeRoot.value' | translate)
29 | : ('certificates.typeClient.value' | translate)
30 | }}
31 |
32 |
33 | {{ 'certificates.profileAssociations.value' | translate }}:
34 | @if (!cert.associatedProfiles || cert.associatedProfiles.length === 0) {
35 | {{ 'certificates.profileAssociationsUnassociated.value' | translate }}
36 | } @else {
37 | {{ cert.associatedProfiles }}
38 | }
39 |
40 |
41 |
47 |
55 |
56 |
57 | }
58 | }
59 |
60 |
61 |
--------------------------------------------------------------------------------
/src/app/ieee8021x/ieee8021x.constants.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Copyright (c) Intel Corporation 2022
3 | * SPDX-License-Identifier: Apache-2.0
4 | **********************************************************************/
5 |
6 | import { FormOption } from '../../models/models'
7 |
8 | // AMT Authentication ProtocoL
9 | // https://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide/HTMLDocuments/WS-Management_Class_Reference/AMT_8021XProfile.htm
10 | // CIM Authentication ProtocoL
11 | // https://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide/default.htm?turl=HTMLDocuments%2FWS-Management_Class_Reference%2FCIM_IEEE8021xSettings.htm
12 | // IPS Authentication Protocol
13 | // https://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide/default.htm?turl=HTMLDocuments%2FWS-Management_Class_Reference%2FIPS_IEEE8021xSettings.htm
14 | // -------------------------------------------------------------------------------------
15 | // | AMT | CIM | IPS
16 | // -------------------------------------------------------------------------------------
17 | // 0 | TLS | EAP-TLS | EAP-TLS
18 | // 1 | TTLS_MSCHAPv2 | EAP-TTLS/MSCHAPv2 | EAP-TTLS/MSCHAPv2
19 | // 2 | PEAP_MSCHAPv2 | PEAPv0/EAP-MSCHAPv2 | PEAPv0/EAP-MSCHAPv2
20 | // 3 | EAP_GTC | PEAPv1/EAP-GTC | PEAPv1/EAP-GTC
21 | // 4 | EAPFAST_MSCHAPv2 | EAP-FAST/MSCHAPv2 | EAP-FAST/MSCHAPv2
22 | // 5 | EAPFAST_GTC | EAP-FAST/GTC | EAP-FAST/GTC
23 | // 6 | EAPFAST_TLS | EAP-MD5 | EAP-MD5
24 | // 7 | | EAP-PSK | EAP-PSK
25 | // 8 | | EAP-SIM | EAP-SIM
26 | // 9 | | EAP-AKA | EAP-AKA
27 | // 10 | | EAP-FAST/TLS | EAP-FAST/TLS
28 | // 11 | | DMTF Reserved | DMTF Reserved
29 |
30 | export const AuthenticationProtocols: FormOption[] = [
31 | { value: 0, mode: 'both', label: 'EAP-TLS' },
32 | //{ value: 1, mode: 'wired', label: 'EAP-TTLS/MSCHAPv2' },
33 | { value: 2, mode: 'both', label: 'PEAPv0/EAP-MSCHAPv2' },
34 | { value: 3, mode: 'wired', label: 'PEAPv1/EAP-GTC' },
35 | // { value: 4, mode: 'wired', label: 'EAP-FAST/MSCHAPv2' },
36 | { value: 5, mode: 'wired', label: 'EAP-FAST/GTC' },
37 | // { value: 6, mode: 'wired', label: 'EAP-MD5' },
38 | // { value: 7, mode: 'wired', label: 'EAP-PSK' },
39 | // { value: 8, mode: 'wired', label: 'EAP-SIM' },
40 | // { value: 9, mode: 'wired', label: 'EAP-AKA' },
41 | { value: 10, mode: 'wired', label: 'EAP-FAST/TLS' }
42 | ]
43 |
--------------------------------------------------------------------------------