├── .asf.yaml ├── .browserslistrc ├── .dockerignore ├── .github ├── PULL_REQUEST_TEMPLATE └── workflows │ └── main.yml ├── .gitignore ├── .go_repro_version ├── .go_version ├── .golangci.yml ├── .nvmrc ├── .prettierrc ├── Dockerfile ├── LICENSE ├── Makefile ├── NOTICE ├── README.md ├── angular.json ├── go.mod ├── go.sum ├── json-db.json ├── json-routes.json ├── json-server.json ├── karma.conf.ci.js ├── karma.conf.js ├── package.json ├── pkg ├── cmd │ └── web │ │ └── main.go └── webserver │ ├── testdata │ └── test.txt │ ├── web_server.go │ └── web_server_test.go ├── pnpm-lock.yaml ├── src ├── app │ ├── app-routing.module.ts │ ├── app.component.html │ ├── app.component.scss │ ├── app.component.spec.ts │ ├── app.component.ts │ ├── app.module.ts │ ├── components │ │ ├── app-history │ │ │ ├── app-history.component.html │ │ │ ├── app-history.component.scss │ │ │ ├── app-history.component.spec.ts │ │ │ └── app-history.component.ts │ │ ├── app-node-utilizations │ │ │ ├── app-node-utilizations.component.html │ │ │ ├── app-node-utilizations.component.scss │ │ │ ├── app-node-utilizations.component.spec.ts │ │ │ └── app-node-utilizations.component.ts │ │ ├── app-status │ │ │ ├── app-status.component.html │ │ │ ├── app-status.component.scss │ │ │ ├── app-status.component.spec.ts │ │ │ └── app-status.component.ts │ │ ├── apps-view │ │ │ ├── apps-view.component.html │ │ │ ├── apps-view.component.scss │ │ │ ├── apps-view.component.spec.ts │ │ │ └── apps-view.component.ts │ │ ├── area-chart │ │ │ ├── area-chart.component.html │ │ │ ├── area-chart.component.scss │ │ │ ├── area-chart.component.spec.ts │ │ │ └── area-chart.component.ts │ │ ├── card │ │ │ ├── card.component.html │ │ │ ├── card.component.scss │ │ │ └── card.component.ts │ │ ├── container-history │ │ │ ├── container-history.component.html │ │ │ ├── container-history.component.scss │ │ │ ├── container-history.component.spec.ts │ │ │ └── container-history.component.ts │ │ ├── container-status │ │ │ ├── container-status.component.html │ │ │ ├── container-status.component.scss │ │ │ ├── container-status.component.spec.ts │ │ │ └── container-status.component.ts │ │ ├── dashboard │ │ │ ├── dashboard.component.html │ │ │ ├── dashboard.component.scss │ │ │ ├── dashboard.component.spec.ts │ │ │ └── dashboard.component.ts │ │ ├── donut-chart │ │ │ ├── donut-chart.component.html │ │ │ ├── donut-chart.component.scss │ │ │ ├── donut-chart.component.spec.ts │ │ │ └── donut-chart.component.ts │ │ ├── error-view │ │ │ ├── error-view.component.html │ │ │ ├── error-view.component.scss │ │ │ ├── error-view.component.spec.ts │ │ │ └── error-view.component.ts │ │ ├── healthchecks │ │ │ ├── healthchecks.component.html │ │ │ ├── healthchecks.component.scss │ │ │ ├── healthchecks.component.spec.ts │ │ │ └── healthchecks.component.ts │ │ ├── licenses-modal │ │ │ ├── licenses-modal.component.html │ │ │ ├── licenses-modal.component.scss │ │ │ ├── licenses-modal.component.spec.ts │ │ │ └── licenses-modal.component.ts │ │ ├── nodes-view │ │ │ ├── highlighttable-search.pipe.ts │ │ │ ├── nodes-view.component.html │ │ │ ├── nodes-view.component.scss │ │ │ ├── nodes-view.component.spec.ts │ │ │ └── nodes-view.component.ts │ │ ├── queue-rack │ │ │ ├── queue-rack.component.html │ │ │ ├── queue-rack.component.scss │ │ │ ├── queue-rack.component.spec.ts │ │ │ └── queue-rack.component.ts │ │ ├── queue-v2 │ │ │ ├── queues-v2.component.html │ │ │ ├── queues-v2.component.scss │ │ │ ├── queues-v2.component.spec.ts │ │ │ └── queues-v2.component.ts │ │ ├── queues-view │ │ │ ├── queues-view.component.html │ │ │ ├── queues-view.component.scss │ │ │ ├── queues-view.component.spec.ts │ │ │ └── queues-view.component.ts │ │ ├── status-view │ │ │ ├── status-view.component.html │ │ │ ├── status-view.component.scss │ │ │ ├── status-view.component.spec.ts │ │ │ └── status-view.component.ts │ │ └── vertical-bar-chart │ │ │ ├── vertical-bar-chart.component.html │ │ │ ├── vertical-bar-chart.component.scss │ │ │ ├── vertical-bar-chart.component.spec.ts │ │ │ └── vertical-bar-chart.component.ts │ ├── interceptors │ │ └── api-error │ │ │ ├── api-error.interceptor.spec.ts │ │ │ └── api-error.interceptor.ts │ ├── models │ │ ├── alloc-info.model.ts │ │ ├── api-error-info.model.ts │ │ ├── app-info.model.ts │ │ ├── app-status.model.ts │ │ ├── area-data.model.ts │ │ ├── chart-data.model.ts │ │ ├── cluster-info.model.ts │ │ ├── column-def.model.ts │ │ ├── dropdown-item.model.ts │ │ ├── envconfig.model.ts │ │ ├── history-info.model.ts │ │ ├── node-info.model.ts │ │ ├── node-utilization.model.ts │ │ ├── partition-info.model.ts │ │ ├── queue-info.model.ts │ │ ├── resource-info.model.ts │ │ ├── scheduler-health-info.model.ts │ │ └── time-series-data.model.ts │ ├── services │ │ ├── envconfig │ │ │ ├── envconfig.service.spec.ts │ │ │ └── envconfig.service.ts │ │ ├── event-bus │ │ │ ├── event-bus.service.spec.ts │ │ │ └── event-bus.service.ts │ │ └── scheduler │ │ │ ├── scheduler.service.spec.ts │ │ │ └── scheduler.service.ts │ ├── testing │ │ └── mocks.ts │ └── utils │ │ ├── common.util.spec.ts │ │ ├── common.util.ts │ │ └── constants.ts ├── assets │ ├── config │ │ └── envconfig.json │ └── images │ │ ├── config.svg │ │ ├── hierarchy.svg │ │ └── logo.png ├── environments │ ├── environment.prod.ts │ └── environment.ts ├── favicon.ico ├── index.html ├── main.ts ├── polyfills.ts ├── styles.scss └── test.ts ├── tsconfig.app.json ├── tsconfig.json └── tsconfig.spec.json /.asf.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Licensed to the Apache Software Foundation (ASF) under one 3 | # or more contributor license agreements. See the NOTICE file 4 | # distributed with this work for additional information 5 | # regarding copyright ownership. The ASF licenses this file 6 | # to you under the Apache License, Version 2.0 (the 7 | # "License"); you may not use this file except in compliance 8 | # with the License. You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, 13 | # software distributed under the License is distributed on an 14 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | # KIND, either express or implied. See the License for the 16 | # specific language governing permissions and limitations 17 | # under the License. 18 | # 19 | 20 | # https://cwiki.apache.org/confluence/display/INFRA/git+-+.asf.yaml+features 21 | 22 | github: 23 | description: "Apache YuniKorn Web UI" 24 | homepage: https://yunikorn.apache.org/ 25 | labels: 26 | - yunikorn 27 | - angular 28 | - universal-resource-scheduler 29 | - apache-yarn 30 | - kubernetes 31 | enabled_merge_buttons: 32 | squash: true 33 | merge: false 34 | rebase: false 35 | features: 36 | wiki: false 37 | issues: false 38 | projects: false 39 | 40 | notifications: 41 | commits: issues@yunikorn.apache.org 42 | issues: reviews@yunikorn.apache.org 43 | pullrequests: reviews@yunikorn.apache.org 44 | jira_options: link label 45 | -------------------------------------------------------------------------------- /.browserslistrc: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # For the full list of supported browsers by the Angular framework, please see: 6 | # https://angular.io/guide/browser-support 7 | 8 | # You can see what browsers were selected by your queries by running: 9 | # npx browserslist 10 | 11 | last 2 Chrome versions 12 | last 1 Firefox version 13 | last 2 Edge major versions 14 | last 2 Safari major versions 15 | last 2 iOS major versions 16 | Firefox ESR 17 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE: -------------------------------------------------------------------------------- 1 | ### What is this PR for? 2 | A few sentences describing the overall goals of the pull request's commits. 3 | First time? Check out the contributing guide - http://yunikorn.apache.org/community/how_to_contribute 4 | 5 | 6 | ### What type of PR is it? 7 | * [ ] - Bug Fix 8 | * [ ] - Improvement 9 | * [ ] - Feature 10 | * [ ] - Documentation 11 | * [ ] - Hot Fix 12 | * [ ] - Refactoring 13 | 14 | ### Todos 15 | * [ ] - Task 16 | 17 | ### What is the Jira issue? 18 | * Open an issue on Jira https://issues.apache.org/jira/browse/YUNIKORN/ 19 | * Put link here, and add [YUNIKORN-*Jira number*] in PR title, eg. `[YUNIKORN-2] Gang scheduling interface parameters` 20 | 21 | ### How should this be tested? 22 | 23 | ### Screenshots (if appropriate) 24 | 25 | ### Questions: 26 | * [ ] - The licenses files need update. 27 | * [ ] - There is breaking changes for older versions. 28 | * [ ] - It needs documentation. 29 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Pre-commit Checks 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - master 7 | push: 8 | branches: 9 | - master 10 | workflow_dispatch: {} 11 | 12 | concurrency: 13 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} 14 | cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} 15 | 16 | jobs: 17 | build: 18 | runs-on: ubuntu-latest 19 | 20 | steps: 21 | - name: Checkout Source Code 22 | uses: actions/checkout@v4 23 | with: 24 | fetch-depth: 2 25 | - name: Set up Go 26 | uses: actions/setup-go@v5 27 | with: 28 | go-version-file: .go_version 29 | - name: Check License 30 | run: make license-check 31 | - name: Set Node.js Environment 32 | uses: actions/setup-node@v4 33 | with: 34 | node-version-file: '.nvmrc' 35 | - name: Build Prod 36 | run: make build-prod 37 | - name: Test Coverage 38 | run: make test_js_coverage 39 | - name: Go lint 40 | run: make lint 41 | - name: Go unit tests 42 | run: make test_go 43 | - name: Code coverage 44 | uses: codecov/codecov-action@v4 45 | with: 46 | files: build/coverage.txt 47 | # After codecov/codecov-action@v4, tokenless uploading of coverage files to non-public repo is unsupported. 48 | # To enable codecov analysis in your forked repo. Please configure CODECOV_TOKEN in your repository secrets. 49 | # Ref: https://docs.codecov.com/docs/adding-the-codecov-token 50 | token: ${{ secrets.CODECOV_TOKEN }} 51 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # Compiled output 4 | /dist 5 | /bin 6 | /build 7 | /tmp 8 | /out-tsc 9 | /bazel-out 10 | /tools 11 | /build.date 12 | 13 | # Node 14 | /node_modules 15 | npm-debug.log 16 | yarn-error.log 17 | yarn.lock 18 | 19 | # IDEs and editors 20 | .idea/ 21 | .project 22 | .classpath 23 | .c9/ 24 | *.launch 25 | *.swp 26 | .settings/ 27 | *.sublime-workspace 28 | 29 | # Visual Studio Code 30 | .vscode/* 31 | .vscode/ 32 | !.vscode/settings.json 33 | !.vscode/tasks.json 34 | !.vscode/launch.json 35 | !.vscode/extensions.json 36 | .history/* 37 | 38 | # Miscellaneous 39 | /.angular/cache 40 | .sass-cache/ 41 | /connect.lock 42 | /coverage 43 | /coverage.txt 44 | /libpeerconnection.log 45 | testem.log 46 | /typings 47 | 48 | # System files 49 | .DS_Store 50 | Thumbs.db 51 | -------------------------------------------------------------------------------- /.go_repro_version: -------------------------------------------------------------------------------- 1 | 1.23.7 2 | -------------------------------------------------------------------------------- /.go_version: -------------------------------------------------------------------------------- 1 | 1.23 2 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | # 2 | # Licensed to the Apache Software Foundation (ASF) under one 3 | # or more contributor license agreements. See the NOTICE file 4 | # distributed with this work for additional information 5 | # regarding copyright ownership. The ASF licenses this file 6 | # to you under the Apache License, Version 2.0 (the 7 | # "License"); you may not use this file except in compliance 8 | # with the License. You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | # options for analysis running 19 | run: 20 | issues-exit-code: 1 21 | modules-download-mode: readonly 22 | timeout: 10m 23 | 24 | # settings of specific linters 25 | linters-settings: 26 | errcheck: 27 | check-type-assertions: true 28 | check-blank: true 29 | revive: 30 | confidence: 0.8 31 | gofmt: 32 | simplify: true 33 | goimports: 34 | local-prefixes: github.com/apache/yunikorn 35 | govet: 36 | shadow: true 37 | funlen: 38 | lines: 120 39 | statements: 80 40 | depguard: 41 | rules: 42 | main: 43 | files: 44 | - $all 45 | deny: 46 | - pkg: "github.com/sirupsen/logrus" 47 | desc: "logging is standardised via yunikorn logger and zap" 48 | - pkg: "github.com/stretchr/testify" 49 | desc: "test assertions must use gotest.tools/v3/assert" 50 | 51 | # linters to use 52 | linters: 53 | disable-all: true 54 | fast: false 55 | enable: 56 | - errcheck 57 | - unused 58 | - staticcheck 59 | - gosimple 60 | - ineffassign 61 | - funlen 62 | - revive 63 | - gofmt 64 | - goimports 65 | - govet 66 | - goconst 67 | - depguard 68 | - nakedret 69 | - gocritic 70 | - godox 71 | - gosec 72 | - dogsled 73 | - whitespace 74 | 75 | issues: 76 | exclude-use-default: true 77 | 78 | # Maximum issues count per one linter. Set to 0 to disable. Default is 50. 79 | max-issues-per-linter: 0 80 | 81 | # Maximum count of issues with the same text. Set to 0 to disable. Default is 3. 82 | max-same-issues: 0 83 | 84 | # Show only new issues: if there are unstaged changes or untracked files, 85 | # only those changes are analyzed, else only changes in HEAD~ are analyzed. 86 | # It's a super-useful option for integration of golangci-lint into existing 87 | # large codebase. It's not practical to fix all existing issues at the moment 88 | # of integration: much better don't allow issues in new code. 89 | # Default is false. 90 | new: false 91 | 92 | # Show only new issues created after git revision `REV` 93 | # new-from-rev: REV 94 | 95 | # Show only new issues created in git patch with set file path. 96 | # new-from-patch: path/to/patch/file 97 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 18.20 2 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 100, 3 | "singleQuote": true, 4 | "useTabs": false, 5 | "tabWidth": 2, 6 | "semi": true, 7 | "bracketSpacing": true, 8 | "trailingComma": "es5" 9 | } 10 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # 2 | # Licensed to the Apache Software Foundation (ASF) under one 3 | # or more contributor license agreements. See the NOTICE file 4 | # distributed with this work for additional information 5 | # regarding copyright ownership. The ASF licenses this file 6 | # to you under the Apache License, Version 2.0 (the 7 | # "License"); you may not use this file except in compliance 8 | # with the License. You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | ARG NODE_VERSION=20 19 | # Buildstage: use the local architecture 20 | FROM --platform=$BUILDPLATFORM node:${NODE_VERSION}-alpine AS buildstage 21 | 22 | WORKDIR /work 23 | # Only copy what is needed for the build 24 | COPY *.json *.js *.yaml .browserslistrc /work/ 25 | COPY src /work/src/ 26 | 27 | RUN npm install -g pnpm@9 28 | RUN PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=1 pnpm i 29 | RUN pnpm build:prod 30 | 31 | # Imagestage: use scratch base image 32 | FROM scratch 33 | COPY --chown=0:0 NOTICE LICENSE build/prod/yunikorn-web / 34 | COPY --chown=0:0 --from=buildstage /work/dist/yunikorn-web /html/ 35 | EXPOSE 9889 36 | ENV DOCUMENT_ROOT=/html 37 | USER 4444:4444 38 | ENTRYPOINT [ "/yunikorn-web" ] 39 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Apache YuniKorn 2 | Copyright 2019-2024 The Apache Software Foundation 3 | 4 | This product includes software developed at 5 | The Apache Software Foundation (http://www.apache.org/). 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 18 | 19 | # Yunikorn web UI 20 | YuniKorn web provides a web interface on top of the scheduler. It provides insight in the current and historic scheduler status. 21 | It depends on `yunikorn-core` which encapsulates all the actual scheduling logic. 22 | 23 | For detailed information on the components and how to build the overall scheduler please see the [yunikorn-core](https://github.com/apache/yunikorn-core). 24 | 25 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 13.3.0. 26 | 27 | ## Development Environment setup 28 | ### Dependencies 29 | The project requires a number of external tools to be installed before the build and development: 30 | - [Node.js](https://nodejs.org/en/) 31 | - [Angular CLI](https://github.com/angular/angular-cli) 32 | - [Karma](https://karma-runner.github.io) 33 | - [pnpm](https://www.npmjs.com/package/pnpm) 34 | - [json-server](https://www.npmjs.com/package/json-server) 35 | 36 | To manage our node packages, we've chosen pnpm. Simply execute the command `pnpm install` to set up all necessary dependencies. This single step ensures that your environment is fully prepared with all the required packages. 37 | 38 | ### Development server 39 | 40 | Run `make start-dev` for a development server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files. 41 | 42 | ## Build 43 | 44 | Run `make build` to build the project. The build artifacts will be stored in the `dist/` directory. Use `make build-prod` for a production build. 45 | Production builds will add the `--prod` flag to the angular build. 46 | 47 | ### Docker image build 48 | Image builds are geared towards a production build and will always build with the `--prod` flag set. 49 | 50 | Run `make image` to build the docker image `apache/yunikorn:web-latest`. 51 | Run `make run` to build the image and deploy the container from the docker image `apache/yunikorn:web-latest`. 52 | 53 | You can set `REGISTRY`, `VERSION` and `DOCKER_ARCH` in the commandline to build docker image with a specified version, registry and host architecture. For example, 54 | ``` 55 | make image REGISTRY=apache VERSION=latest DOCKER_ARCH=amd64 56 | ``` 57 | This command will build binary with version `web-latest` and the docker full image tag is `apache/yunikorn:web-amd64-latest`. 58 | 59 | The Makefile is smart enough to detect your host architecture but it will tag the image name. 60 | 61 | ### Running tests 62 | 63 | All tests can be executed via `make test`. It will first build the project and then execute the unit tests followed by the end to end tests. 64 | If you want to run the unit tests separately, run `pnpm test` to execute them via [Karma](https://karma-runner.github.io). If you want to run the unit tests with code coverage, run `pnpm test:coverage`. 65 | 66 | ## Local development 67 | Beside the simple all in way to start the development server via make you can also start a development environment manually. 68 | 69 | The application depends on [json-server](https://www.npmjs.com/package/json-server) for data. Install json-server locally. Run `pnpm start:srv` to start json-server for local development. 70 | Run `pnpm start` to start the angular development server and navigate to `http://localhost:4200/`. 71 | 72 | After updating the context in the `json-db.json` or `json-route.json`, checking the json server is available by running `make json-server`. 73 | 74 | ## Further help 75 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). 76 | 77 | ## Code scaffolding 78 | Run `ng generate component component-name` to generate a new component. 79 | 80 | You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. 81 | 82 | ## Port configurations 83 | The default port used for the web server is port 9889. 84 | 85 | ## How do I contribute code? 86 | See how to contribute code from [this guide](https://yunikorn.apache.org/community/how_to_contribute). 87 | -------------------------------------------------------------------------------- /angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "cli": { 5 | "packageManager": "pnpm", 6 | "analytics": false 7 | }, 8 | "newProjectRoot": "projects", 9 | "projects": { 10 | "yunikorn-web": { 11 | "projectType": "application", 12 | "schematics": { 13 | "@schematics/angular:component": { 14 | "style": "scss" 15 | }, 16 | "@schematics/angular:application": { 17 | "strict": true 18 | } 19 | }, 20 | "root": "", 21 | "sourceRoot": "src", 22 | "prefix": "app", 23 | "architect": { 24 | "build": { 25 | "builder": "@angular-devkit/build-angular:browser", 26 | "options": { 27 | "outputPath": "dist/yunikorn-web", 28 | "index": "src/index.html", 29 | "main": "src/main.ts", 30 | "polyfills": "src/polyfills.ts", 31 | "tsConfig": "tsconfig.app.json", 32 | "inlineStyleLanguage": "scss", 33 | "assets": ["src/favicon.ico", "src/assets", {"glob": "LICENSE", "input": "./", "output": "./"}], 34 | "styles": [ 35 | "src/styles.scss", 36 | "node_modules/@fontsource/roboto/index.css", 37 | "node_modules/@fontsource/roboto/300.css", 38 | "node_modules/@fontsource/roboto/500.css", 39 | "node_modules/@fortawesome/fontawesome-free/css/all.css" 40 | ], 41 | "scripts": [] 42 | }, 43 | "configurations": { 44 | "production": { 45 | "budgets": [ 46 | { 47 | "type": "initial", 48 | "maximumWarning": "3mb", 49 | "maximumError": "5mb" 50 | }, 51 | { 52 | "type": "anyComponentStyle", 53 | "maximumWarning": "4kb", 54 | "maximumError": "5kb" 55 | } 56 | ], 57 | "fileReplacements": [ 58 | { 59 | "replace": "src/environments/environment.ts", 60 | "with": "src/environments/environment.prod.ts" 61 | } 62 | ], 63 | "outputHashing": "all" 64 | }, 65 | "development": { 66 | "buildOptimizer": false, 67 | "optimization": false, 68 | "vendorChunk": true, 69 | "extractLicenses": true, 70 | "sourceMap": true, 71 | "namedChunks": true 72 | } 73 | }, 74 | "defaultConfiguration": "production" 75 | }, 76 | "serve": { 77 | "builder": "@angular-devkit/build-angular:dev-server", 78 | "configurations": { 79 | "production": { 80 | "browserTarget": "yunikorn-web:build:production" 81 | }, 82 | "development": { 83 | "buildTarget": "yunikorn-web:build:development" 84 | } 85 | }, 86 | "defaultConfiguration": "development" 87 | }, 88 | "extract-i18n": { 89 | "builder": "@angular-devkit/build-angular:extract-i18n", 90 | "options": { 91 | "browserTarget": "yunikorn-web:build" 92 | } 93 | }, 94 | "test": { 95 | "builder": "@angular-devkit/build-angular:karma", 96 | "options": { 97 | "main": "src/test.ts", 98 | "polyfills": "src/polyfills.ts", 99 | "tsConfig": "tsconfig.spec.json", 100 | "karmaConfig": "karma.conf.js", 101 | "inlineStyleLanguage": "scss", 102 | "assets": ["src/favicon.ico", "src/assets"], 103 | "styles": ["src/styles.scss"], 104 | "scripts": [] 105 | } 106 | } 107 | } 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | // 2 | // Licensed to the Apache Software Foundation (ASF) under one 3 | // or more contributor license agreements. See the NOTICE file 4 | // distributed with this work for additional information 5 | // regarding copyright ownership. The ASF licenses this file 6 | // to you under the Apache License, Version 2.0 (the 7 | // "License"); you may not use this file except in compliance 8 | // with the License. You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, 13 | // software distributed under the License is distributed on an 14 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | // KIND, either express or implied. See the License for the 16 | // specific language governing permissions and limitations 17 | // under the License. 18 | // 19 | 20 | module github.com/apache/yunikorn-web 21 | 22 | go 1.23 23 | 24 | toolchain go1.23.7 25 | 26 | require gotest.tools/v3 v3.5.2 27 | 28 | require github.com/google/go-cmp v0.7.0 // indirect 29 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= 2 | github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 3 | github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= 4 | github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= 5 | gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= 6 | gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= 7 | gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= 8 | gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= 9 | -------------------------------------------------------------------------------- /json-routes.json: -------------------------------------------------------------------------------- 1 | { 2 | "/ws/v1/scheduler/node-utilizations": "/node-utilizations", 3 | "/ws/v1/*": "/$1", 4 | "/history/apps": "/appHistory", 5 | "/history/containers": "/containerHistory", 6 | "/partition/:partition/queues": "/queues", 7 | "/partition/:partition/nodes": "/nodes", 8 | "/partition/:partition/queue/:queue/applications": "/apps", 9 | "/scheduler/healthcheck": "/healthCheck" 10 | } 11 | -------------------------------------------------------------------------------- /json-server.json: -------------------------------------------------------------------------------- 1 | { 2 | "port": 9889, 3 | "routes": "json-routes.json" 4 | } 5 | -------------------------------------------------------------------------------- /karma.conf.ci.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | // Karma configuration file, see link for more information 20 | // https://karma-runner.github.io/1.0/config/configuration-file.html 21 | 22 | process.env.CHROME_BIN = require('puppeteer').executablePath(); 23 | 24 | module.exports = function (config) { 25 | config.set({ 26 | basePath: '', 27 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 28 | plugins: [ 29 | require('karma-jasmine'), 30 | require('karma-chrome-launcher'), 31 | require('karma-jasmine-html-reporter'), 32 | require('karma-coverage'), 33 | require('karma-coverage-istanbul-reporter'), 34 | require('@angular-devkit/build-angular/plugins/karma'), 35 | require('karma-super-dots-reporter'), 36 | ], 37 | client: { 38 | clearContext: false, // leave Jasmine Spec Runner output visible in browser 39 | }, 40 | reporters: ['super-dots', 'coverage-istanbul'], 41 | superDotsReporter: { 42 | nbDotsPerLine: 180, 43 | }, 44 | coverageIstanbulReporter: { 45 | dir: require('path').join(__dirname, './coverage/yunikorn-web'), 46 | reports: ['text-summary'], 47 | fixWebpackSourcePaths: true, 48 | }, 49 | port: 9876, 50 | colors: true, 51 | logLevel: config.LOG_INFO, 52 | autoWatch: false, 53 | browsers: ['ChromeHeadlessNoSandbox'], 54 | customLaunchers: { 55 | ChromeHeadlessNoSandbox: { 56 | base: 'ChromeHeadless', 57 | flags: ['--no-sandbox'], 58 | }, 59 | }, 60 | captureTimeout: 180000, 61 | browserDisconnectTolerance: 3, 62 | browserDisconnectTimeout: 180000, 63 | browserNoActivityTimeout: 180000, 64 | singleRun: true, 65 | restartOnFileChange: true, 66 | }); 67 | }; 68 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | // Karma configuration file, see link for more information 20 | // https://karma-runner.github.io/1.0/config/configuration-file.html 21 | 22 | process.env.CHROME_BIN = require('puppeteer').executablePath(); 23 | 24 | module.exports = function (config) { 25 | config.set({ 26 | basePath: '', 27 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 28 | plugins: [ 29 | require('karma-jasmine'), 30 | require('karma-chrome-launcher'), 31 | require('karma-jasmine-html-reporter'), 32 | require('karma-coverage'), 33 | require('@angular-devkit/build-angular/plugins/karma'), 34 | require('karma-spec-reporter'), 35 | ], 36 | client: { 37 | jasmine: { 38 | // you can add configuration options for Jasmine here 39 | // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html 40 | // for example, you can disable the random execution with `random: false` 41 | // or set a specific seed with `seed: 4321` 42 | }, 43 | clearContext: false, // leave Jasmine Spec Runner output visible in browser 44 | }, 45 | jasmineHtmlReporter: { 46 | suppressAll: true, // removes the duplicated traces 47 | }, 48 | coverageReporter: { 49 | dir: require('path').join(__dirname, './coverage/yunikorn-web'), 50 | subdir: '.', 51 | reporters: [{ type: 'html' }, { type: 'text-summary' }], 52 | }, 53 | reporters: ['spec'], 54 | specReporter: { 55 | maxLogLines: 5, // limit number of lines logged per test 56 | suppressErrorSummary: true, // do not print error summary 57 | suppressFailed: false, // do not print information about failed tests 58 | suppressPassed: false, // do not print information about passed tests 59 | suppressSkipped: true, // do not print information about skipped tests 60 | showSpecTiming: false, // print the time elapsed for each spec 61 | failFast: true, // test would finish with error when a first fail occurs. 62 | }, 63 | port: 9876, 64 | colors: true, 65 | logLevel: config.LOG_INFO, 66 | autoWatch: true, 67 | browsers: ['ChromeHeadlessNoSandbox'], 68 | customLaunchers: { 69 | ChromeHeadlessNoSandbox: { 70 | base: 'ChromeHeadless', 71 | flags: ['--no-sandbox'], 72 | }, 73 | }, 74 | captureTimeout: 180000, 75 | browserDisconnectTolerance: 3, 76 | browserDisconnectTimeout: 180000, 77 | browserNoActivityTimeout: 180000, 78 | singleRun: false, 79 | restartOnFileChange: true, 80 | }); 81 | }; 82 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "yunikorn-web", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "preinstall": "npx only-allow pnpm", 6 | "ng": "ng", 7 | "start": "ng serve", 8 | "build": "ng build", 9 | "test": "ng test", 10 | "watch": "ng build --watch --configuration development", 11 | "test:singleRun": "ng test --code-coverage --watch false", 12 | "start:host": "ng serve --host 0.0.0.0", 13 | "build:prod": "ng build --configuration production", 14 | "start:srv": "json-server --watch json-db.json", 15 | "test:coverage": "ng test --code-coverage --karma-config=./karma.conf.ci.js", 16 | "prettify": "prettier --config ./.prettierrc --write 'src/**/*.{js,ts,json,css,scss,md,html}'" 17 | }, 18 | "private": true, 19 | "husky": { 20 | "hooks": { 21 | "pre-commit": "lint-staged" 22 | } 23 | }, 24 | "lint-staged": { 25 | "src/**/*.{js,ts,json,css,scss,md,html}": [ 26 | "prettier --single-quote --write", 27 | "git add" 28 | ] 29 | }, 30 | "dependencies": { 31 | "@angular/animations": "^18.2.13", 32 | "@angular/cdk": "^18.2.14", 33 | "@angular/common": "^18.2.13", 34 | "@angular/compiler": "^18.2.13", 35 | "@angular/core": "^18.2.13", 36 | "@angular/forms": "^18.2.13", 37 | "@angular/material": "^18.2.14", 38 | "@angular/platform-browser": "^18.2.13", 39 | "@angular/platform-browser-dynamic": "^18.2.13", 40 | "@angular/router": "^18.2.13", 41 | "@fontsource/roboto": "^5.2.5", 42 | "@fortawesome/fontawesome-free": "^6.7.2", 43 | "@types/d3-flextree": "^2.1.4", 44 | "@types/d3-hierarchy": "^3.1.7", 45 | "@types/d3-selection": "^3.0.11", 46 | "@types/d3-shape": "^3.1.7", 47 | "@types/d3-transition": "^3.0.9", 48 | "@types/d3-zoom": "^3.0.8", 49 | "angular-material-expansion-panel": "^0.7.2", 50 | "chart.js": "^4.4.9", 51 | "chartjs-adapter-date-fns": "^3.0.0", 52 | "color": "^4.2.3", 53 | "d3-flextree": "^2.1.2", 54 | "d3-hierarchy": "^3.1.2", 55 | "d3-selection": "^3.0.0", 56 | "d3-transition": "^3.0.1", 57 | "d3-zoom": "^3.0.0", 58 | "date-fns": "^2.30.0", 59 | "material-design-icons": "^3.0.1", 60 | "moment": "^2.30.1", 61 | "ngx-spinner": "^17.0.0", 62 | "rxjs": "~7.8.2", 63 | "tslib": "^2.8.1", 64 | "zone.js": "~0.14.10" 65 | }, 66 | "devDependencies": { 67 | "@angular-devkit/build-angular": "^18.2.19", 68 | "@angular/cli": "^18.2.19", 69 | "@angular/compiler-cli": "^18.2.13", 70 | "@types/color": "^4.2.0", 71 | "@types/jasmine": "~5.1.7", 72 | "@types/node": "^20.17.32", 73 | "husky": "^8.0.3", 74 | "jasmine-core": "~5.3.0", 75 | "json-server": "^0.17.4", 76 | "karma": "~6.4.4", 77 | "karma-chrome-launcher": "~3.2.0", 78 | "karma-coverage": "~2.2.1", 79 | "karma-coverage-istanbul-reporter": "^3.0.3", 80 | "karma-jasmine": "~5.1.0", 81 | "karma-jasmine-html-reporter": "~2.1.0", 82 | "karma-spec-reporter": "^0.0.36", 83 | "karma-super-dots-reporter": "^0.2.0", 84 | "lint-staged": "^15.5.1", 85 | "ng-mocks": "^14.13.4", 86 | "prettier": "^3.5.3", 87 | "puppeteer": "^23.11.1", 88 | "typescript": "5.5.4" 89 | }, 90 | "engines": { 91 | "node": "18", 92 | "pnpm": "9" 93 | }, 94 | "packageManager": "pnpm@9" 95 | } 96 | -------------------------------------------------------------------------------- /pkg/cmd/web/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | package main 20 | 21 | import ( 22 | "log" 23 | "os" 24 | "os/signal" 25 | "syscall" 26 | 27 | "github.com/apache/yunikorn-web/pkg/webserver" 28 | ) 29 | 30 | var ( 31 | version string 32 | date string 33 | ) 34 | 35 | func main() { 36 | documentRoot := envOrDefault("DOCUMENT_ROOT", "dist/yunikorn-web") 37 | listenAddress := envOrDefault("LISTEN_ADDRESS", ":9889") 38 | proxyUrl := envOrDefault("PROXY_URL", "http://127.0.0.1:9080") 39 | log.Default().Printf("Starting yunikorn-web version: %s, buildDate: %s, docRoot: %s, listenAddress: %s, proxyUrl: %s", 40 | version, date, documentRoot, listenAddress, proxyUrl) 41 | server, err := webserver.NewWebServer(documentRoot, listenAddress, proxyUrl) 42 | if err != nil { 43 | log.Fatal(err) 44 | } 45 | server.Start() 46 | 47 | done := make(chan struct{}) 48 | go func() { 49 | c := make(chan os.Signal, 1) 50 | signal.Notify(c, os.Interrupt, syscall.SIGTERM) 51 | <-c 52 | close(done) 53 | }() 54 | <-done 55 | server.Stop() 56 | } 57 | 58 | func envOrDefault(envVar, defValue string) string { 59 | if result, ok := os.LookupEnv(envVar); ok { 60 | return result 61 | } 62 | return defValue 63 | } 64 | -------------------------------------------------------------------------------- /pkg/webserver/testdata/test.txt: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | TESTING 19 | -------------------------------------------------------------------------------- /pkg/webserver/web_server.go: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | package webserver 20 | 21 | import ( 22 | ctx "context" 23 | "errors" 24 | "log" 25 | "net/http" 26 | "net/http/httputil" 27 | "net/url" 28 | "time" 29 | ) 30 | 31 | type WebServer struct { 32 | server *http.Server 33 | } 34 | 35 | func NewWebServer(documentRoot, listenAddress, proxyUrl string) (*WebServer, error) { 36 | origin, err := url.Parse(proxyUrl) 37 | if err != nil { 38 | return nil, err 39 | } 40 | proxy := httputil.NewSingleHostReverseProxy(origin) 41 | fs := http.FileServer(http.Dir(documentRoot)) 42 | mux := http.NewServeMux() 43 | mux.Handle("/", fs) 44 | mux.Handle("/ws/", proxy) 45 | server := &http.Server{ 46 | Addr: listenAddress, 47 | Handler: mux, 48 | ReadHeaderTimeout: 10 * time.Second, 49 | } 50 | return &WebServer{ 51 | server: server, 52 | }, nil 53 | } 54 | 55 | func (ws *WebServer) Start() { 56 | go func() { 57 | if err := ws.server.ListenAndServe(); err != nil { 58 | if !errors.Is(err, http.ErrServerClosed) { 59 | log.Fatal(err) 60 | } 61 | } 62 | }() 63 | } 64 | 65 | func (ws *WebServer) Stop() { 66 | ws.server.Close() 67 | if err := ws.server.Shutdown(ctx.Background()); err != nil { 68 | if !errors.Is(err, http.ErrServerClosed) { 69 | log.Fatal(err) 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /pkg/webserver/web_server_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | package webserver 20 | 21 | import ( 22 | "errors" 23 | "fmt" 24 | "io" 25 | "net/http" 26 | "strings" 27 | "testing" 28 | "time" 29 | 30 | "gotest.tools/v3/assert" 31 | ) 32 | 33 | func TestWebServer(t *testing.T) { 34 | mux := http.NewServeMux() 35 | mux.HandleFunc("/ws/v1/test", func(w http.ResponseWriter, r *http.Request) { 36 | fmt.Fprintln(w, "OK") 37 | }) 38 | proxiedServer := http.Server{ 39 | Addr: ":40001", 40 | Handler: mux, 41 | ReadHeaderTimeout: 10 * time.Second, 42 | } 43 | go func() { 44 | if err := proxiedServer.ListenAndServe(); err != nil { 45 | if !errors.Is(err, http.ErrServerClosed) { 46 | assert.NilError(t, err, "failed to start server") 47 | } 48 | } 49 | }() 50 | defer func() { 51 | if err := proxiedServer.Close(); err != nil { 52 | if !errors.Is(err, http.ErrServerClosed) { 53 | assert.NilError(t, err, "failed to stop server") 54 | } 55 | } 56 | }() 57 | 58 | server, err := NewWebServer("testdata", "127.0.0.1:40002", "http://127.0.0.1:40001") 59 | assert.NilError(t, err, "failed to create server") 60 | server.Start() 61 | defer server.Stop() 62 | 63 | time.Sleep(100 * time.Millisecond) 64 | 65 | // validate local content 66 | res, err := http.Get("http://127.0.0.1:40002/test.txt") 67 | assert.NilError(t, err, "failed to read from server") 68 | body, err := io.ReadAll(res.Body) 69 | assert.NilError(t, err, "failed to read body") 70 | str := string(body) 71 | assert.Check(t, strings.Contains(str, "TESTING"), "test string not found") 72 | 73 | // validate proxied content 74 | res, err = http.Get("http://127.0.0.1:40002/ws/v1/test") 75 | assert.NilError(t, err, "failed to read from server") 76 | body, err = io.ReadAll(res.Body) 77 | assert.NilError(t, err, "failed to read body") 78 | str = string(body) 79 | assert.Check(t, strings.Contains(str, "OK"), "test string not found") 80 | } 81 | 82 | func TestProxy(t *testing.T) { 83 | 84 | } 85 | -------------------------------------------------------------------------------- /src/app/app-routing.module.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import { NgModule } from '@angular/core'; 20 | import { Routes, RouterModule } from '@angular/router'; 21 | 22 | import { DashboardComponent } from './components/dashboard/dashboard.component'; 23 | import { QueuesViewComponent } from './components/queues-view/queues-view.component'; 24 | import { QueueV2Component } from './components/queue-v2/queues-v2.component'; 25 | import { AppsViewComponent } from './components/apps-view/apps-view.component'; 26 | import { NodesViewComponent } from './components/nodes-view/nodes-view.component'; 27 | import { StatusViewComponent } from './components/status-view/status-view.component'; 28 | import { ErrorViewComponent } from './components/error-view/error-view.component'; 29 | 30 | const appRoutes: Routes = [ 31 | { 32 | path: 'dashboard', 33 | component: DashboardComponent, 34 | data: { breadcrumb: 'Dashboard' }, 35 | }, 36 | { 37 | path: 'applications', 38 | component: AppsViewComponent, 39 | data: { breadcrumb: 'Applications' }, 40 | }, 41 | { 42 | path: 'queues', 43 | component: QueuesViewComponent, 44 | data: { breadcrumb: 'Queues' }, 45 | }, 46 | { 47 | path: 'queues-v2', 48 | component: QueueV2Component, 49 | data: { breadcrumb: 'Queues V2' }, 50 | }, 51 | { 52 | path: 'nodes', 53 | component: NodesViewComponent, 54 | data: { breadcrumb: 'Nodes' }, 55 | }, 56 | { 57 | path: 'status', 58 | component: StatusViewComponent, 59 | data: { breadcrumb: 'Status' }, 60 | }, 61 | { 62 | path: 'error', 63 | component: ErrorViewComponent, 64 | data: { breadcrumb: 'Error' }, 65 | }, 66 | { 67 | path: '**', 68 | redirectTo: '/dashboard', 69 | }, 70 | ]; 71 | 72 | @NgModule({ 73 | imports: [RouterModule.forRoot(appRoutes, { useHash: true })], 74 | exports: [RouterModule], 75 | }) 76 | export class AppRoutingModule {} 77 | -------------------------------------------------------------------------------- /src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 18 | 19 | 73 |
74 |
75 |
76 | 107 |
108 |
109 | 110 |
111 |
112 |
113 | 114 | 120 | -------------------------------------------------------------------------------- /src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import { TestBed, ComponentFixture } from '@angular/core/testing'; 20 | import { RouterTestingModule } from '@angular/router/testing'; 21 | import { NgxSpinnerModule } from 'ngx-spinner'; 22 | import { MatMenuModule } from '@angular/material/menu'; 23 | import { MatTooltipModule } from '@angular/material/tooltip'; 24 | import { HAMMER_LOADER } from '@angular/platform-browser'; 25 | 26 | import { AppComponent } from './app.component'; 27 | import { EventBusService } from './services/event-bus/event-bus.service'; 28 | import { MockEventBusService } from './testing/mocks'; 29 | import { MatDialog } from '@angular/material/dialog'; 30 | 31 | describe('AppComponent', () => { 32 | let component: AppComponent; 33 | let fixture: ComponentFixture; 34 | 35 | beforeAll(() => { 36 | TestBed.configureTestingModule({ 37 | declarations: [AppComponent], 38 | imports: [RouterTestingModule, NgxSpinnerModule, MatMenuModule, MatTooltipModule], 39 | providers: [ 40 | { provide: EventBusService, useValue: MockEventBusService }, 41 | { provide: HAMMER_LOADER, useValue: () => new Promise(() => {}) }, 42 | { provide: MatDialog, useValue: {} }, 43 | ], 44 | }).compileComponents(); 45 | }); 46 | 47 | beforeEach(() => { 48 | fixture = TestBed.createComponent(AppComponent); 49 | component = fixture.componentInstance; 50 | fixture.detectChanges(); 51 | }); 52 | 53 | it('should create the component', () => { 54 | expect(component).toBeTruthy(); 55 | }); 56 | }); 57 | -------------------------------------------------------------------------------- /src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import { Component, OnInit } from '@angular/core'; 20 | import { ActivatedRoute, Router, NavigationEnd } from '@angular/router'; 21 | import { debounceTime, filter } from 'rxjs/operators'; 22 | import { fromEvent } from 'rxjs'; 23 | 24 | import { EventBusService, EventMap } from '@app/services/event-bus/event-bus.service'; 25 | import { LicensesModalComponent } from '@app/components/licenses-modal/licenses-modal.component'; 26 | import { MatDialog } from '@angular/material/dialog'; 27 | 28 | @Component({ 29 | selector: 'app-root', 30 | templateUrl: './app.component.html', 31 | styleUrls: ['./app.component.scss'], 32 | }) 33 | export class AppComponent implements OnInit { 34 | isNavOpen = true; 35 | breadcrumbs: Array<{ label: string; url: string }> = []; 36 | 37 | constructor( 38 | private route: ActivatedRoute, 39 | private router: Router, 40 | private eventBus: EventBusService, 41 | private dialog: MatDialog 42 | ) {} 43 | 44 | ngOnInit() { 45 | this.router.events.pipe(filter((event) => event instanceof NavigationEnd)).subscribe(() => { 46 | this.generateBreadcrumb(); 47 | }); 48 | 49 | fromEvent(window, 'resize') 50 | .pipe(debounceTime(500)) 51 | .subscribe(() => this.eventBus.publish(EventMap.WindowResizedEvent)); 52 | } 53 | 54 | generateBreadcrumb() { 55 | this.breadcrumbs = []; 56 | let url = ''; 57 | let currentRoute: ActivatedRoute | null = this.route.root; 58 | 59 | do { 60 | const childrenRoutes = currentRoute.children; 61 | currentRoute = null; 62 | childrenRoutes.forEach((route) => { 63 | if (route.outlet === 'primary') { 64 | const routeSnapshot = route.snapshot; 65 | if (routeSnapshot) { 66 | url += '/' + routeSnapshot.url.map((segment) => segment.path).join('/'); 67 | if (!!route.snapshot.data['breadcrumb']) { 68 | this.breadcrumbs.push({ 69 | label: route.snapshot.data['breadcrumb'].includes(':') 70 | ? this.getResourceName( 71 | route.snapshot.data['breadcrumb'], 72 | routeSnapshot.params, 73 | route.snapshot.data['breadcrumb'].split(':')[1] 74 | ) 75 | : route.snapshot.data['breadcrumb'], 76 | url, 77 | }); 78 | if (route.snapshot.data['prependRoot']) { 79 | this.breadcrumbs.unshift({ 80 | label: 'Dashboard', 81 | url: '/', 82 | }); 83 | } 84 | } 85 | } 86 | currentRoute = route; 87 | } 88 | }); 89 | } while (currentRoute); 90 | } 91 | 92 | getResourceName(label: string, params: Record, routeParam: string) { 93 | return label.replace(`:${routeParam}`, params[routeParam]); 94 | } 95 | 96 | toggleNavigation() { 97 | this.isNavOpen = !this.isNavOpen; 98 | setTimeout(() => { 99 | this.eventBus.publish(EventMap.LayoutChangedEvent); 100 | }, 1000); 101 | } 102 | 103 | openYuniKornHelp(url: string) { 104 | const fullUrl = `http://yunikorn.apache.org${url}`; 105 | window.open(fullUrl, '_blank'); 106 | } 107 | 108 | openYuniKornLicense() { 109 | this.dialog.open(LicensesModalComponent, { 110 | maxWidth: '800px', 111 | disableClose: true, 112 | }); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/app/components/app-history/app-history.component.html: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 21 | 22 | Application History 23 | 24 |
25 | 26 |
27 |
-------------------------------------------------------------------------------- /src/app/components/app-history/app-history.component.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | .history-wrapper { 20 | height: 220px; 21 | } 22 | -------------------------------------------------------------------------------- /src/app/components/app-history/app-history.component.spec.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import {ComponentFixture, TestBed} from '@angular/core/testing'; 20 | import {MatCardModule} from '@angular/material/card'; 21 | import {AreaChartComponent} from '@app/components/area-chart/area-chart.component'; 22 | import {MockComponent} from 'ng-mocks'; 23 | 24 | import {AppHistoryComponent} from './app-history.component'; 25 | 26 | describe('AppHistoryComponent', () => { 27 | let component: AppHistoryComponent; 28 | let fixture: ComponentFixture; 29 | 30 | beforeAll(() => { 31 | TestBed.configureTestingModule({ 32 | declarations: [AppHistoryComponent, MockComponent(AreaChartComponent)], 33 | imports: [MatCardModule], 34 | }).compileComponents(); 35 | }); 36 | 37 | beforeEach(() => { 38 | fixture = TestBed.createComponent(AppHistoryComponent); 39 | component = fixture.componentInstance; 40 | fixture.detectChanges(); 41 | }); 42 | 43 | it('should create the component', () => { 44 | expect(component).toBeTruthy(); 45 | }); 46 | }); 47 | -------------------------------------------------------------------------------- /src/app/components/app-history/app-history.component.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import { Component, OnInit, Input } from '@angular/core'; 20 | 21 | import { AreaDataItem } from '@app/models/area-data.model'; 22 | 23 | @Component({ 24 | selector: 'app-application-history', 25 | templateUrl: './app-history.component.html', 26 | styleUrls: ['./app-history.component.scss'], 27 | }) 28 | export class AppHistoryComponent implements OnInit { 29 | @Input() chartData: AreaDataItem[] = []; 30 | 31 | constructor() {} 32 | 33 | ngOnInit() {} 34 | } 35 | -------------------------------------------------------------------------------- /src/app/components/app-node-utilizations/app-node-utilizations.component.html: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 21 |
22 | 23 | Node Resource Utilization 24 |
25 |
26 | 27 | Partition 28 | 32 | 33 | {{ part.name }} 34 | 35 | 36 | 37 |
38 |
39 |
40 |
41 | 42 |
43 |
44 |
-------------------------------------------------------------------------------- /src/app/components/app-node-utilizations/app-node-utilizations.component.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | ::ng-deep .app-node-utilizations { 20 | .header { 21 | justify-content: space-between; 22 | } 23 | 24 | .partition-selector { 25 | .mat-mdc-form-field-subscript-wrapper { 26 | display: none; 27 | } 28 | } 29 | 30 | .chart-wrapper { 31 | max-height: 400px; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/app/components/app-status/app-status.component.html: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 21 | 22 | Application Status 23 | 24 |
25 |
26 | 27 |
28 |
29 |
30 | 31 | {{ data.name }} 32 | {{ data.value }} 33 |
34 |
35 |
36 |
-------------------------------------------------------------------------------- /src/app/components/app-status/app-status.component.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | .status-wrapper { 20 | align-items: center; 21 | gap: 12px; 22 | height: 220px; 23 | } 24 | .chart-wrapper { 25 | max-width: 220px; 26 | z-index: 1; 27 | } 28 | .chart-legend { 29 | min-width: 140px; 30 | max-width: 200px; 31 | max-height: 220px; 32 | overflow: auto; 33 | margin: 0 auto; 34 | font-size: 0.8em; 35 | font-weight: 500; 36 | color: #666; 37 | > div { 38 | margin: 12px 0; 39 | } 40 | .legend-label { 41 | padding-left: 10px; 42 | } 43 | .legend-value { 44 | float: right; 45 | padding-right: 20px; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/app/components/app-status/app-status.component.spec.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import {ComponentFixture, TestBed} from '@angular/core/testing'; 20 | import {MatCardModule} from '@angular/material/card'; 21 | import {DonutChartComponent} from '@app/components/donut-chart/donut-chart.component'; 22 | import {MockComponent} from 'ng-mocks'; 23 | 24 | import {AppStatusComponent} from './app-status.component'; 25 | 26 | describe('AppStatusComponent', () => { 27 | let component: AppStatusComponent; 28 | let fixture: ComponentFixture; 29 | 30 | beforeAll(() => { 31 | TestBed.configureTestingModule({ 32 | declarations: [AppStatusComponent, MockComponent(DonutChartComponent)], 33 | imports: [MatCardModule], 34 | }).compileComponents(); 35 | }); 36 | 37 | beforeEach(() => { 38 | fixture = TestBed.createComponent(AppStatusComponent); 39 | component = fixture.componentInstance; 40 | fixture.detectChanges(); 41 | }); 42 | 43 | it('should create the component', () => { 44 | expect(component).toBeTruthy(); 45 | }); 46 | }); 47 | -------------------------------------------------------------------------------- /src/app/components/app-status/app-status.component.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import { Component, OnInit, Input } from '@angular/core'; 20 | import { ChartDataItem } from '@app/models/chart-data.model'; 21 | 22 | @Component({ 23 | selector: 'app-application-status', 24 | templateUrl: './app-status.component.html', 25 | styleUrls: ['./app-status.component.scss'], 26 | }) 27 | export class AppStatusComponent implements OnInit { 28 | @Input() chartData: ChartDataItem[] = []; 29 | 30 | constructor() {} 31 | 32 | ngOnInit() {} 33 | } 34 | -------------------------------------------------------------------------------- /src/app/components/area-chart/area-chart.component.html: -------------------------------------------------------------------------------- 1 | 18 | 19 |
20 | 21 |
22 | -------------------------------------------------------------------------------- /src/app/components/area-chart/area-chart.component.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | .area-chart { 20 | width: 100%; 21 | height: 100%; 22 | } 23 | -------------------------------------------------------------------------------- /src/app/components/area-chart/area-chart.component.spec.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import {ComponentFixture, TestBed} from '@angular/core/testing'; 20 | 21 | import {AreaChartComponent} from './area-chart.component'; 22 | 23 | describe('AreaChartComponent', () => { 24 | let component: AreaChartComponent; 25 | let fixture: ComponentFixture; 26 | 27 | beforeAll(() => { 28 | TestBed.configureTestingModule({ 29 | declarations: [AreaChartComponent], 30 | }).compileComponents(); 31 | }); 32 | 33 | beforeEach(() => { 34 | fixture = TestBed.createComponent(AreaChartComponent); 35 | component = fixture.componentInstance; 36 | fixture.detectChanges(); 37 | }); 38 | 39 | it('should create the component', () => { 40 | expect(component).toBeTruthy(); 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /src/app/components/card/card.component.html: -------------------------------------------------------------------------------- 1 | 18 | 19 |
20 |
21 | 22 |
23 |
24 | 25 |
26 |
-------------------------------------------------------------------------------- /src/app/components/card/card.component.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | .card-wrapper { 20 | border: 2px solid #d5d9e4; 21 | border-radius: 8px; 22 | background-color: #eee; 23 | padding: 16px; 24 | } 25 | 26 | .header { 27 | color: #172940; 28 | font-weight: 600; 29 | font-size: 20px; 30 | display: flex; 31 | align-items: center; 32 | gap: 8px; 33 | } 34 | 35 | .body { 36 | padding-top: 12px; 37 | } -------------------------------------------------------------------------------- /src/app/components/card/card.component.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import { Component, OnInit, Input } from '@angular/core'; 20 | 21 | @Component({ 22 | selector: 'app-card', 23 | templateUrl: './card.component.html', 24 | styleUrls: ['./card.component.scss'], 25 | }) 26 | export class CardComponent implements OnInit { 27 | constructor() {} 28 | 29 | ngOnInit() {} 30 | } 31 | -------------------------------------------------------------------------------- /src/app/components/container-history/container-history.component.html: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 21 | 22 | Container History 23 | 24 |
25 | 26 |
27 |
-------------------------------------------------------------------------------- /src/app/components/container-history/container-history.component.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | .history-wrapper { 20 | height: 220px; 21 | } 22 | -------------------------------------------------------------------------------- /src/app/components/container-history/container-history.component.spec.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import {ComponentFixture, TestBed} from '@angular/core/testing'; 20 | import {MatCardModule} from '@angular/material/card'; 21 | import {AreaChartComponent} from '@app/components/area-chart/area-chart.component'; 22 | import {MockComponent} from 'ng-mocks'; 23 | 24 | import {ContainerHistoryComponent} from './container-history.component'; 25 | 26 | describe('ContainerHistoryComponent', () => { 27 | let component: ContainerHistoryComponent; 28 | let fixture: ComponentFixture; 29 | 30 | beforeAll(() => { 31 | TestBed.configureTestingModule({ 32 | declarations: [ContainerHistoryComponent, MockComponent(AreaChartComponent)], 33 | imports: [MatCardModule], 34 | }).compileComponents(); 35 | }); 36 | 37 | beforeEach(() => { 38 | fixture = TestBed.createComponent(ContainerHistoryComponent); 39 | component = fixture.componentInstance; 40 | fixture.detectChanges(); 41 | }); 42 | 43 | it('should create the component', () => { 44 | expect(component).toBeTruthy(); 45 | }); 46 | }); 47 | -------------------------------------------------------------------------------- /src/app/components/container-history/container-history.component.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import { Component, OnInit, Input } from '@angular/core'; 20 | 21 | import { AreaDataItem } from '@app/models/area-data.model'; 22 | 23 | @Component({ 24 | selector: 'app-container-history', 25 | templateUrl: './container-history.component.html', 26 | styleUrls: ['./container-history.component.scss'], 27 | }) 28 | export class ContainerHistoryComponent implements OnInit { 29 | @Input() chartData: AreaDataItem[] = []; 30 | 31 | constructor() {} 32 | 33 | ngOnInit() {} 34 | } 35 | -------------------------------------------------------------------------------- /src/app/components/container-status/container-status.component.html: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 21 | 22 | Container Status 23 | 24 |
25 |
26 | 27 |
28 |
29 |
30 | 31 | {{ data.name }} 32 | {{ data.value }} 33 |
34 |
35 |
36 |
-------------------------------------------------------------------------------- /src/app/components/container-status/container-status.component.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | .status-wrapper { 20 | align-items: center; 21 | gap: 12px; 22 | height: 220px; 23 | } 24 | .chart-wrapper { 25 | max-width: 220px; 26 | } 27 | .chart-legend { 28 | min-width: 140px; 29 | max-width: 200px; 30 | margin: 0 auto; 31 | font-size: 0.8em; 32 | font-weight: 500; 33 | color: #666; 34 | > div { 35 | margin: 12px 0; 36 | } 37 | .legend-label { 38 | padding-left: 10px; 39 | } 40 | .legend-value { 41 | float: right; 42 | padding-right: 20px; 43 | } 44 | } -------------------------------------------------------------------------------- /src/app/components/container-status/container-status.component.spec.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import {ComponentFixture, TestBed} from '@angular/core/testing'; 20 | import {MatCardModule} from '@angular/material/card'; 21 | import {DonutChartComponent} from '@app/components/donut-chart/donut-chart.component'; 22 | import {MockComponent} from 'ng-mocks'; 23 | 24 | import {ContainerStatusComponent} from './container-status.component'; 25 | 26 | describe('ContainerStatusComponent', () => { 27 | let component: ContainerStatusComponent; 28 | let fixture: ComponentFixture; 29 | 30 | beforeAll(() => { 31 | TestBed.configureTestingModule({ 32 | declarations: [ContainerStatusComponent, MockComponent(DonutChartComponent)], 33 | imports: [MatCardModule], 34 | }).compileComponents(); 35 | }); 36 | 37 | beforeEach(() => { 38 | fixture = TestBed.createComponent(ContainerStatusComponent); 39 | component = fixture.componentInstance; 40 | fixture.detectChanges(); 41 | }); 42 | 43 | it('should create the component', () => { 44 | expect(component).toBeTruthy(); 45 | }); 46 | }); 47 | -------------------------------------------------------------------------------- /src/app/components/container-status/container-status.component.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import { Component, OnInit, Input } from '@angular/core'; 20 | import { ChartDataItem } from '@app/models/chart-data.model'; 21 | 22 | @Component({ 23 | selector: 'app-container-status', 24 | templateUrl: './container-status.component.html', 25 | styleUrls: ['./container-status.component.scss'], 26 | }) 27 | export class ContainerStatusComponent implements OnInit { 28 | @Input() chartData: ChartDataItem[] = []; 29 | 30 | constructor() {} 31 | 32 | ngOnInit() {} 33 | } 34 | -------------------------------------------------------------------------------- /src/app/components/dashboard/dashboard.component.html: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 |
21 |
22 |
Name
23 |
{{ clusterInfo.clusterName }}
24 |
25 |
26 |
Status
27 |
{{ clusterInfo.clusterStatus }}
28 |
29 |
30 |
Nodes
31 |
{{ totalNodes | titlecase }}
32 |
33 |
34 |
NodeSort Policy
35 |
{{ nodeSortPolicy | titlecase }}
36 |
37 |
38 |
Applications
39 |
{{ totalApplications | titlecase }}
40 |
41 |
42 |
Containers
43 |
{{ totalContainers | titlecase }}
44 |
45 |
46 |
Partition
47 |
{{ partitionName | titlecase }}
48 |
49 |
50 | 59 | 60 |
61 |
62 |
Build Date
63 |
{{ buildInfo.buildDate }}
64 |
65 |
66 |
Build Version
67 |
{{ buildInfo.buildVersion }}
68 |
69 |
70 |
RM Id
71 |
{{ buildInfo.rmId }}
72 |
73 |
74 |
75 |
76 |
77 |
78 | 79 |
80 |
81 |
82 | 83 |
84 |
85 | 86 |
87 |
88 |
89 |
90 | 91 |
92 |
93 | 94 |
95 |
96 |
97 | 98 |
99 | 100 |
-------------------------------------------------------------------------------- /src/app/components/dashboard/dashboard.component.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | .mat-mdc-card { 20 | padding: 20px; 21 | margin-bottom: 20px; 22 | } 23 | 24 | .top-info { 25 | border-radius: 8px; 26 | box-shadow: rgba(100, 100, 111, 0.1) 0px 2px 12px 0px; 27 | } 28 | 29 | .info-label { 30 | font-size: 14px; 31 | line-height: 19px; 32 | } 33 | 34 | .info-value { 35 | font-size: 18px; 36 | line-height: 24px; 37 | } 38 | 39 | .cluster-info { 40 | width: 100%; 41 | height: 100%; 42 | margin-top: 30px; 43 | .left-col { 44 | width: 35%; 45 | max-width: 35%; 46 | margin-right: 30px; 47 | min-width: 320px; 48 | } 49 | .right-col { 50 | width: 65%; 51 | max-width: 65%; 52 | } 53 | .half-col { 54 | width: 50%; 55 | max-width: 50%; 56 | } 57 | .grid-row { 58 | margin-top: 30px; 59 | } 60 | } 61 | 62 | .info-card > .menu-trigger { 63 | background: #d7d7d7; 64 | font-size: 14px; 65 | color: #666; 66 | outline: none; 67 | cursor: pointer; 68 | border-radius: 8px; 69 | margin: 0px; 70 | &:hover { 71 | background: #666; 72 | color: #fff; 73 | } 74 | } 75 | 76 | .about-card { 77 | flex-direction: column; 78 | font-size: 14px; 79 | padding: 10px; 80 | line-height: 22px; 81 | } 82 | 83 | .about-card .info-value { 84 | font-size: 14px; 85 | margin: 0 0 3px 0; 86 | } 87 | -------------------------------------------------------------------------------- /src/app/components/dashboard/dashboard.component.spec.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 20 | import { RouterTestingModule } from '@angular/router/testing'; 21 | import { MatCardModule } from '@angular/material/card'; 22 | import { MatMenuModule } from '@angular/material/menu'; 23 | import { NgxSpinnerService } from 'ngx-spinner'; 24 | import { MockComponent } from 'ng-mocks'; 25 | 26 | import { DashboardComponent } from './dashboard.component'; 27 | import { AppStatusComponent } from '@app/components/app-status/app-status.component'; 28 | import { AppHistoryComponent } from '@app/components/app-history/app-history.component'; 29 | import { ContainerStatusComponent } from '@app/components/container-status/container-status.component'; 30 | import { ContainerHistoryComponent } from '@app/components/container-history/container-history.component'; 31 | import { SchedulerService } from '@app/services/scheduler/scheduler.service'; 32 | import { EventBusService } from '@app/services/event-bus/event-bus.service'; 33 | import { 34 | MockSchedulerService, 35 | MockNgxSpinnerService, 36 | MockEventBusService, 37 | } from '@app/testing/mocks'; 38 | 39 | describe('DashboardComponent', () => { 40 | let component: DashboardComponent; 41 | let fixture: ComponentFixture; 42 | 43 | beforeAll(() => { 44 | TestBed.configureTestingModule({ 45 | declarations: [ 46 | DashboardComponent, 47 | MockComponent(AppStatusComponent), 48 | MockComponent(AppHistoryComponent), 49 | MockComponent(ContainerStatusComponent), 50 | MockComponent(ContainerHistoryComponent), 51 | ], 52 | imports: [MatCardModule, MatMenuModule, RouterTestingModule], 53 | providers: [ 54 | { provide: SchedulerService, useValue: MockSchedulerService }, 55 | { provide: NgxSpinnerService, useValue: MockNgxSpinnerService }, 56 | { provide: EventBusService, useValue: MockEventBusService }, 57 | ], 58 | }).compileComponents(); 59 | }); 60 | 61 | beforeEach(() => { 62 | fixture = TestBed.createComponent(DashboardComponent); 63 | component = fixture.componentInstance; 64 | fixture.detectChanges(); 65 | }); 66 | 67 | it('should create the component', () => { 68 | expect(component).toBeTruthy(); 69 | }); 70 | }); 71 | -------------------------------------------------------------------------------- /src/app/components/donut-chart/donut-chart.component.html: -------------------------------------------------------------------------------- 1 | 18 | 19 |
20 | 21 |
22 | 23 |

{{ totalCount }}

24 |
25 |
26 | -------------------------------------------------------------------------------- /src/app/components/donut-chart/donut-chart.component.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | .donut-chart-wrapper { 20 | position: relative; 21 | width: 100%; 22 | height: 100%; 23 | display: flex; 24 | justify-content: center; 25 | align-items: center; 26 | } 27 | 28 | .donut-chart { 29 | width: 100%; 30 | height: 100%; 31 | } 32 | 33 | .total-count { 34 | position: absolute; 35 | top: 50%; 36 | left: 50%; 37 | transform: translate(-50%, -50%); 38 | text-align: center; 39 | 40 | .label { 41 | font-size: 14px; 42 | font-weight: 300; 43 | } 44 | 45 | .value { 46 | font-size: 28px; 47 | font-weight: 500; 48 | margin: 4px 0px; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/app/components/donut-chart/donut-chart.component.spec.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import {ComponentFixture, TestBed} from '@angular/core/testing'; 20 | 21 | import {DonutChartComponent} from './donut-chart.component'; 22 | 23 | describe('DonutChartComponent', () => { 24 | let component: DonutChartComponent; 25 | let fixture: ComponentFixture; 26 | 27 | beforeAll(() => { 28 | TestBed.configureTestingModule({ 29 | declarations: [DonutChartComponent], 30 | }).compileComponents(); 31 | }); 32 | 33 | beforeEach(() => { 34 | fixture = TestBed.createComponent(DonutChartComponent); 35 | component = fixture.componentInstance; 36 | fixture.detectChanges(); 37 | }); 38 | 39 | it('should create the component', () => { 40 | expect(component).toBeTruthy(); 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /src/app/components/donut-chart/donut-chart.component.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import { 20 | Component, 21 | OnInit, 22 | AfterViewInit, 23 | Input, 24 | OnChanges, 25 | SimpleChanges, 26 | OnDestroy, 27 | } from '@angular/core'; 28 | import { Subject } from 'rxjs'; 29 | import { takeUntil } from 'rxjs/operators'; 30 | import { Chart, ArcElement, DoughnutController, Tooltip } from 'chart.js'; 31 | import { CommonUtil } from '@app/utils/common.util'; 32 | import { ChartDataItem } from '@app/models/chart-data.model'; 33 | import { EventBusService, EventMap } from '@app/services/event-bus/event-bus.service'; 34 | 35 | Chart.register(ArcElement, DoughnutController, Tooltip); 36 | 37 | @Component({ 38 | selector: 'app-donut-chart', 39 | templateUrl: './donut-chart.component.html', 40 | styleUrls: ['./donut-chart.component.scss'], 41 | }) 42 | export class DonutChartComponent implements OnInit, AfterViewInit, OnChanges, OnDestroy { 43 | destroy$ = new Subject(); 44 | chartContainerId = ''; 45 | donutChartData: ChartDataItem[] = []; 46 | donutChart: Chart<'doughnut', number[], string> | undefined; 47 | 48 | @Input() data: ChartDataItem[] = []; 49 | 50 | constructor(private eventBus: EventBusService) {} 51 | 52 | get totalCount(): number { 53 | return this.data.reduce((acc, item) => acc + item.value, 0); 54 | } 55 | 56 | ngOnInit() { 57 | this.chartContainerId = CommonUtil.createUniqId('donut_chart_'); 58 | 59 | this.eventBus 60 | .getEvent(EventMap.WindowResizedEvent) 61 | .pipe(takeUntil(this.destroy$)) 62 | .subscribe(() => this.renderChart(this.donutChartData)); 63 | } 64 | 65 | ngOnDestroy() { 66 | this.destroy$.next(true); 67 | this.destroy$.unsubscribe(); 68 | } 69 | 70 | ngAfterViewInit() { 71 | if (this.data) { 72 | this.renderChart(this.data); 73 | } 74 | } 75 | 76 | ngOnChanges(changes: SimpleChanges) { 77 | if ( 78 | changes['data'] && 79 | changes['data'].currentValue && 80 | changes['data'].currentValue.length > 0 81 | ) { 82 | this.donutChartData = changes['data'].currentValue; 83 | this.renderChart(this.donutChartData); 84 | } 85 | } 86 | 87 | renderChart(chartData: ChartDataItem[] = []) { 88 | if (!this.chartContainerId) { 89 | return; 90 | } 91 | const ctx = (document.getElementById(this.chartContainerId) as HTMLCanvasElement).getContext( 92 | '2d' 93 | ); 94 | 95 | const dataValues = chartData.map((d) => d.value); 96 | const chartLabels = chartData.map((d) => d.name); 97 | const colors = chartData.map((d) => d.color); 98 | 99 | if (this.donutChart) { 100 | this.donutChart.destroy(); 101 | } 102 | 103 | this.donutChart = new Chart(ctx!, { 104 | type: 'doughnut', 105 | data: { 106 | labels: chartLabels, 107 | datasets: [ 108 | { 109 | data: dataValues, 110 | backgroundColor: colors, 111 | borderWidth: 0, 112 | }, 113 | ], 114 | }, 115 | options: { 116 | responsive: true, 117 | animation: { 118 | animateScale: true, 119 | animateRotate: true, 120 | }, 121 | plugins: { 122 | legend: { 123 | display: false, 124 | }, 125 | title: { 126 | display: false, 127 | }, 128 | tooltip: { 129 | enabled: true, 130 | position: 'nearest', 131 | }, 132 | }, 133 | cutout: '70%', 134 | }, 135 | }); 136 | 137 | this.donutChart.update(); 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/app/components/error-view/error-view.component.html: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 21 | 22 | {{ apiError.statusCode }}: {{ apiError.message }} 23 | 24 | 25 | {{ apiError.description }} 26 | 27 | 28 | 29 | 30 | Oops, something went wrong. YuniKorn is not accessible. 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /src/app/components/error-view/error-view.component.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | .error-view { 20 | color: #cb0100; 21 | text-align: center; 22 | font-size: 16px; 23 | .center-header { 24 | display: flex; 25 | justify-content: center; 26 | } 27 | .try-btn { 28 | color: #333; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/app/components/error-view/error-view.component.spec.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import {ComponentFixture, TestBed} from '@angular/core/testing'; 20 | import {MatCardModule} from '@angular/material/card'; 21 | import {RouterTestingModule} from '@angular/router/testing'; 22 | 23 | import {ErrorViewComponent} from './error-view.component'; 24 | 25 | describe('ErrorViewComponent', () => { 26 | let component: ErrorViewComponent; 27 | let fixture: ComponentFixture; 28 | 29 | beforeAll(() => { 30 | TestBed.configureTestingModule({ 31 | imports: [MatCardModule, RouterTestingModule], 32 | declarations: [ErrorViewComponent], 33 | }).compileComponents(); 34 | }); 35 | 36 | beforeEach(() => { 37 | fixture = TestBed.createComponent(ErrorViewComponent); 38 | component = fixture.componentInstance; 39 | fixture.detectChanges(); 40 | }); 41 | 42 | it('should create the component', () => { 43 | expect(component).toBeTruthy(); 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /src/app/components/error-view/error-view.component.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import { Component, OnInit } from '@angular/core'; 20 | import { ActivatedRoute, Router } from '@angular/router'; 21 | import { ApiErrorInfo } from '@app/models/api-error-info.model'; 22 | 23 | @Component({ 24 | selector: 'app-error-view', 25 | templateUrl: './error-view.component.html', 26 | styleUrls: ['./error-view.component.scss'], 27 | }) 28 | export class ErrorViewComponent implements OnInit { 29 | apiError: ApiErrorInfo | null = null; 30 | lastActiveUrl = ''; 31 | 32 | constructor(private activatedRoute: ActivatedRoute, private router: Router) {} 33 | 34 | ngOnInit() { 35 | this.apiError = window.history.state; 36 | this.lastActiveUrl = this.activatedRoute.snapshot.queryParams['last']; 37 | } 38 | 39 | retryLastActiveUrlAgain() { 40 | if (this.lastActiveUrl) { 41 | this.router.navigateByUrl(this.lastActiveUrl); 42 | } else { 43 | this.router.navigateByUrl('/'); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/app/components/healthchecks/healthchecks.component.html: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 21 | 22 | 23 | Healthy 24 | 25 | 26 | Scheduler status 27 | 28 | done 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | {{ healthCheck.Name }} 37 | 38 | 39 | {{ healthCheck.Description }} 40 | 41 | done 42 | 43 | 44 | 45 |

{{ healthCheck.DiagnosisMessage }}

46 |
47 |
48 | 49 | 50 | close 51 | 52 | -------------------------------------------------------------------------------- /src/app/components/healthchecks/healthchecks.component.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | @import '~material-design-icons/iconfont/material-icons.css'; 20 | 21 | .healthcheck-headers-align .mat-expansion-panel-header-title, 22 | .healthcheck-headers-align .mat-expansion-panel-header-description { 23 | flex-basis: 0; 24 | } 25 | 26 | .healthcheck-headers-align .mat-expansion-panel-header-description { 27 | justify-content: space-between; 28 | align-items: center; 29 | } 30 | 31 | .healthcheck-headers-align .mat-mdc-form-field + .mat-form-field { 32 | margin-left: 8px; 33 | } 34 | -------------------------------------------------------------------------------- /src/app/components/healthchecks/healthchecks.component.spec.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import {ComponentFixture, TestBed} from '@angular/core/testing'; 20 | import {MatExpansionModule} from "@angular/material/expansion"; 21 | import {MatIconModule} from "@angular/material/icon"; 22 | import {NoopAnimationsModule} from "@angular/platform-browser/animations"; 23 | import {RouterTestingModule} from "@angular/router/testing"; 24 | 25 | import {HealthchecksComponent} from './healthchecks.component'; 26 | 27 | describe('HealthchecksComponent', () => { 28 | let component: HealthchecksComponent; 29 | let fixture: ComponentFixture; 30 | 31 | beforeEach(() => { 32 | TestBed.configureTestingModule({ 33 | declarations: [ HealthchecksComponent ], 34 | imports: [ 35 | NoopAnimationsModule, 36 | RouterTestingModule, 37 | MatIconModule, 38 | MatExpansionModule, 39 | ], 40 | }) 41 | .compileComponents(); 42 | fixture = TestBed.createComponent(HealthchecksComponent); 43 | component = fixture.componentInstance; 44 | fixture.detectChanges(); 45 | }); 46 | 47 | it('should create', () => { 48 | expect(component).toBeTruthy(); 49 | }); 50 | }); 51 | -------------------------------------------------------------------------------- /src/app/components/healthchecks/healthchecks.component.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import { Component, Input, OnInit } from '@angular/core'; 20 | import { SchedulerHealthInfo } from "@app/models/scheduler-health-info.model"; 21 | 22 | @Component({ 23 | selector: 'app-healthchecks', 24 | templateUrl: './healthchecks.component.html', 25 | styleUrls: ['./healthchecks.component.scss'] 26 | }) 27 | 28 | export class HealthchecksComponent implements OnInit { 29 | @Input() schedulerHealth: SchedulerHealthInfo = new SchedulerHealthInfo; 30 | 31 | constructor() { } 32 | 33 | ngOnInit(): void { 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/app/components/licenses-modal/licenses-modal.component.html: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 23 | 24 | 27 | 28 | 31 | -------------------------------------------------------------------------------- /src/app/components/licenses-modal/licenses-modal.component.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | .licenses-modal { 20 | display: flex; 21 | flex-direction: column; 22 | height: 100%; 23 | max-width: 750px; 24 | 25 | .modal-header { 26 | position: sticky; 27 | top: 0; 28 | z-index: 1; 29 | color: rgb(51,51,51); 30 | } 31 | 32 | .modal-body { 33 | flex-grow: 1; 34 | overflow-y: auto; 35 | 36 | pre { 37 | word-wrap: break-word; 38 | white-space: pre-wrap; 39 | font-size: 12px; 40 | line-height: 13px; 41 | } 42 | } 43 | 44 | .modal-footer { 45 | position: sticky; 46 | bottom: 0; 47 | padding-top: 10px; 48 | border-top: 1px solid #e9e9e9; 49 | z-index: 1; 50 | text-align: right; 51 | } 52 | } -------------------------------------------------------------------------------- /src/app/components/licenses-modal/licenses-modal.component.spec.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 20 | 21 | import { LicensesModalComponent } from './licenses-modal.component'; 22 | import { MatDialogRef, MatDialogModule } from '@angular/material/dialog'; 23 | import { HttpClientTestingModule } from '@angular/common/http/testing'; 24 | 25 | describe('LicensesModalComponent', () => { 26 | let component: LicensesModalComponent; 27 | let fixture: ComponentFixture; 28 | 29 | beforeEach(async () => { 30 | await TestBed.configureTestingModule({ 31 | declarations: [LicensesModalComponent], 32 | providers: [{ provide: MatDialogRef, useValue: {} }], 33 | imports: [HttpClientTestingModule, MatDialogModule], 34 | }).compileComponents(); 35 | fixture = TestBed.createComponent(LicensesModalComponent); 36 | component = fixture.componentInstance; 37 | fixture.detectChanges(); 38 | }); 39 | 40 | it('should create', () => { 41 | expect(component).toBeTruthy(); 42 | }); 43 | }); 44 | -------------------------------------------------------------------------------- /src/app/components/licenses-modal/licenses-modal.component.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import { Component } from '@angular/core'; 20 | import { MatDialogRef } from '@angular/material/dialog'; 21 | import { HttpClient } from '@angular/common/http'; 22 | import { isDevMode } from '@angular/core'; 23 | 24 | @Component({ 25 | selector: 'app-licenses-modal', 26 | templateUrl: './licenses-modal.component.html', 27 | styleUrls: ['./licenses-modal.component.scss'], 28 | }) 29 | export class LicensesModalComponent { 30 | licenses = ''; 31 | 32 | constructor( 33 | private dialogRef: MatDialogRef, 34 | private httpClient: HttpClient 35 | ) { 36 | // Licenses file is generated during build time and is available at /3rdpartylicenses.txt 37 | // Dev mode uses the file from assets folder assets/example-licenses.txt 38 | const licensePath = isDevMode() ? 'LICENSE' : '3rdpartylicenses.txt'; 39 | 40 | this.httpClient.get(licensePath, { responseType: 'text' }).subscribe((data) => { 41 | if (data) this.licenses = data.replace(/\n/g, '
'); 42 | else this.licenses = 'No licenses found'; 43 | }); 44 | } 45 | 46 | close() { 47 | this.dialogRef.close(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/app/components/nodes-view/highlighttable-search.pipe.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import { Pipe, PipeTransform } from '@angular/core'; 20 | 21 | @Pipe({ 22 | name: 'highlightSearch' 23 | }) 24 | export class HighlightSearchPipe implements PipeTransform { 25 | 26 | transform(value: string, search: string): string { 27 | const valueStr = String(value); // Ensure numeric values are converted to strings 28 | // (?![^&;]+;) - to ensure that there are no HTML entities (such as & or <) 29 | // ex. value = "<span>" search = "span", The word 'span' will not be included in the matches 30 | // (?!<[^<>]*) - to ensure that there are no HTML tags (<...>) 31 | // ex. value = "" search = "span", The word 'span' will not be included in the matches 32 | return valueStr.replace(new RegExp('(?![^&;]+;)(?!<[^<>]*)(' + search + ')(?![^<>]*>)(?![^&;]+;)', 'gi'), '$1'); 33 | } 34 | 35 | } 36 | 37 | -------------------------------------------------------------------------------- /src/app/components/nodes-view/nodes-view.component.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | @import '~material-design-icons/iconfont/material-icons.css'; 19 | 20 | .top-part{ 21 | display: flex; 22 | justify-content: space-between; 23 | align-items: center; 24 | .dropdown-wrapper{ 25 | padding-right: 40px; 26 | .part-label { 27 | color: #333; 28 | font-size: 14px; 29 | margin-right: 10px; 30 | } 31 | } 32 | .right-wrapper{ 33 | display: flex; 34 | flex-direction: row; 35 | justify-content: flex-end; 36 | align-items: center; 37 | width: 35%; 38 | .filter{ 39 | width: 100%; 40 | margin: 0 30px; 41 | .mat-mdc-form-field{ 42 | width: 100%; 43 | } 44 | } 45 | .btn-wrapper { 46 | filter: drop-shadow(0px 2px 1px rgba(90, 90, 90, 0.5)); 47 | &:hover{ 48 | filter: drop-shadow(0px 3px 3px rgba(90, 90, 90, 0.5)); 49 | } 50 | :hover{ 51 | cursor: pointer; 52 | } 53 | .btn{ 54 | display: block; 55 | border: none; 56 | padding: 5px 16px; 57 | border-radius: 5px; 58 | font-size: 24px; 59 | transform: translateY(-13px); 60 | } 61 | .material-icons{ 62 | transform: translateY(2px); 63 | } 64 | } 65 | } 66 | 67 | } 68 | 69 | .nodes-view { 70 | width: 100%; 71 | .mat-mdc-header-cell { 72 | font-size: 15px; 73 | font-weight: 500; 74 | color: #666; 75 | } 76 | .mat-mdc-cell { 77 | color: #333; 78 | display: flex; 79 | flex-direction: column; 80 | align-items: flex-start; 81 | .mat-res-ul{ 82 | padding: 0; 83 | margin: 0; 84 | .mat-res-li{ 85 | list-style-type: none; 86 | } 87 | } 88 | .mat-toggle-more { 89 | display: block; 90 | color: #a1a3b7; 91 | padding: 5px 45px 0 0; 92 | &:hover { 93 | color: #8d00d4; 94 | } 95 | } 96 | .mat-attr-ul{ 97 | padding: 0; 98 | margin: 0; 99 | .mat-attr-li{ 100 | list-style-type: none; 101 | } 102 | } 103 | } 104 | .mat-mdc-row { 105 | &:hover { 106 | background: #cccccc; 107 | cursor: pointer; 108 | } 109 | &.selected-row { 110 | background: #303d54; 111 | .mat-mdc-cell { 112 | color: #fff; 113 | .mat-toggle-more { 114 | color: #b8bbff; 115 | &:hover { 116 | color: #b871dc; 117 | } 118 | } 119 | } 120 | } 121 | } 122 | .mat-mdc-header-cell.indicator-icon, 123 | .mat-mdc-cell.indicator-icon { 124 | max-width: 40px; 125 | font-size: 18px; 126 | display: flex; 127 | justify-content: center; 128 | align-items: center; 129 | } 130 | .node-allocations { 131 | margin-top: 20px; 132 | .mat-mdc-table { 133 | margin-top: 20px; 134 | } 135 | } 136 | .no-record { 137 | font-size: 14px; 138 | font-weight: 500; 139 | color: #666; 140 | width: 100%; 141 | text-align: center; 142 | } 143 | } -------------------------------------------------------------------------------- /src/app/components/nodes-view/nodes-view.component.spec.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 20 | import { NoopAnimationsModule } from '@angular/platform-browser/animations'; 21 | import { NgxSpinnerService } from 'ngx-spinner'; 22 | 23 | import { NodesViewComponent } from './nodes-view.component'; 24 | import { AppNodeUtilizationsComponent } from '@app/components/app-node-utilizations/app-node-utilizations.component'; 25 | import { VerticalBarChartComponent } from '@app/components/vertical-bar-chart/vertical-bar-chart.component'; 26 | 27 | import { SchedulerService } from '@app/services/scheduler/scheduler.service'; 28 | import { HAMMER_LOADER } from '@angular/platform-browser'; 29 | import { MockSchedulerService, MockNgxSpinnerService } from '@app/testing/mocks'; 30 | import { MatCardModule } from '@angular/material/card'; 31 | import { MatTableModule } from '@angular/material/table'; 32 | import { MatPaginatorModule } from '@angular/material/paginator'; 33 | import { MatDividerModule } from '@angular/material/divider'; 34 | import { MatSortModule } from '@angular/material/sort'; 35 | import { MatSelectModule } from '@angular/material/select'; 36 | import { MatFormFieldModule } from '@angular/material/form-field'; 37 | import { MatInputModule } from '@angular/material/input'; 38 | import { ReactiveFormsModule } from '@angular/forms'; 39 | 40 | describe('NodesViewComponent', () => { 41 | let component: NodesViewComponent; 42 | let fixture: ComponentFixture; 43 | 44 | beforeAll(() => { 45 | TestBed.configureTestingModule({ 46 | declarations: [NodesViewComponent], 47 | imports: [ 48 | NoopAnimationsModule, 49 | MatTableModule, 50 | MatPaginatorModule, 51 | MatDividerModule, 52 | MatSortModule, 53 | MatSelectModule, 54 | ], 55 | providers: [ 56 | { provide: SchedulerService, useValue: MockSchedulerService }, 57 | { provide: NgxSpinnerService, useValue: MockNgxSpinnerService }, 58 | { provide: HAMMER_LOADER, useValue: () => new Promise(() => {}) }, 59 | ], 60 | }).compileComponents(); 61 | }); 62 | 63 | beforeEach(() => { 64 | TestBed.configureTestingModule({ 65 | declarations: [NodesViewComponent, AppNodeUtilizationsComponent, VerticalBarChartComponent], 66 | imports: [MatFormFieldModule, MatInputModule, ReactiveFormsModule, MatCardModule], 67 | }) 68 | .compileComponents(); 69 | fixture = TestBed.createComponent(NodesViewComponent); 70 | component = fixture.componentInstance; 71 | }); 72 | 73 | it('should create the component', () => { 74 | expect(component).toBeTruthy(); 75 | }); 76 | }); 77 | -------------------------------------------------------------------------------- /src/app/components/queue-rack/queue-rack.component.html: -------------------------------------------------------------------------------- 1 | 18 | 19 |
20 | 21 |
27 |
28 | {{ item.queueName }} 29 |
30 | 31 | 32 | 33 | 34 | 35 |
36 | 37 |
38 |
39 | -------------------------------------------------------------------------------- /src/app/components/queue-rack/queue-rack.component.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | .mat-mdc-card.queue-item { 20 | max-width: 200px; 21 | padding: 0; 22 | margin-bottom: 20px; 23 | .queue-name { 24 | font-size: 1.2em; 25 | color: #333; 26 | align-items: center; 27 | padding: 12px 10px 10px; 28 | cursor: pointer; 29 | > a { 30 | text-decoration: none; 31 | color: #333; 32 | font-size: 18px; 33 | &:hover { 34 | color: #000; 35 | } 36 | } 37 | &.selected { 38 | background: #303d54 !important; 39 | color: #fff; 40 | > a { 41 | color: #fff; 42 | } 43 | } 44 | .queue-label { 45 | max-width: 162px; 46 | word-wrap: break-word; 47 | } 48 | } 49 | .fa-caret-right { 50 | position: absolute; 51 | right: -13px; 52 | font-size: 24px; 53 | color: #303d54; 54 | } 55 | } 56 | .queue-rack { 57 | padding: 20px 0px 20px 10px; 58 | border-right: 1px solid #ddd; 59 | height: calc(100vh - 190px); 60 | max-width: 236px; 61 | .queue-item:last-child { 62 | margin-bottom: 0; 63 | } 64 | overflow: hidden; 65 | overflow-y: auto; 66 | &::-webkit-scrollbar { 67 | -webkit-appearance: none; 68 | width: 11px; 69 | } 70 | &::-webkit-scrollbar-track { 71 | background-color: #ffffff; 72 | } 73 | &::-webkit-scrollbar-thumb { 74 | border-radius: 8px; 75 | border: 2px solid white; 76 | background-color: rgba(0, 0, 0, 0.5); 77 | } 78 | &::-webkit-scrollbar-thumb:hover { 79 | background-color: rgba(0, 0, 0, 0.5); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/app/components/queue-rack/queue-rack.component.spec.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 20 | import { MatCardModule } from '@angular/material/card'; 21 | import { MatProgressBarModule } from '@angular/material/progress-bar'; 22 | 23 | import { QueueRackComponent } from './queue-rack.component'; 24 | 25 | describe('QueueRackComponent', () => { 26 | let component: QueueRackComponent; 27 | let fixture: ComponentFixture; 28 | 29 | beforeAll(() => { 30 | TestBed.configureTestingModule({ 31 | declarations: [QueueRackComponent], 32 | imports: [MatCardModule, MatProgressBarModule], 33 | }).compileComponents(); 34 | }); 35 | 36 | beforeEach(() => { 37 | fixture = TestBed.createComponent(QueueRackComponent); 38 | component = fixture.componentInstance; 39 | fixture.detectChanges(); 40 | }); 41 | 42 | it('should create the component', () => { 43 | expect(component).toBeTruthy(); 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /src/app/components/queue-rack/queue-rack.component.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; 20 | 21 | import { QueueInfo, ToggleQueueChildrenEvent } from '@app/models/queue-info.model'; 22 | import { NOT_AVAILABLE } from '@app/utils/constants'; 23 | import { queueScheduler } from 'rxjs'; 24 | 25 | @Component({ 26 | selector: 'app-queue-rack', 27 | templateUrl: './queue-rack.component.html', 28 | styleUrls: ['./queue-rack.component.scss'], 29 | }) 30 | export class QueueRackComponent implements OnInit { 31 | @Input() queueList: QueueInfo[] | null = []; 32 | @Input() nextLevel = ''; 33 | 34 | @Output() toggleChildren = new EventEmitter(); 35 | @Output() queueSelected = new EventEmitter(); 36 | 37 | constructor() {} 38 | 39 | ngOnInit() {} 40 | 41 | toggleQueueChildren(event: Event, item: QueueInfo) { 42 | event.preventDefault(); 43 | event.stopPropagation(); 44 | this.collapseQueueList(item); 45 | item.isExpanded = !item.isExpanded; 46 | this.toggleChildren.emit({ 47 | queueItem: item, 48 | nextLevel: this.nextLevel, 49 | }); 50 | } 51 | 52 | collapseQueueList(item: QueueInfo) { 53 | if (this.queueList) { 54 | this.queueList.forEach((queue) => { 55 | if (queue !== item) { 56 | queue.isExpanded = false; 57 | } 58 | }); 59 | } 60 | } 61 | 62 | onQueueSelected(queue: QueueInfo) { 63 | queue.isSelected = !queue.isSelected; 64 | this.queueSelected.emit(queue); 65 | } 66 | 67 | getQueueCapacityColor(queue: QueueInfo) { 68 | const value = queue.absoluteUsedPercent; 69 | if (value > 60 && value <= 75) { 70 | return '#60cea5'; 71 | } else if (value > 75 && value < 90) { 72 | return '#ffbc0b'; 73 | } else if (value >= 90) { 74 | return '#ef6162'; 75 | } 76 | return '#fff'; 77 | } 78 | 79 | getProgressBarValue(queue: QueueInfo) { 80 | return queue.absoluteUsedPercent; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/app/components/queue-v2/queues-v2.component.spec.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; 20 | import { QueueV2Component } from './queues-v2.component'; 21 | import { SchedulerService } from '@app/services/scheduler/scheduler.service'; 22 | import { NgxSpinnerService } from 'ngx-spinner'; 23 | import { RouterTestingModule } from '@angular/router/testing'; 24 | import { of } from 'rxjs'; 25 | 26 | // Mock services 27 | class MockSchedulerService { 28 | fetchSchedulerQueues(partitionName: string) { 29 | return of({ 30 | rootQueue: { name: 'root', children: [{ name: 'child1' }] } 31 | }); 32 | } 33 | } 34 | 35 | class MockNgxSpinnerService { 36 | show() {} 37 | hide() {} 38 | } 39 | 40 | describe('QueueV2Component', () => { 41 | let component: QueueV2Component; 42 | let fixture: ComponentFixture; 43 | let schedulerService: SchedulerService; 44 | let spinnerService: NgxSpinnerService; 45 | 46 | beforeEach(waitForAsync(() => { 47 | TestBed.configureTestingModule({ 48 | declarations: [QueueV2Component], 49 | providers: [ 50 | { provide: SchedulerService, useClass: MockSchedulerService }, 51 | { provide: NgxSpinnerService, useClass: MockNgxSpinnerService } 52 | ], 53 | imports: [RouterTestingModule] 54 | }) 55 | .compileComponents(); 56 | })); 57 | 58 | beforeEach(() => { 59 | fixture = TestBed.createComponent(QueueV2Component); 60 | component = fixture.componentInstance; 61 | schedulerService = TestBed.inject(SchedulerService); 62 | spinnerService = TestBed.inject(NgxSpinnerService); 63 | fixture.detectChanges(); 64 | }); 65 | 66 | it('should create', () => { 67 | expect(component).toBeTruthy(); 68 | }); 69 | 70 | describe('fetchSchedulerQueuesForPartition', () => { 71 | it('should call SchedulerService and NgxSpinnerService methods', () => { 72 | const schedulerSpy = spyOn(schedulerService, 'fetchSchedulerQueues').and.callThrough(); 73 | const spinnerShowSpy = spyOn(spinnerService, 'show').and.callThrough(); 74 | const spinnerHideSpy = spyOn(spinnerService, 'hide').and.callThrough(); 75 | 76 | component.fetchSchedulerQueuesForPartition(); 77 | 78 | expect(schedulerSpy).toHaveBeenCalledWith('default'); 79 | expect(spinnerShowSpy).toHaveBeenCalledBefore(schedulerSpy); 80 | expect(spinnerHideSpy).toHaveBeenCalled(); 81 | expect(component.rootQueue).toBeTruthy(); 82 | }); 83 | }); 84 | }); 85 | -------------------------------------------------------------------------------- /src/app/components/queues-view/queues-view.component.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | .part-label { 20 | color: #333; 21 | font-size: 14px; 22 | margin-right: 10px; 23 | } 24 | .queues-view { 25 | overflow: hidden; 26 | overflow-x: auto; 27 | .queue-level { 28 | max-width: 240px; 29 | } 30 | } 31 | .mat-drawer-container { 32 | width: 430px; 33 | height: calc(100vh - 190px); 34 | background: #eee; 35 | position: absolute; 36 | right: 0; 37 | display: none; 38 | .mat-drawer { 39 | width: 100%; 40 | .content { 41 | padding: 0 10px; 42 | } 43 | } 44 | .close-btn { 45 | float: right; 46 | font-size: 1.2em; 47 | cursor: pointer; 48 | padding-right: 5px; 49 | &:hover { 50 | color: #f44336; 51 | } 52 | } 53 | .header { 54 | padding: 10px; 55 | height: 38px; 56 | border-bottom: 1px solid #ccc; 57 | font-size: 1.2em; 58 | font-weight: bold; 59 | } 60 | .item-wrapper { 61 | .left-item { 62 | text-align: right; 63 | } 64 | .left-item, 65 | .right-item { 66 | width: 50%; 67 | padding: 6px; 68 | padding-right: 0; 69 | font-size: 1.1em; 70 | color: #666; 71 | } 72 | .right-item { 73 | font-weight: 600; 74 | } 75 | } 76 | .app-link { 77 | text-decoration: none; 78 | font-size: 1.1em; 79 | color: #666; 80 | &:hover { 81 | text-decoration: underline; 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/app/components/queues-view/queues-view.component.spec.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import {ComponentFixture, TestBed} from '@angular/core/testing'; 20 | import {MatDividerModule} from '@angular/material/divider'; 21 | import {MatSelectModule} from '@angular/material/select'; 22 | import {MatSidenavModule} from '@angular/material/sidenav'; 23 | import {NoopAnimationsModule} from '@angular/platform-browser/animations'; 24 | import {RouterTestingModule} from '@angular/router/testing'; 25 | import {QueueRackComponent} from '@app/components/queue-rack/queue-rack.component'; 26 | import {SchedulerService} from '@app/services/scheduler/scheduler.service'; 27 | import {MockNgxSpinnerService, MockSchedulerService} from '@app/testing/mocks'; 28 | import {MockComponent} from 'ng-mocks'; 29 | import {NgxSpinnerService} from 'ngx-spinner'; 30 | 31 | import {QueuesViewComponent} from './queues-view.component'; 32 | 33 | describe('QueuesViewComponent', () => { 34 | let component: QueuesViewComponent; 35 | let fixture: ComponentFixture; 36 | 37 | beforeAll(() => { 38 | TestBed.configureTestingModule({ 39 | declarations: [QueuesViewComponent, MockComponent(QueueRackComponent)], 40 | imports: [ 41 | NoopAnimationsModule, 42 | RouterTestingModule, 43 | MatDividerModule, 44 | MatSelectModule, 45 | MatSidenavModule, 46 | ], 47 | providers: [ 48 | { provide: SchedulerService, useValue: MockSchedulerService }, 49 | { provide: NgxSpinnerService, useValue: MockNgxSpinnerService }, 50 | ], 51 | }).compileComponents(); 52 | }); 53 | 54 | beforeEach(() => { 55 | fixture = TestBed.createComponent(QueuesViewComponent); 56 | component = fixture.componentInstance; 57 | fixture.detectChanges(); 58 | }); 59 | 60 | it('should create the component', () => { 61 | expect(component).toBeTruthy(); 62 | }); 63 | }); 64 | -------------------------------------------------------------------------------- /src/app/components/status-view/status-view.component.html: -------------------------------------------------------------------------------- 1 | 18 | 19 |
20 |

Entrypoint healthCheck

21 | 22 |
23 | -------------------------------------------------------------------------------- /src/app/components/status-view/status-view.component.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | -------------------------------------------------------------------------------- /src/app/components/status-view/status-view.component.spec.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import {ComponentFixture, TestBed} from '@angular/core/testing'; 20 | 21 | import {SchedulerService} from '@app/services/scheduler/scheduler.service'; 22 | import {MockNgxSpinnerService, MockSchedulerService} from '@app/testing/mocks'; 23 | import {MockComponent} from 'ng-mocks'; 24 | import {NgxSpinnerService} from 'ngx-spinner'; 25 | 26 | import {StatusViewComponent} from './status-view.component'; 27 | 28 | describe('StatusViewComponent', () => { 29 | let component: StatusViewComponent; 30 | let fixture: ComponentFixture; 31 | 32 | 33 | beforeEach( () => { 34 | TestBed.configureTestingModule({ 35 | declarations: [ StatusViewComponent, MockComponent(StatusViewComponent) ], 36 | providers: [ 37 | { provide: SchedulerService, useValue: MockSchedulerService }, 38 | { provide: NgxSpinnerService, useValue: MockNgxSpinnerService }, 39 | ], 40 | }) 41 | .compileComponents(); 42 | fixture = TestBed.createComponent(StatusViewComponent); 43 | component = fixture.componentInstance; 44 | fixture.detectChanges(); 45 | }); 46 | 47 | it('should create', () => { 48 | expect(component).toBeTruthy(); 49 | }); 50 | }); 51 | -------------------------------------------------------------------------------- /src/app/components/status-view/status-view.component.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import { Component, OnInit } from '@angular/core'; 20 | import { NgxSpinnerService } from 'ngx-spinner'; 21 | import { finalize } from 'rxjs/operators'; 22 | 23 | import { SchedulerHealthInfo } from "@app/models/scheduler-health-info.model"; 24 | import { SchedulerService } from '@app/services/scheduler/scheduler.service'; 25 | 26 | @Component({ 27 | selector: 'app-status-view', 28 | templateUrl: './status-view.component.html', 29 | styleUrls: ['./status-view.component.scss'] 30 | }) 31 | 32 | export class StatusViewComponent implements OnInit { 33 | CurrentSchedulerHealth: SchedulerHealthInfo = new SchedulerHealthInfo; 34 | 35 | constructor( 36 | private scheduler: SchedulerService, 37 | private spinner: NgxSpinnerService 38 | ) {} 39 | 40 | ngOnInit() { 41 | this.spinner.show(); 42 | 43 | this.scheduler 44 | .fecthHealthchecks() 45 | .pipe( 46 | finalize(() => { 47 | this.spinner.hide(); 48 | }) 49 | ) 50 | .subscribe((healthInfos) => { 51 | if (healthInfos) { 52 | this.CurrentSchedulerHealth = healthInfos; 53 | } else { 54 | this.CurrentSchedulerHealth = new SchedulerHealthInfo; 55 | } 56 | }); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/app/components/vertical-bar-chart/vertical-bar-chart.component.html: -------------------------------------------------------------------------------- 1 | 18 |
19 | 20 |
21 | -------------------------------------------------------------------------------- /src/app/components/vertical-bar-chart/vertical-bar-chart.component.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | .chart-wrapper { 20 | width: 100%; 21 | height: 100%; 22 | 23 | .vertical-bar-chart { 24 | width: 100%; 25 | height: 100%; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/app/components/vertical-bar-chart/vertical-bar-chart.component.spec.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 20 | import { VerticalBarChartComponent } from './vertical-bar-chart.component'; 21 | 22 | describe('VerticalBarChartComponent', () => { 23 | let component: VerticalBarChartComponent; 24 | let fixture: ComponentFixture; 25 | 26 | beforeEach(() => { 27 | TestBed.configureTestingModule({ 28 | declarations: [VerticalBarChartComponent] 29 | }); 30 | fixture = TestBed.createComponent(VerticalBarChartComponent); 31 | component = fixture.componentInstance; 32 | fixture.detectChanges(); 33 | }); 34 | 35 | it('should create', () => { 36 | expect(component).toBeTruthy(); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /src/app/interceptors/api-error/api-error.interceptor.spec.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import {TestBed} from '@angular/core/testing'; 20 | import {RouterTestingModule} from '@angular/router/testing'; 21 | 22 | import {ApiErrorInterceptor} from './api-error.interceptor'; 23 | 24 | describe('ApiErrorInterceptor', () => { 25 | let interceptor: ApiErrorInterceptor; 26 | 27 | beforeAll(() => { 28 | TestBed.configureTestingModule({ 29 | imports: [RouterTestingModule], 30 | providers: [ApiErrorInterceptor], 31 | }).compileComponents(); 32 | }); 33 | 34 | beforeEach(() => { 35 | interceptor = TestBed.inject(ApiErrorInterceptor); 36 | }); 37 | 38 | it('should create the interceptor', () => { 39 | expect(interceptor).toBeTruthy(); 40 | }); 41 | }); 42 | -------------------------------------------------------------------------------- /src/app/interceptors/api-error/api-error.interceptor.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import { Injectable } from '@angular/core'; 20 | import { Router } from '@angular/router'; 21 | import { Observable, throwError } from 'rxjs'; 22 | import { catchError } from 'rxjs/operators'; 23 | import { 24 | HttpEvent, 25 | HttpInterceptor, 26 | HttpHandler, 27 | HttpRequest, 28 | HttpErrorResponse, 29 | } from '@angular/common/http'; 30 | import { ApiErrorInfo } from '@app/models/api-error-info.model'; 31 | 32 | @Injectable() 33 | export class ApiErrorInterceptor implements HttpInterceptor { 34 | constructor(private router: Router) {} 35 | 36 | intercept(request: HttpRequest, next: HttpHandler): Observable> { 37 | return next.handle(request).pipe(catchError(this.handleApiError.bind(this))); 38 | } 39 | 40 | handleApiError(response: HttpErrorResponse) { 41 | if (!this.router.url.startsWith('/error')) { 42 | this.router.navigate(['/error'], { 43 | queryParams: { last: this.router.url }, 44 | state: this.parseErrorResponse(response.error), 45 | }); 46 | } 47 | 48 | return throwError(() => response); 49 | } 50 | 51 | parseErrorResponse(error: any): ApiErrorInfo | undefined { 52 | if (error) { 53 | return { 54 | statusCode: error.StatusCode, 55 | message: error.Message, 56 | description: error.Description, 57 | }; 58 | } else { 59 | return undefined; 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/app/models/alloc-info.model.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | export class AllocationInfo { 20 | constructor( 21 | public displayName: string, 22 | public allocationKey: string, 23 | public allocationTags: null | string, 24 | public resource: string, 25 | public priority: string, 26 | public queueName: string, 27 | public nodeId: string, 28 | public applicationId: string, 29 | public partition: string 30 | ) {} 31 | } 32 | -------------------------------------------------------------------------------- /src/app/models/api-error-info.model.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | export interface ApiErrorInfo { 20 | statusCode: number; 21 | message: string; 22 | description: string; 23 | } 24 | -------------------------------------------------------------------------------- /src/app/models/app-info.model.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import { NOT_AVAILABLE } from '@app/utils/constants'; 20 | import * as moment from 'moment'; 21 | import { AllocationInfo } from './alloc-info.model'; 22 | 23 | export class AppInfo { 24 | isSelected = false; 25 | 26 | constructor( 27 | public applicationId: string, 28 | public usedResource: string, 29 | public pendingResource: string, 30 | public maxUsedResource: string, 31 | public submissionTime: number, 32 | public finishedTime: null | number, 33 | public stateLog: Array = [], // Default to empty array 34 | public lastStateChangeTime: null | number, 35 | public applicationState: string, 36 | public allocations: AllocationInfo[] | null 37 | ) { 38 | // Ensure stateLog is always an array 39 | if (!Array.isArray(this.stateLog)) { 40 | this.stateLog = []; 41 | } 42 | } 43 | 44 | get formattedSubmissionTime() { 45 | const millisecs = Math.round(this.submissionTime / (1000 * 1000)); 46 | return moment(millisecs).format('YYYY/MM/DD HH:mm:ss'); 47 | } 48 | 49 | get formattedlastStateChangeTime() { 50 | if(this.lastStateChangeTime==null){ 51 | return 'n/a' 52 | } 53 | const millisecs = Math.round(this.lastStateChangeTime! / (1000 * 1000)); 54 | return moment(millisecs).format('YYYY/MM/DD HH:mm:ss'); 55 | } 56 | 57 | get formattedFinishedTime() { 58 | if (this.finishedTime) { 59 | const millisecs = Math.round(this.finishedTime / (1000 * 1000)); 60 | return moment(millisecs).format('YYYY/MM/DD HH:mm:ss'); 61 | } 62 | 63 | return NOT_AVAILABLE; 64 | } 65 | 66 | setAllocations(allocs: AllocationInfo[]) { 67 | this.allocations = allocs; 68 | } 69 | 70 | setLastStateChangeTime() { 71 | let time=0 72 | this.stateLog.forEach(log => { 73 | if (log.time>time){ 74 | time=log.time 75 | } 76 | }); 77 | this.lastStateChangeTime=time 78 | } 79 | } 80 | 81 | export class StateLog{ 82 | constructor( 83 | public time: number, 84 | public applicationState: string 85 | ) {} 86 | } 87 | -------------------------------------------------------------------------------- /src/app/models/app-status.model.ts: -------------------------------------------------------------------------------- 1 | export type AppStatus = 2 | | 'New' 3 | | 'Accepted' 4 | | 'Starting' 5 | | 'Running' 6 | | 'Rejected' 7 | | 'Completing' 8 | | 'Completed' 9 | | 'Failing' 10 | | 'Failed' 11 | | 'Expired' 12 | | 'Resuming'; 13 | 14 | export type AppStatusColors = { 15 | [K in AppStatus]: string; 16 | } -------------------------------------------------------------------------------- /src/app/models/area-data.model.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | export class AreaDataItem { 20 | y: number; 21 | x: Date; 22 | 23 | constructor(value: number, date: Date) { 24 | this.y = value; 25 | this.x = date; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/app/models/chart-data.model.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | export class ChartDataItem { 20 | name: string; 21 | value: number; 22 | color?: string; 23 | description?: string; 24 | 25 | constructor(name: string, value: number, color?: string, description?: string) { 26 | this.name = name; 27 | this.value = value; 28 | this.color = color; 29 | this.description = description; 30 | } 31 | } 32 | 33 | export class BarChartDataSet { 34 | label: string; 35 | data: number[]; 36 | avgUtilizationRate: number; 37 | backgroundColor: string; 38 | borderWidth: number; 39 | description: string[]; 40 | 41 | constructor(label: string, data: number[], avgUtilizationRate: number, backgroundColor: string, borderWidth: number, description: string[]) { 42 | this.label = label; 43 | this.data = data; 44 | this.avgUtilizationRate = avgUtilizationRate; 45 | this.backgroundColor = backgroundColor; 46 | this.borderWidth = borderWidth; 47 | this.description = description; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/app/models/cluster-info.model.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | export interface ClusterInfo { 20 | startTime: number; 21 | rmBuildInformation: BuildInfo[]; 22 | partition: string; 23 | clusterName: string; 24 | clusterStatus?: string; 25 | } 26 | 27 | export interface BuildInfo { 28 | buildDate: string; 29 | buildVersion: string; 30 | isPluginVersion: string, 31 | rmId: string; 32 | } 33 | -------------------------------------------------------------------------------- /src/app/models/column-def.model.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | export interface ColumnDef { 20 | colId: string; 21 | colName: string; 22 | colFormatter?: (val: any) => any; 23 | colWidth?: number; 24 | } 25 | -------------------------------------------------------------------------------- /src/app/models/dropdown-item.model.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | export class DropdownItem { 20 | name: string; 21 | value: string; 22 | 23 | constructor(name: string, value: string) { 24 | this.name = name; 25 | this.value = value; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/app/models/envconfig.model.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | export interface EnvConfig { 20 | localSchedulerWebAddress: string; 21 | } 22 | -------------------------------------------------------------------------------- /src/app/models/history-info.model.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | export class HistoryInfo { 20 | timestamp: number; 21 | value: number; 22 | 23 | constructor(timestamp: number, value: number) { 24 | this.timestamp = timestamp; 25 | this.value = value; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/app/models/node-info.model.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import { AllocationInfo } from './alloc-info.model'; 20 | 21 | export class NodeInfo { 22 | isSelected = false; 23 | constructor( 24 | public nodeId: string, 25 | public hostName: string, 26 | public rackName: string, 27 | public partitionName: string, 28 | public capacity: string, 29 | public allocated: string, 30 | public occupied: string, 31 | public available: string, 32 | public utilized: string, 33 | public allocations: AllocationInfo[] | null, 34 | public attributes: Attributes, 35 | ) {} 36 | 37 | setAllocations(allocs: AllocationInfo[]) { 38 | this.allocations = allocs; 39 | } 40 | } 41 | 42 | export interface Attributes{ 43 | [key: string]: string; 44 | } 45 | -------------------------------------------------------------------------------- /src/app/models/node-utilization.model.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | export class NodeUtilization { 20 | constructor( 21 | public type: string, 22 | public utilization: { 23 | bucketName: string; 24 | numOfNodes: number; 25 | nodeNames: null | string[]; 26 | }[], 27 | ) { } 28 | } 29 | 30 | export class NodeUtilizationsInfo { 31 | constructor( 32 | public clusterId: string, 33 | public partition: string, 34 | public utilizations: NodeUtilization[], 35 | ) { } 36 | } 37 | -------------------------------------------------------------------------------- /src/app/models/partition-info.model.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | import { AppStatus } from './app-status.model' 19 | 20 | export class PartitionInfo { 21 | name: string; 22 | value: string; 23 | 24 | constructor(name: string, value: string) { 25 | this.name = name; 26 | this.value = value; 27 | } 28 | } 29 | 30 | export interface Partition { 31 | name: string; 32 | state: string; 33 | clusterId: string; 34 | capacity: Capacity; 35 | nodeSortingPolicy: NodeSortingPolicy; 36 | applications: Applications; 37 | lastStateTransitionTime: string; 38 | totalNodes: number; 39 | totalContainers: number; 40 | } 41 | 42 | export interface Capacity { 43 | capacity: string; 44 | usedCapacity: string; 45 | } 46 | 47 | export interface Applications extends Record { 48 | total: number; 49 | } 50 | 51 | export interface NodeSortingPolicy { 52 | type: string; 53 | resourceWeights: { 54 | memory: number; 55 | vcore: number; 56 | }; 57 | } 58 | -------------------------------------------------------------------------------- /src/app/models/queue-info.model.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | export class QueueInfo { 20 | queueName: string = ''; 21 | status: string = ''; 22 | partitionName: string = ''; 23 | maxResource: string = ''; 24 | guaranteedResource: string = ''; 25 | allocatedResource: string = ''; 26 | pendingResource: string=''; 27 | absoluteUsedCapacity: string = ''; 28 | absoluteUsedPercent: number = 0; 29 | parentQueue: null | QueueInfo = null; 30 | children: null | QueueInfo[] = null; 31 | properties: QueuePropertyItem[] = []; 32 | template: null | QueueTemplate = null; 33 | isLeaf: boolean = false; 34 | isManaged: boolean = false; 35 | isExpanded: boolean = false; 36 | isSelected: boolean = false; 37 | MaxRunningApps: number = 0; 38 | RunningApps: number = 0; 39 | } 40 | 41 | export interface QueuePropertyItem { 42 | name: string; 43 | value: string; 44 | } 45 | 46 | export interface QueueTemplate { 47 | maxResource: string; 48 | guaranteedResource: string; 49 | properties: { [key: string]: string }; 50 | } 51 | 52 | export interface SchedulerInfo { 53 | rootQueue: QueueInfo; 54 | } 55 | 56 | export interface ToggleQueueChildrenEvent { 57 | queueItem: QueueInfo; 58 | nextLevel: string; 59 | } 60 | -------------------------------------------------------------------------------- /src/app/models/resource-info.model.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | export interface ResourceInfo { 20 | memory: string; 21 | vcore: string; 22 | [key: string]: string; 23 | } 24 | 25 | export interface SchedulerResourceInfo { 26 | memory: number; 27 | vcore: number; 28 | [key: string]: number; 29 | } 30 | -------------------------------------------------------------------------------- /src/app/models/scheduler-health-info.model.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | export class SchedulerHealthInfo { 20 | Healthy: boolean = false; 21 | HealthChecks: null | HealthCheckInfo[] = []; 22 | } 23 | 24 | export interface HealthCheckInfo { 25 | Name: string; 26 | Succeeded: boolean; 27 | Description: string; 28 | DiagnosisMessage: string; 29 | } 30 | 31 | -------------------------------------------------------------------------------- /src/app/models/time-series-data.model.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | export interface TimeSeriesDataItem { 20 | value: number; 21 | timestamp: number; 22 | } 23 | -------------------------------------------------------------------------------- /src/app/services/envconfig/envconfig.service.spec.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import {HttpClientTestingModule} from '@angular/common/http/testing'; 20 | import {TestBed} from '@angular/core/testing'; 21 | 22 | import {EnvconfigService} from './envconfig.service'; 23 | 24 | describe('EnvconfigService', () => { 25 | let service: EnvconfigService; 26 | 27 | beforeAll(() => { 28 | TestBed.configureTestingModule({ 29 | imports: [HttpClientTestingModule], 30 | providers: [EnvconfigService], 31 | }).compileComponents(); 32 | }); 33 | 34 | beforeEach(() => { 35 | service = TestBed.inject(EnvconfigService); 36 | }); 37 | 38 | it('should create the service', () => { 39 | expect(service).toBeTruthy(); 40 | }); 41 | }); 42 | -------------------------------------------------------------------------------- /src/app/services/envconfig/envconfig.service.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import { Injectable } from '@angular/core'; 20 | import { HttpClient } from '@angular/common/http'; 21 | import { environment } from '../../../environments/environment'; 22 | 23 | import { EnvConfig } from '@app/models/envconfig.model'; 24 | import { DEFAULT_PROTOCOL } from '@app/utils/constants'; 25 | 26 | const ENV_CONFIG_JSON_URL = './assets/config/envconfig.json'; 27 | 28 | export function envConfigFactory(envConfig: EnvconfigService) { 29 | return () => envConfig.loadEnvConfig(); 30 | } 31 | 32 | @Injectable({ 33 | providedIn: 'root', 34 | }) 35 | export class EnvconfigService { 36 | private envConfig: EnvConfig; 37 | private uiProtocol: string; 38 | private uiHostname: string; 39 | private uiPort: string; 40 | 41 | constructor(private httpClient: HttpClient) { 42 | this.uiProtocol = window.location.protocol; 43 | this.uiHostname = window.location.hostname; 44 | this.uiPort = window.location.port; 45 | this.envConfig = { 46 | localSchedulerWebAddress: 'http://localhost:9889', 47 | }; 48 | } 49 | 50 | loadEnvConfig(): Promise { 51 | return new Promise((resolve) => { 52 | this.httpClient.get(ENV_CONFIG_JSON_URL).subscribe((data) => { 53 | this.envConfig = data; 54 | resolve(); 55 | }); 56 | }); 57 | } 58 | 59 | getSchedulerWebAddress() { 60 | if (!environment.production) { 61 | return this.envConfig.localSchedulerWebAddress; 62 | } 63 | 64 | return `${this.uiProtocol}//${this.uiHostname}:${this.uiPort}`; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/app/services/event-bus/event-bus.service.spec.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import {TestBed} from '@angular/core/testing'; 20 | 21 | import {EventBusService} from './event-bus.service'; 22 | 23 | describe('EventBusService', () => { 24 | let service: EventBusService; 25 | 26 | beforeAll(() => { 27 | TestBed.configureTestingModule({ 28 | providers: [EventBusService], 29 | }).compileComponents(); 30 | }); 31 | 32 | beforeEach(() => { 33 | service = TestBed.inject(EventBusService); 34 | }); 35 | 36 | it('should create the service', () => { 37 | expect(service).toBeTruthy(); 38 | }); 39 | }); 40 | -------------------------------------------------------------------------------- /src/app/services/event-bus/event-bus.service.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import { Injectable } from '@angular/core'; 20 | import { Observable, Subject } from 'rxjs'; 21 | 22 | export const EventMap = { 23 | LayoutChangedEvent: 'LAYOUT_CHANGED_EVENT', 24 | WindowResizedEvent: 'WINDOW_RESIZED_EVENT', 25 | }; 26 | 27 | interface EventRegistry { 28 | [eventName: string]: Subject; 29 | } 30 | 31 | @Injectable({ 32 | providedIn: 'root', 33 | }) 34 | export class EventBusService { 35 | private eventRegistry: EventRegistry = {}; 36 | 37 | constructor() {} 38 | 39 | getEvent(eventName: string): Observable { 40 | if (!this.eventRegistry[eventName]) { 41 | this.eventRegistry[eventName] = new Subject(); 42 | } 43 | 44 | const subject = this.eventRegistry[eventName]; 45 | return subject.asObservable(); 46 | } 47 | 48 | publish(eventName: string, data?: any) { 49 | const subject = this.eventRegistry[eventName]; 50 | 51 | if (subject) { 52 | subject.next(data); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/app/testing/mocks.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import { of } from 'rxjs'; 20 | import { AppInfo } from '@app/models/app-info.model'; 21 | import { CommonUtil } from '@app/utils/common.util'; 22 | 23 | export const noopFn = () => {}; 24 | 25 | export const MockSchedulerService = { 26 | fetchClusterByName: () => of({}), 27 | fetchClusterList: () => of([]), 28 | fetchPartitionList: () => of([]), 29 | fetchSchedulerQueues: () => of({}), 30 | fetchAppList: () => of([]), 31 | fetchAppHistory: () => of([]), 32 | fetchContainerHistory: () => of([]), 33 | fetchNodeList: () => of([]), 34 | fecthHealthchecks: () => of([]), 35 | }; 36 | 37 | export const MockNgxSpinnerService = { 38 | show: noopFn, 39 | hide: noopFn, 40 | }; 41 | 42 | export const MockEnvconfigService = { 43 | getSchedulerWebAddress: noopFn, 44 | }; 45 | 46 | export const MockEventBusService = { 47 | getEvent: () => of(), 48 | publish: noopFn, 49 | }; 50 | -------------------------------------------------------------------------------- /src/app/utils/constants.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import { AppStatus, AppStatusColors } from "@app/models/app-status.model"; 20 | 21 | export const DEFAULT_PARTITION_VALUE = ''; 22 | export const DEFAULT_PROTOCOL = 'http:'; 23 | export const NOT_AVAILABLE = 'n/a'; 24 | export const PARTITION_DEFAULT = 'default'; 25 | export const DEFAULT_BAR_COLOR = 'rgba(66, 133, 244, 1)'; 26 | export const CHART_COLORS = ['rgba(66, 133, 244, 1)', 'rgb(219, 68, 55, 1)', 'rgb(244, 180, 0, 1)', 'rgb(15, 157, 88, 1)', 'rgb(255, 109, 0, 1)', 'rgb(57, 73, 171, 1)', 'rgb(250, 204, 84, 1)', 'rgb(38, 187, 240, 1)', 'rgb(204, 97, 100, 1)', 'rgb(96, 206, 165, 1)'] 27 | 28 | export const APP_STATUSES: AppStatus[] = ['New', 'Accepted', 'Starting', 'Running', 'Rejected', 'Completing', 'Completed', 'Failing', 'Failed', 'Expired', 'Resuming']; 29 | 30 | export const APP_STATUS_COLOR_MAP: AppStatusColors = { 31 | New: "#facc54", 32 | Accepted: "#f4b400", 33 | Starting: "#26bbf0", 34 | Running: "#234378", 35 | Completing: "#60cea5", 36 | Completed: "#0f9d58", 37 | Rejected: "#ff6d00", 38 | Failing: "#cc6164", 39 | Failed: "#db4437", 40 | Expired: "#3949ab", 41 | Resuming: "#694cb5" 42 | } 43 | -------------------------------------------------------------------------------- /src/assets/config/envconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "localSchedulerWebAddress": "http://localhost:9889" 3 | } 4 | -------------------------------------------------------------------------------- /src/assets/images/config.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/assets/images/hierarchy.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/assets/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apache/yunikorn-web/541135b7f28c9e63155d76ec730bfd36dcafa27b/src/assets/images/logo.png -------------------------------------------------------------------------------- /src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | export const environment = { 20 | production: true, 21 | }; 22 | -------------------------------------------------------------------------------- /src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | // This file can be replaced during build by using the `fileReplacements` array. 20 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. 21 | // The list of file replacements can be found in `angular.json`. 22 | 23 | export const environment = { 24 | production: false, 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/dist/zone-error'; // Included with Angular CLI. 35 | -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apache/yunikorn-web/541135b7f28c9e63155d76ec730bfd36dcafa27b/src/favicon.ico -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 21 | 22 | 23 | YuniKorn UI 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import { enableProdMode } from '@angular/core'; 20 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 21 | 22 | import { AppModule } from './app/app.module'; 23 | import { environment } from './environments/environment'; 24 | 25 | if (environment.production) { 26 | enableProdMode(); 27 | } 28 | 29 | platformBrowserDynamic() 30 | .bootstrapModule(AppModule) 31 | .catch((err) => console.error(err)); 32 | -------------------------------------------------------------------------------- /src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | // zone JS is required by default for Angular itself. 20 | import 'zone.js'; 21 | -------------------------------------------------------------------------------- /src/styles.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | @use '@angular/material' as mat; 19 | 20 | @import '~@angular/material/prebuilt-themes/indigo-pink.css'; 21 | 22 | * { 23 | box-sizing: border-box; 24 | -webkit-box-sizing: border-box; 25 | -moz-box-sizing: border-box; 26 | -ms-box-sizing: border-box; 27 | -o-box-sizing: border-box; 28 | } 29 | 30 | body { 31 | @include mat.form-field-density(-4); 32 | font-family: 'Roboto', sans-serif; 33 | font-size: 14px; 34 | color: #666; 35 | background: #eee; 36 | margin: 0; 37 | padding: 0; 38 | } 39 | 40 | .text-semibold { 41 | font-weight: 500; 42 | } 43 | 44 | .text-uppercase { 45 | text-transform: uppercase; 46 | } 47 | 48 | .text-center { 49 | text-align: center; 50 | } 51 | 52 | .error-border { 53 | border-color: #ef6162; 54 | } 55 | 56 | .warning-border { 57 | border-color: #e98a40; 58 | } 59 | 60 | .success-border { 61 | border-color: #3fae2a; 62 | } 63 | 64 | .error-bg { 65 | background: #ef6162; 66 | } 67 | 68 | .warning-bg { 69 | background: #e98a40; 70 | } 71 | 72 | .success-bg { 73 | background: #3fae2a; 74 | } 75 | 76 | .error-text { 77 | color: #ef6162; 78 | } 79 | 80 | .warning-text { 81 | color: #e98a40; 82 | } 83 | 84 | .success-text { 85 | color: #3fae2a; 86 | } 87 | 88 | .light-text { 89 | color: #999; 90 | } 91 | 92 | .strong-text { 93 | color: #333; 94 | } 95 | 96 | .regular-text { 97 | color: #666; 98 | } 99 | 100 | p { 101 | margin: 10px 0; 102 | } 103 | 104 | .flex-grid { 105 | display: flex; 106 | } 107 | 108 | .align-center { 109 | align-items: center; 110 | } 111 | 112 | .flex-primary { 113 | flex-grow: 1; 114 | } 115 | 116 | .mat-mdc-card.box-card { 117 | padding: 0; 118 | border-radius: 0; 119 | .mat-mdc-card-header { 120 | color: #666; 121 | background-color: #f7f7f7; 122 | border-bottom: 1px solid #d5d5d5; 123 | padding: 20px; 124 | } 125 | .mat-mdc-card-title { 126 | font-size: 18px; 127 | line-height: 24px; 128 | margin-bottom: 0 !important; 129 | } 130 | .mat-mdc-card-content { 131 | padding: 60px 50px; 132 | } 133 | .thin-card-content { 134 | padding: 60px 16px; 135 | } 136 | } 137 | 138 | .white-mat-form-field .mat-mdc-form-field-flex { 139 | background-color: #fff; 140 | padding: 0 5px 0 5px; 141 | } 142 | -------------------------------------------------------------------------------- /src/test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 20 | 21 | import 'zone.js/testing'; 22 | import { getTestBed } from '@angular/core/testing'; 23 | import { 24 | BrowserDynamicTestingModule, 25 | platformBrowserDynamicTesting, 26 | } from '@angular/platform-browser-dynamic/testing'; 27 | 28 | // First, initialize the Angular testing environment. 29 | getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting()); 30 | -------------------------------------------------------------------------------- /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 | }, 8 | "files": [ 9 | "src/main.ts", 10 | "src/polyfills.ts" 11 | ], 12 | "include": [ 13 | "src/**/*.d.ts" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /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 | "strict": true, 9 | "noImplicitOverride": true, 10 | "noPropertyAccessFromIndexSignature": true, 11 | "noImplicitReturns": true, 12 | "noFallthroughCasesInSwitch": true, 13 | "sourceMap": true, 14 | "declaration": false, 15 | "downlevelIteration": true, 16 | "experimentalDecorators": true, 17 | "moduleResolution": "node", 18 | "importHelpers": true, 19 | "target": "ES2022", 20 | "module": "es2020", 21 | "lib": [ 22 | "es2022", 23 | "dom" 24 | ], 25 | "paths": { 26 | "@app/*": [ 27 | "src/app/*" 28 | ], 29 | "@envs/*": [ 30 | "src/environments/*" 31 | ] 32 | }, 33 | "useDefineForClassFields": false 34 | }, 35 | "angularCompilerOptions": { 36 | "enableI18nLegacyMessageIdFormat": false, 37 | "strictInjectionParameters": true, 38 | "strictInputAccessModifiers": true, 39 | "strictTemplates": true 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /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 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts", 12 | "src/polyfills.ts" 13 | ], 14 | "include": [ 15 | "src/**/*.spec.ts", 16 | "src/**/*.d.ts" 17 | ] 18 | } 19 | --------------------------------------------------------------------------------