├── .nvmrc
├── .go_version
├── .go_repro_version
├── .dockerignore
├── json-server.json
├── src
├── favicon.ico
├── assets
│ ├── config
│ │ └── envconfig.json
│ └── images
│ │ ├── logo.png
│ │ ├── hierarchy.svg
│ │ └── config.svg
├── app
│ ├── models
│ │ ├── app-status.model.ts
│ │ ├── envconfig.model.ts
│ │ ├── time-series-data.model.ts
│ │ ├── api-error-info.model.ts
│ │ ├── column-def.model.ts
│ │ ├── area-data.model.ts
│ │ ├── dropdown-item.model.ts
│ │ ├── history-info.model.ts
│ │ ├── resource-info.model.ts
│ │ ├── scheduler-health-info.model.ts
│ │ ├── cluster-info.model.ts
│ │ ├── alloc-info.model.ts
│ │ ├── node-utilization.model.ts
│ │ ├── node-info.model.ts
│ │ ├── partition-info.model.ts
│ │ ├── chart-data.model.ts
│ │ ├── queue-info.model.ts
│ │ └── app-info.model.ts
│ ├── components
│ │ ├── status-view
│ │ │ ├── status-view.component.scss
│ │ │ ├── status-view.component.html
│ │ │ ├── status-view.component.spec.ts
│ │ │ └── status-view.component.ts
│ │ ├── app-history
│ │ │ ├── app-history.component.scss
│ │ │ ├── app-history.component.html
│ │ │ ├── app-history.component.ts
│ │ │ └── app-history.component.spec.ts
│ │ ├── area-chart
│ │ │ ├── area-chart.component.scss
│ │ │ ├── area-chart.component.html
│ │ │ └── area-chart.component.spec.ts
│ │ ├── container-history
│ │ │ ├── container-history.component.scss
│ │ │ ├── container-history.component.html
│ │ │ ├── container-history.component.ts
│ │ │ └── container-history.component.spec.ts
│ │ ├── vertical-bar-chart
│ │ │ ├── vertical-bar-chart.component.html
│ │ │ ├── vertical-bar-chart.component.scss
│ │ │ └── vertical-bar-chart.component.spec.ts
│ │ ├── card
│ │ │ ├── card.component.html
│ │ │ ├── card.component.ts
│ │ │ └── card.component.scss
│ │ ├── error-view
│ │ │ ├── error-view.component.scss
│ │ │ ├── error-view.component.html
│ │ │ ├── error-view.component.spec.ts
│ │ │ └── error-view.component.ts
│ │ ├── donut-chart
│ │ │ ├── donut-chart.component.html
│ │ │ ├── donut-chart.component.scss
│ │ │ ├── donut-chart.component.spec.ts
│ │ │ └── donut-chart.component.ts
│ │ ├── app-node-utilizations
│ │ │ ├── app-node-utilizations.component.scss
│ │ │ └── app-node-utilizations.component.html
│ │ ├── licenses-modal
│ │ │ ├── licenses-modal.component.html
│ │ │ ├── licenses-modal.component.scss
│ │ │ ├── licenses-modal.component.spec.ts
│ │ │ └── licenses-modal.component.ts
│ │ ├── app-status
│ │ │ ├── app-status.component.ts
│ │ │ ├── app-status.component.scss
│ │ │ ├── app-status.component.html
│ │ │ └── app-status.component.spec.ts
│ │ ├── healthchecks
│ │ │ ├── healthchecks.component.scss
│ │ │ ├── healthchecks.component.ts
│ │ │ ├── healthchecks.component.spec.ts
│ │ │ └── healthchecks.component.html
│ │ ├── container-status
│ │ │ ├── container-status.component.ts
│ │ │ ├── container-status.component.scss
│ │ │ ├── container-status.component.html
│ │ │ └── container-status.component.spec.ts
│ │ ├── nodes-view
│ │ │ ├── highlighttable-search.pipe.ts
│ │ │ ├── nodes-view.component.spec.ts
│ │ │ └── nodes-view.component.scss
│ │ ├── queue-rack
│ │ │ ├── queue-rack.component.spec.ts
│ │ │ ├── queue-rack.component.html
│ │ │ ├── queue-rack.component.scss
│ │ │ └── queue-rack.component.ts
│ │ ├── dashboard
│ │ │ ├── dashboard.component.scss
│ │ │ ├── dashboard.component.spec.ts
│ │ │ └── dashboard.component.html
│ │ ├── queues-view
│ │ │ ├── queues-view.component.scss
│ │ │ └── queues-view.component.spec.ts
│ │ └── queue-v2
│ │ │ └── queues-v2.component.spec.ts
│ ├── services
│ │ ├── event-bus
│ │ │ ├── event-bus.service.spec.ts
│ │ │ └── event-bus.service.ts
│ │ └── envconfig
│ │ │ ├── envconfig.service.spec.ts
│ │ │ └── envconfig.service.ts
│ ├── interceptors
│ │ └── api-error
│ │ │ ├── api-error.interceptor.spec.ts
│ │ │ └── api-error.interceptor.ts
│ ├── testing
│ │ └── mocks.ts
│ ├── utils
│ │ └── constants.ts
│ ├── app.component.spec.ts
│ ├── app-routing.module.ts
│ ├── app.component.ts
│ └── app.component.html
├── polyfills.ts
├── environments
│ ├── environment.prod.ts
│ └── environment.ts
├── index.html
├── main.ts
├── test.ts
└── styles.scss
├── NOTICE
├── .prettierrc
├── go.sum
├── tsconfig.app.json
├── json-routes.json
├── tsconfig.spec.json
├── .browserslistrc
├── .gitignore
├── pkg
├── webserver
│ ├── testdata
│ │ └── test.txt
│ ├── web_server.go
│ └── web_server_test.go
└── cmd
│ └── web
│ └── main.go
├── .github
├── PULL_REQUEST_TEMPLATE
└── workflows
│ └── main.yml
├── go.mod
├── tsconfig.json
├── Dockerfile
├── .asf.yaml
├── karma.conf.ci.js
├── .golangci.yml
├── package.json
├── karma.conf.js
└── angular.json
/.nvmrc:
--------------------------------------------------------------------------------
1 | 20.19
2 |
--------------------------------------------------------------------------------
/.go_version:
--------------------------------------------------------------------------------
1 | 1.25
2 |
--------------------------------------------------------------------------------
/.go_repro_version:
--------------------------------------------------------------------------------
1 | 1.25.5
2 |
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
3 |
--------------------------------------------------------------------------------
/json-server.json:
--------------------------------------------------------------------------------
1 | {
2 | "port": 9889,
3 | "routes": "json-routes.json"
4 | }
5 |
--------------------------------------------------------------------------------
/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apache/yunikorn-web/HEAD/src/favicon.ico
--------------------------------------------------------------------------------
/src/assets/config/envconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "localSchedulerWebAddress": "http://localhost:9889"
3 | }
4 |
--------------------------------------------------------------------------------
/src/assets/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apache/yunikorn-web/HEAD/src/assets/images/logo.png
--------------------------------------------------------------------------------
/NOTICE:
--------------------------------------------------------------------------------
1 | Apache YuniKorn
2 | Copyright 2019-2025 The Apache Software Foundation
3 |
4 | This product includes software developed at
5 | The Apache Software Foundation (http://www.apache.org/).
6 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
2 | github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
3 | gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
4 | gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=
5 |
--------------------------------------------------------------------------------
/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 | };
17 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/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/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/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/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/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/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/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/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/components/area-chart/area-chart.component.html:
--------------------------------------------------------------------------------
1 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/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/components/vertical-bar-chart/vertical-bar-chart.component.html:
--------------------------------------------------------------------------------
1 |
18 |
23 |
--------------------------------------------------------------------------------
/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.24
23 |
24 | toolchain go1.24.11
25 |
26 | require gotest.tools/v3 v3.5.2
27 |
28 | require github.com/google/go-cmp v0.7.0 // indirect
29 |
--------------------------------------------------------------------------------
/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/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/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/components/card/card.component.html:
--------------------------------------------------------------------------------
1 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/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/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/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/donut-chart/donut-chart.component.html:
--------------------------------------------------------------------------------
1 |
18 |
19 |
20 |
21 |
22 |
23 |
{{ totalCount }}
24 |
25 |
26 |
--------------------------------------------------------------------------------
/src/assets/images/hierarchy.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "compileOnSave": false,
4 | "compilerOptions": {
5 | "baseUrl": "./",
6 | "outDir": "./dist/out-tsc",
7 | "forceConsistentCasingInFileNames": true,
8 | "esModuleInterop": true,
9 | "strict": true,
10 | "noImplicitOverride": true,
11 | "noPropertyAccessFromIndexSignature": true,
12 | "noImplicitReturns": true,
13 | "noFallthroughCasesInSwitch": true,
14 | "sourceMap": true,
15 | "declaration": false,
16 | "experimentalDecorators": true,
17 | "moduleResolution": "bundler",
18 | "importHelpers": true,
19 | "target": "ES2022",
20 | "module": "es2020",
21 | "lib": [
22 | "es2022",
23 | "dom"
24 | ],
25 | "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 |
--------------------------------------------------------------------------------
/src/app/components/app-history/app-history.component.html:
--------------------------------------------------------------------------------
1 |
18 |
19 |
20 |
21 |
22 | Application History
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/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/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/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 | standalone: false,
26 | })
27 | export class CardComponent implements OnInit {
28 | constructor() {}
29 |
30 | ngOnInit() {}
31 | }
32 |
--------------------------------------------------------------------------------
/src/app/components/container-history/container-history.component.html:
--------------------------------------------------------------------------------
1 |
18 |
19 |
20 |
21 |
22 | Container History
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/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 | }
38 |
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
18 |
19 |
20 |
21 |
22 |
23 | YuniKorn UI
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/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/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/app/components/licenses-modal/licenses-modal.component.html:
--------------------------------------------------------------------------------
1 |
18 |
19 |
20 |
21 |
Licenses used in YuniKorn project
22 |
23 |
24 |
25 |
26 |
27 |
28 |
31 |
32 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/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 | standalone: false,
27 | })
28 | export class AppStatusComponent implements OnInit {
29 | @Input() chartData: ChartDataItem[] = [];
30 |
31 | constructor() {}
32 |
33 | ngOnInit() {}
34 | }
35 |
--------------------------------------------------------------------------------
/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 | standalone: false,
28 | })
29 | export class AppHistoryComponent implements OnInit {
30 | @Input() chartData: AreaDataItem[] = [];
31 |
32 | constructor() {}
33 |
34 | ngOnInit() {}
35 | }
36 |
--------------------------------------------------------------------------------
/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/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 | standalone: false,
27 | })
28 | export class ContainerStatusComponent implements OnInit {
29 | @Input() chartData: ChartDataItem[] = [];
30 |
31 | constructor() {}
32 |
33 | ngOnInit() {}
34 | }
35 |
--------------------------------------------------------------------------------
/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 | }
45 |
--------------------------------------------------------------------------------
/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 | standalone: false,
28 | })
29 | export class ContainerHistoryComponent implements OnInit {
30 | @Input() chartData: AreaDataItem[] = [];
31 |
32 | constructor() {}
33 |
34 | ngOnInit() {}
35 | }
36 |
--------------------------------------------------------------------------------
/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 | standalone: false,
27 | })
28 | export class HealthchecksComponent implements OnInit {
29 | @Input() schedulerHealth: SchedulerHealthInfo = new SchedulerHealthInfo();
30 |
31 | constructor() {}
32 |
33 | ngOnInit(): void {}
34 | }
35 |
--------------------------------------------------------------------------------
/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/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/src/assets/images/config.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/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/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 | }
53 |
--------------------------------------------------------------------------------
/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/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/components/app-status/app-status.component.html:
--------------------------------------------------------------------------------
1 |
18 |
19 |
20 |
21 |
22 | Application Status
23 |
24 |
38 |
39 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/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/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/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/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/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 | standalone: false,
24 | })
25 | export class HighlightSearchPipe implements PipeTransform {
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(
33 | new RegExp('(?![^&;]+;)(?!<[^<>]*)(' + search + ')(?![^<>]*>)(?![^&;]+;)', 'gi'),
34 | '$1'
35 | );
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/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/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/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 | standalone: false,
28 | })
29 | export class ErrorViewComponent implements OnInit {
30 | apiError: ApiErrorInfo | null = null;
31 | lastActiveUrl = '';
32 |
33 | constructor(
34 | private activatedRoute: ActivatedRoute,
35 | private router: Router
36 | ) {}
37 |
38 | ngOnInit() {
39 | this.apiError = window.history.state;
40 | this.lastActiveUrl = this.activatedRoute.snapshot.queryParams['last'];
41 | }
42 |
43 | retryLastActiveUrlAgain() {
44 | if (this.lastActiveUrl) {
45 | this.router.navigateByUrl(this.lastActiveUrl);
46 | } else {
47 | this.router.navigateByUrl('/');
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/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(
42 | label: string,
43 | data: number[],
44 | avgUtilizationRate: number,
45 | backgroundColor: string,
46 | borderWidth: number,
47 | description: string[]
48 | ) {
49 | this.label = label;
50 | this.data = data;
51 | this.avgUtilizationRate = avgUtilizationRate;
52 | this.backgroundColor = backgroundColor;
53 | this.borderWidth = borderWidth;
54 | this.description = description;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/app/components/app-node-utilizations/app-node-utilizations.component.html:
--------------------------------------------------------------------------------
1 |
18 |
19 |
20 |
21 |
46 |
47 |
--------------------------------------------------------------------------------
/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/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/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/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/queue-rack/queue-rack.component.html:
--------------------------------------------------------------------------------
1 |
18 |
19 |
49 |
--------------------------------------------------------------------------------
/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/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: [NoopAnimationsModule, RouterTestingModule, MatIconModule, MatExpansionModule],
35 | }).compileComponents();
36 | fixture = TestBed.createComponent(HealthchecksComponent);
37 | component = fixture.componentInstance;
38 | fixture.detectChanges();
39 | });
40 |
41 | it('should create', () => {
42 | expect(component).toBeTruthy();
43 | });
44 | });
45 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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 | standalone: false,
29 | })
30 | export class LicensesModalComponent {
31 | licenses = '';
32 |
33 | constructor(
34 | private dialogRef: MatDialogRef,
35 | private httpClient: HttpClient
36 | ) {
37 | // Licenses file is generated during build time and is available at /3rdpartylicenses.txt
38 | // Dev mode uses the file from assets folder assets/example-licenses.txt
39 | const licensePath = isDevMode() ? 'LICENSE' : '3rdpartylicenses.txt';
40 |
41 | this.httpClient.get(licensePath, { responseType: 'text' }).subscribe((data) => {
42 | if (data) this.licenses = data.replace(/\n/g, ' ');
43 | else this.licenses = 'No licenses found';
44 | });
45 | }
46 |
47 | close() {
48 | this.dialogRef.close();
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/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 | beforeEach(() => {
33 | TestBed.configureTestingModule({
34 | declarations: [StatusViewComponent, MockComponent(StatusViewComponent)],
35 | providers: [
36 | { provide: SchedulerService, useValue: MockSchedulerService },
37 | { provide: NgxSpinnerService, useValue: MockNgxSpinnerService },
38 | ],
39 | }).compileComponents();
40 | fixture = TestBed.createComponent(StatusViewComponent);
41 | component = fixture.componentInstance;
42 | fixture.detectChanges();
43 | });
44 |
45 | it('should create', () => {
46 | expect(component).toBeTruthy();
47 | });
48 | });
49 |
--------------------------------------------------------------------------------
/src/app/components/healthchecks/healthchecks.component.html:
--------------------------------------------------------------------------------
1 |
18 |
19 |
20 |
21 |
22 | Healthy
23 |
24 | Scheduler status
25 | @if (schedulerHealth.Healthy) {
26 | done
27 | } @else {
28 | close
29 | }
30 |
31 |
32 |
33 | @for (healthCheck of schedulerHealth.HealthChecks; track healthCheck) {
34 |
35 |
36 |
37 | {{ healthCheck.Name }}
38 |
39 |
40 | {{ healthCheck.Description }}
41 | @if (healthCheck.Succeeded) {
42 | done
43 | } @else {
44 | close
45 | }
46 |
47 |
48 |
{{ healthCheck.DiagnosisMessage }}
49 |
50 | }
51 |
52 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 = [
27 | 'rgba(66, 133, 244, 1)',
28 | 'rgb(219, 68, 55, 1)',
29 | 'rgb(244, 180, 0, 1)',
30 | 'rgb(15, 157, 88, 1)',
31 | 'rgb(255, 109, 0, 1)',
32 | 'rgb(57, 73, 171, 1)',
33 | 'rgb(250, 204, 84, 1)',
34 | 'rgb(38, 187, 240, 1)',
35 | 'rgb(204, 97, 100, 1)',
36 | 'rgb(96, 206, 165, 1)',
37 | ];
38 |
39 | export const APP_STATUSES: AppStatus[] = [
40 | 'New',
41 | 'Accepted',
42 | 'Starting',
43 | 'Running',
44 | 'Rejected',
45 | 'Completing',
46 | 'Completed',
47 | 'Failing',
48 | 'Failed',
49 | 'Expired',
50 | 'Resuming',
51 | ];
52 |
53 | export const APP_STATUS_COLOR_MAP: AppStatusColors = {
54 | New: '#facc54',
55 | Accepted: '#f4b400',
56 | Starting: '#26bbf0',
57 | Running: '#234378',
58 | Completing: '#60cea5',
59 | Completed: '#0f9d58',
60 | Rejected: '#ff6d00',
61 | Failing: '#cc6164',
62 | Failed: '#db4437',
63 | Expired: '#3949ab',
64 | Resuming: '#694cb5',
65 | };
66 |
--------------------------------------------------------------------------------
/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 | standalone: false,
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/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/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/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/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/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/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 |
--------------------------------------------------------------------------------
/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'],
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('karma-super-dots-reporter'),
35 | ],
36 | client: {
37 | clearContext: false, // leave Jasmine Spec Runner output visible in browser
38 | },
39 | reporters: ['super-dots', 'coverage-istanbul'],
40 | superDotsReporter: {
41 | nbDotsPerLine: 180,
42 | },
43 | coverageIstanbulReporter: {
44 | dir: require('path').join(__dirname, './coverage/yunikorn-web'),
45 | reports: ['text-summary'],
46 | fixWebpackSourcePaths: true,
47 | },
48 | port: 9876,
49 | colors: true,
50 | logLevel: config.LOG_INFO,
51 | autoWatch: false,
52 | browsers: ['ChromeHeadlessNoSandbox'],
53 | customLaunchers: {
54 | ChromeHeadlessNoSandbox: {
55 | base: 'ChromeHeadless',
56 | flags: ['--no-sandbox'],
57 | },
58 | },
59 | captureTimeout: 180000,
60 | browserDisconnectTolerance: 3,
61 | browserDisconnectTimeout: 180000,
62 | browserNoActivityTimeout: 180000,
63 | singleRun: true,
64 | restartOnFileChange: true,
65 | });
66 | };
67 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/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/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 | standalone: false,
30 | })
31 | export class QueueRackComponent implements OnInit {
32 | @Input() queueList: QueueInfo[] | null = [];
33 | @Input() nextLevel = '';
34 |
35 | @Output() toggleChildren = new EventEmitter();
36 | @Output() queueSelected = new EventEmitter();
37 |
38 | constructor() {}
39 |
40 | ngOnInit() {}
41 |
42 | toggleQueueChildren(event: Event, item: QueueInfo) {
43 | event.preventDefault();
44 | event.stopPropagation();
45 | this.collapseQueueList(item);
46 | item.isExpanded = !item.isExpanded;
47 | this.toggleChildren.emit({
48 | queueItem: item,
49 | nextLevel: this.nextLevel,
50 | });
51 | }
52 |
53 | collapseQueueList(item: QueueInfo) {
54 | if (this.queueList) {
55 | this.queueList.forEach((queue) => {
56 | if (queue !== item) {
57 | queue.isExpanded = false;
58 | }
59 | });
60 | }
61 | }
62 |
63 | onQueueSelected(queue: QueueInfo) {
64 | queue.isSelected = !queue.isSelected;
65 | this.queueSelected.emit(queue);
66 | }
67 |
68 | getQueueCapacityColor(queue: QueueInfo) {
69 | const value = queue.absoluteUsedPercent;
70 | if (value > 60 && value <= 75) {
71 | return '#60cea5';
72 | } else if (value > 75 && value < 90) {
73 | return '#ffbc0b';
74 | } else if (value >= 90) {
75 | return '#ef6162';
76 | }
77 | return '#fff';
78 | }
79 |
80 | getProgressBarValue(queue: QueueInfo) {
81 | return queue.absoluteUsedPercent;
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/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 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 |
--------------------------------------------------------------------------------
/.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 | version: "2"
20 | # options for analysis running
21 | run:
22 | issues-exit-code: 1
23 | modules-download-mode: readonly
24 | tests: true
25 | linters:
26 | settings:
27 | errcheck:
28 | check-type-assertions: true
29 | check-blank: true
30 | revive:
31 | confidence: 0.8
32 | govet:
33 | enable:
34 | - shadow
35 | goconst:
36 | min-occurrences: 5
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 | default: none
51 | # linters to use
52 | enable:
53 | - errcheck
54 | - unused
55 | - staticcheck
56 | - ineffassign
57 | - funlen
58 | - revive
59 | - govet
60 | - goconst
61 | - depguard
62 | - nakedret
63 | - gocritic
64 | - godox
65 | - gosec
66 | - dogsled
67 | - whitespace
68 | - ginkgolinter
69 | exclusions:
70 | generated: lax
71 | presets:
72 | - comments
73 | - common-false-positives
74 | - legacy
75 | - std-error-handling
76 | paths:
77 | - third_party$
78 | - builtin$
79 | - examples$
80 | issues:
81 | # Maximum issues count per one linter. Set to 0 to disable. Default is 50.
82 | max-issues-per-linter: 0
83 | # Maximum count of issues with the same text. Set to 0 to disable. Default is 3.
84 | max-same-issues: 0
85 | new: false
86 | formatters:
87 | enable:
88 | - gofmt
89 | - goimports
90 | settings:
91 | gofmt:
92 | simplify: true
93 | goimports:
94 | local-prefixes:
95 | - github.com/apache/yunikorn
96 | exclusions:
97 | generated: lax
98 | paths:
99 | - third_party$
100 | - builtin$
101 | - examples$
102 |
--------------------------------------------------------------------------------
/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/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 | font-family: 'Roboto', sans-serif;
32 | font-size: 14px;
33 | color: #666;
34 | background: #eee;
35 | margin: 0;
36 | padding: 0;
37 | @include mat.form-field-density(-4);
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 |
--------------------------------------------------------------------------------
/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 --watch=false",
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 --watch=false",
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": "^20.3.15",
32 | "@angular/cdk": "^20.2.14",
33 | "@angular/common": "^20.3.15",
34 | "@angular/compiler": "^20.3.15",
35 | "@angular/core": "^20.3.15",
36 | "@angular/forms": "^20.3.15",
37 | "@angular/material": "^20.2.14",
38 | "@angular/platform-browser": "^20.3.15",
39 | "@angular/platform-browser-dynamic": "^20.3.15",
40 | "@angular/router": "^20.3.15",
41 | "@fontsource/roboto": "^5.2.9",
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.5.1",
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.15.1"
65 | },
66 | "devDependencies": {
67 | "@angular/build": "^20.3.13",
68 | "@angular/cli": "^20.3.13",
69 | "@angular/compiler-cli": "^20.3.14",
70 | "@types/color": "^4.2.0",
71 | "@types/jasmine": "~5.1.13",
72 | "@types/node": "^20.19.25",
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.2",
85 | "ng-mocks": "^14.14.0",
86 | "prettier": "^3.7.3",
87 | "puppeteer": "^24.31.0",
88 | "typescript": "5.8.3"
89 | },
90 | "engines": {
91 | "node": "20",
92 | "pnpm": "9"
93 | },
94 | "packageManager": "pnpm@9"
95 | }
--------------------------------------------------------------------------------
/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 | }).compileComponents();
55 | }));
56 |
57 | beforeEach(() => {
58 | fixture = TestBed.createComponent(QueueV2Component);
59 | component = fixture.componentInstance;
60 | schedulerService = TestBed.inject(SchedulerService);
61 | spinnerService = TestBed.inject(NgxSpinnerService);
62 | fixture.detectChanges();
63 | });
64 |
65 | it('should create', () => {
66 | expect(component).toBeTruthy();
67 | });
68 |
69 | describe('fetchSchedulerQueuesForPartition', () => {
70 | it('should call SchedulerService and NgxSpinnerService methods', () => {
71 | const schedulerSpy = spyOn(schedulerService, 'fetchSchedulerQueues').and.callThrough();
72 | const spinnerShowSpy = spyOn(spinnerService, 'show').and.callThrough();
73 | const spinnerHideSpy = spyOn(spinnerService, 'hide').and.callThrough();
74 |
75 | component.fetchSchedulerQueuesForPartition();
76 |
77 | expect(schedulerSpy).toHaveBeenCalledWith('default');
78 | expect(spinnerShowSpy).toHaveBeenCalledBefore(schedulerSpy);
79 | expect(spinnerHideSpy).toHaveBeenCalled();
80 | expect(component.rootQueue).toBeTruthy();
81 | });
82 | });
83 | });
84 |
--------------------------------------------------------------------------------
/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 |
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 |
--------------------------------------------------------------------------------
/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 | }).compileComponents();
68 | fixture = TestBed.createComponent(NodesViewComponent);
69 | component = fixture.componentInstance;
70 | });
71 |
72 | it('should create the component', () => {
73 | expect(component).toBeTruthy();
74 | });
75 | });
76 |
--------------------------------------------------------------------------------
/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 | .nodes-view {
69 | width: 100%;
70 | .mat-mdc-header-cell {
71 | font-size: 15px;
72 | font-weight: 500;
73 | color: #666;
74 | }
75 | .mat-mdc-cell {
76 | color: #333;
77 | display: flex;
78 | flex-direction: column;
79 | align-items: flex-start;
80 | .mat-res-ul {
81 | padding: 0;
82 | margin: 0;
83 | .mat-res-li {
84 | list-style-type: none;
85 | }
86 | }
87 | .mat-toggle-more {
88 | display: block;
89 | color: #a1a3b7;
90 | padding: 5px 45px 0 0;
91 | &:hover {
92 | color: #8d00d4;
93 | }
94 | }
95 | .mat-attr-ul {
96 | padding: 0;
97 | margin: 0;
98 | .mat-attr-li {
99 | list-style-type: none;
100 | }
101 | }
102 | }
103 | .mat-mdc-row {
104 | &:hover {
105 | background: #cccccc;
106 | cursor: pointer;
107 | }
108 | &.selected-row {
109 | background: #303d54;
110 | .mat-mdc-cell {
111 | color: #fff;
112 | .mat-toggle-more {
113 | color: #b8bbff;
114 | &:hover {
115 | color: #b871dc;
116 | }
117 | }
118 | }
119 | }
120 | }
121 | .mat-mdc-header-cell.indicator-icon,
122 | .mat-mdc-cell.indicator-icon {
123 | max-width: 40px;
124 | font-size: 18px;
125 | display: flex;
126 | justify-content: center;
127 | align-items: center;
128 | }
129 | .node-allocations {
130 | margin-top: 20px;
131 | .mat-mdc-table {
132 | margin-top: 20px;
133 | }
134 | }
135 | .no-record {
136 | font-size: 14px;
137 | font-weight: 500;
138 | color: #666;
139 | width: 100%;
140 | text-align: center;
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/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 | standalone: false,
33 | })
34 | export class AppComponent implements OnInit {
35 | isNavOpen = true;
36 | breadcrumbs: Array<{ label: string; url: string }> = [];
37 |
38 | constructor(
39 | private route: ActivatedRoute,
40 | private router: Router,
41 | private eventBus: EventBusService,
42 | private dialog: MatDialog
43 | ) {}
44 |
45 | ngOnInit() {
46 | this.router.events.pipe(filter((event) => event instanceof NavigationEnd)).subscribe(() => {
47 | this.generateBreadcrumb();
48 | });
49 |
50 | fromEvent(window, 'resize')
51 | .pipe(debounceTime(500))
52 | .subscribe(() => this.eventBus.publish(EventMap.WindowResizedEvent));
53 | }
54 |
55 | generateBreadcrumb() {
56 | this.breadcrumbs = [];
57 | let url = '';
58 | let currentRoute: ActivatedRoute | null = this.route.root;
59 |
60 | do {
61 | const childrenRoutes = currentRoute.children;
62 | currentRoute = null;
63 | childrenRoutes.forEach((route) => {
64 | if (route.outlet === 'primary') {
65 | const routeSnapshot = route.snapshot;
66 | if (routeSnapshot) {
67 | url += '/' + routeSnapshot.url.map((segment) => segment.path).join('/');
68 | if (!!route.snapshot.data['breadcrumb']) {
69 | this.breadcrumbs.push({
70 | label: route.snapshot.data['breadcrumb'].includes(':')
71 | ? this.getResourceName(
72 | route.snapshot.data['breadcrumb'],
73 | routeSnapshot.params,
74 | route.snapshot.data['breadcrumb'].split(':')[1]
75 | )
76 | : route.snapshot.data['breadcrumb'],
77 | url,
78 | });
79 | if (route.snapshot.data['prependRoot']) {
80 | this.breadcrumbs.unshift({
81 | label: 'Dashboard',
82 | url: '/',
83 | });
84 | }
85 | }
86 | }
87 | currentRoute = route;
88 | }
89 | });
90 | } while (currentRoute);
91 | }
92 |
93 | getResourceName(label: string, params: Record, routeParam: string) {
94 | return label.replace(`:${routeParam}`, params[routeParam]);
95 | }
96 |
97 | toggleNavigation() {
98 | this.isNavOpen = !this.isNavOpen;
99 | setTimeout(() => {
100 | this.eventBus.publish(EventMap.LayoutChangedEvent);
101 | }, 1000);
102 | }
103 |
104 | openYuniKornHelp(url: string) {
105 | const fullUrl = `http://yunikorn.apache.org${url}`;
106 | window.open(fullUrl, '_blank');
107 | }
108 |
109 | openYuniKornLicense() {
110 | this.dialog.open(LicensesModalComponent, {
111 | maxWidth: '800px',
112 | disableClose: true,
113 | });
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/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 | standalone: false,
42 | })
43 | export class DonutChartComponent implements OnInit, AfterViewInit, OnChanges, OnDestroy {
44 | destroy$ = new Subject();
45 | chartContainerId = '';
46 | donutChartData: ChartDataItem[] = [];
47 | donutChart: Chart<'doughnut', number[], string> | undefined;
48 |
49 | @Input() data: ChartDataItem[] = [];
50 |
51 | constructor(private eventBus: EventBusService) {}
52 |
53 | get totalCount(): number {
54 | return this.data.reduce((acc, item) => acc + item.value, 0);
55 | }
56 |
57 | ngOnInit() {
58 | this.chartContainerId = CommonUtil.createUniqId('donut_chart_');
59 |
60 | this.eventBus
61 | .getEvent(EventMap.WindowResizedEvent)
62 | .pipe(takeUntil(this.destroy$))
63 | .subscribe(() => this.renderChart(this.donutChartData));
64 | }
65 |
66 | ngOnDestroy() {
67 | this.destroy$.next(true);
68 | this.destroy$.unsubscribe();
69 | }
70 |
71 | ngAfterViewInit() {
72 | if (this.data) {
73 | this.renderChart(this.data);
74 | }
75 | }
76 |
77 | ngOnChanges(changes: SimpleChanges) {
78 | if (
79 | changes['data'] &&
80 | changes['data'].currentValue &&
81 | changes['data'].currentValue.length > 0
82 | ) {
83 | this.donutChartData = changes['data'].currentValue;
84 | this.renderChart(this.donutChartData);
85 | }
86 | }
87 |
88 | renderChart(chartData: ChartDataItem[] = []) {
89 | if (!this.chartContainerId) {
90 | return;
91 | }
92 | const ctx = (document.getElementById(this.chartContainerId) as HTMLCanvasElement).getContext(
93 | '2d'
94 | );
95 |
96 | const dataValues = chartData.map((d) => d.value);
97 | const chartLabels = chartData.map((d) => d.name);
98 | const colors = chartData.map((d) => d.color);
99 |
100 | if (this.donutChart) {
101 | this.donutChart.destroy();
102 | }
103 |
104 | this.donutChart = new Chart(ctx!, {
105 | type: 'doughnut',
106 | data: {
107 | labels: chartLabels,
108 | datasets: [
109 | {
110 | data: dataValues,
111 | backgroundColor: colors,
112 | borderWidth: 0,
113 | },
114 | ],
115 | },
116 | options: {
117 | responsive: true,
118 | animation: {
119 | animateScale: true,
120 | animateRotate: true,
121 | },
122 | plugins: {
123 | legend: {
124 | display: false,
125 | },
126 | title: {
127 | display: false,
128 | },
129 | tooltip: {
130 | enabled: true,
131 | position: 'nearest',
132 | },
133 | },
134 | cutout: '70%',
135 | },
136 | });
137 |
138 | this.donutChart.update();
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/src/app/components/dashboard/dashboard.component.html:
--------------------------------------------------------------------------------
1 |
18 |
19 | @if (clusterInfo) {
20 |
21 |