├── .github └── workflows │ ├── jekyll-docker.yml │ └── maven-publish.yml ├── Dockerfile ├── LICENSE ├── README.md ├── docker-compose.yml ├── images └── logo.png ├── pom.xml └── src └── main ├── java └── dev │ └── leons │ └── ward │ ├── Ward.java │ ├── components │ ├── ServletComponent.java │ └── UtilitiesComponent.java │ ├── configurations │ └── BeanConfiguration.java │ ├── controllers │ ├── ErrorController.java │ ├── IndexController.java │ ├── InfoController.java │ ├── SetupController.java │ ├── UptimeController.java │ └── UsageController.java │ ├── dto │ ├── ErrorDto.java │ ├── InfoDto.java │ ├── MachineDto.java │ ├── ProcessorDto.java │ ├── ResponseDto.java │ ├── SetupDto.java │ ├── StorageDto.java │ ├── UptimeDto.java │ └── UsageDto.java │ ├── exceptions │ ├── ApplicationAlreadyConfiguredException.java │ └── ApplicationNotConfiguredException.java │ ├── handlers │ └── ControllerExceptionHandler.java │ └── services │ ├── ErrorService.java │ ├── IndexService.java │ ├── InfoService.java │ ├── SetupService.java │ ├── UptimeService.java │ └── UsageService.java └── resources ├── static ├── css │ ├── animations.css │ ├── assets │ │ ├── bootstrap.min.css │ │ ├── dhtmlx.dark.min.css │ │ └── dhtmlx.light.min.css │ ├── colors.css │ ├── dimensions.css │ ├── fonts.css │ ├── gradients.css │ ├── layout.css │ ├── shadows.css │ └── themes.css ├── fonts │ └── roboto │ │ ├── bold.woff2 │ │ └── regular.woff2 ├── img │ ├── error │ │ ├── 404.gif │ │ └── 500.gif │ ├── ico │ │ └── favicon.ico │ ├── icons │ │ ├── disk.png │ │ ├── memory.png │ │ └── processor.png │ └── logo │ │ ├── background.png │ │ └── clouds │ │ ├── left.png │ │ └── right.png └── js │ ├── assets │ ├── chart.min.js │ ├── dhtmlx.min.js │ ├── three.min.js │ └── vanta.min.js │ ├── background.js │ ├── chart.js │ ├── globals.js │ ├── index.js │ ├── labels.js │ └── setup.js └── templates ├── error ├── 404.html └── 500.html ├── index.html └── setup.html /.github/workflows/jekyll-docker.yml: -------------------------------------------------------------------------------- 1 | name: docker-image 2 | on: 3 | release: 4 | types: [published] 5 | jobs: 6 | build-and-push: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: Checkout 10 | uses: actions/checkout@v4 11 | - name: Set up QEMU 12 | uses: docker/setup-qemu-action@v3 13 | - name: Set up Docker Buildx 14 | uses: docker/setup-buildx-action@v3 15 | - name: Login to DockerHub 16 | uses: docker/login-action@v3 17 | with: 18 | username: ${{ secrets.DOCKER_USERNAME }} 19 | password: ${{ secrets.DOCKER_TOKEN }} 20 | - name: Get the tag name 21 | run: echo "TAG=${GITHUB_REF/refs\/tags\//}" >> $GITHUB_ENV 22 | - name: Build and push Docker images 23 | uses: docker/build-push-action@v6.7.0 24 | with: 25 | context: . 26 | push: true 27 | platforms: linux/amd64,linux/arm64,linux/s390x,linux/ppc64le 28 | tags: antonyleons/ward:latest,antonyleons/ward:${{ env.TAG }} 29 | -------------------------------------------------------------------------------- /.github/workflows/maven-publish.yml: -------------------------------------------------------------------------------- 1 | name: build-jar 2 | on: pull_request 3 | jobs: 4 | build-and-upload: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - uses: actions/checkout@v4 8 | - uses: actions/setup-java@v4 9 | with: 10 | java-version: '17' 11 | distribution: 'temurin' 12 | - run: mvn clean install 13 | - run: mvn clean package 14 | - uses: actions/upload-artifact@v4 15 | with: 16 | name: Ward.jar 17 | path: target/*.jar 18 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Base image with maven installed already 2 | FROM maven:3.9-eclipse-temurin-17 as builder 3 | 4 | # Copy whole project inside docker 5 | COPY . . 6 | 7 | # Build project 8 | RUN mvn clean package 9 | 10 | 11 | # Base image containing OpenJDK 17 12 | FROM eclipse-temurin:17-jre 13 | 14 | # Copy jar and pom from builder image to working directory 15 | COPY --from=builder target/*.jar /ward.jar 16 | COPY --from=builder pom.xml /pom.xml 17 | 18 | EXPOSE 4000 19 | 20 | # Run jar as sudo user on entry point 21 | ENTRYPOINT java -jar ward.jar 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 B-Software 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ward_CN 2 | Ward性能监控的中文版本 3 | 原项目:https://github.com/AntonyLeons/Ward 4 | 5 | ### 关于 6 | 7 | Ward是一个简单而简约的服务器监控工具。Ward支持自适应设计系统。此外,它还支持黑暗主题。 8 | 它只显示主要信息,如果你想看到漂亮的仪表板,而不是看一堆数字和图表,可以使用它。 9 | Ward在所有流行的操作系统上都运行良好,因为它使用[OSHI](https://github.com/oshi/oshi). 10 | 11 | **所有功能都在以下平台上进行了测试:**“Windows”Linux` 12 | 13 | ![image](https://github.com/user-attachments/assets/fa63cbf2-0639-4277-bacb-f3e61460773b) 14 | 15 | 16 | --- 17 | 18 | ### 安装 19 | 20 | 创建你的jar 21 | 22 | • 克隆项目 23 | • 将IDE中的项目作为Maven项目导入 24 | • mvn 构建 25 | 26 |
27 | 28 | 运行jar文件 29 | 30 | 1.如上所述创建自己的罐子 31 | 2.使用管理权限在Windows或Linux上执行jar 32 | 3.输入localhost:4000并设置应用程序 33 | 34 |
35 | 36 | 用Docker构建 37 | 38 | 1. 克隆项目 39 | 2. docker build --tag ward 40 | 3. docker run --restart unless-stopped -it -d --name ward -p 4000:4000 -e WARD_PORT=4000 -e WARD_THEME=dark --privileged ward 41 | 4. 输入localhost:4000并设置应用程序 42 | 43 | ### Config 44 | 45 | 如果你想更改Ward的配置,你可以编辑`setup.ini `。使用Docker时,使用环境变量“WARD_NAME”、“WARD_THEME”和“WARD_PORT”在启动时自动重新生成此文件。使用列出的任何环境变量都将启用下面的默认值,并在没有GUI设置的情况下立即启动Ward。 46 | 47 | | 设置 | 变量 | 描述 | 默认 | 48 | |-----------------|-----------------|----------------------------------------------|---------| 49 | | serverName | WARD_NAME | 服务器的名称. | Ward | 50 | | port | WARD_PORT | 运行端口. | 4000 | 51 | | theme | WARD_THEME | 要么是“亮”,要么是“暗”. | light | 52 | | enableFog | WARD_FOG | 要么是“true”,要么是“false”. | true | 53 | | backgroundColor | WARD_BACKGROUND | 禁用雾时背景为HexColor. | default | 54 | 55 | 环境变量具有优先权,并将使用您的变量重新生成此文件。如果没有设置环境变量,则导航到Ward的网页并完成初始设置后,将生成“setup.ini”。您也可以在启动Ward之前自己制作此文件,并将其放置在同一目录中。 56 | 57 | 例如: 58 | 59 | ```ini 60 | [setup] 61 | serverName = my-server 62 | theme = dark 63 | port = 8200 64 | enableFog = true 65 | backgroundColor = #303030 66 | ``` 67 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.3' 2 | services: 3 | run: 4 | restart: unless-stopped 5 | container_name: ward 6 | ports: 7 | - '4000:4000' 8 | environment: 9 | - WARD_PORT=4000 10 | - WARD_THEME=dark 11 | - WARD_NAME=leons-server 12 | - WARD_FOG=false 13 | - WARD_BACKGROUND=#3c3c3c 14 | privileged: true 15 | image: antonyleons/ward -------------------------------------------------------------------------------- /images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Akttoer/Ward_CN/90b8902e1e244497399341890d7065a6d2b11e03/images/logo.png -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 4.0.0 7 | dev.leons 8 | ward 9 | 2.5.2 10 | jar 11 | 12 | 13 | 14 | org.springframework.boot 15 | spring-boot-starter-parent 16 | 3.1.10 17 | 18 | 19 | 20 | 21 | 22 | 6.6.0 23 | 5.14.0 24 | 1.18.32 25 | 0.5.4 26 | 27 | 28 | 29 | 30 | 31 | org.springframework.boot 32 | spring-boot-starter-web 33 | 34 | 35 | org.springframework.boot 36 | spring-boot-starter-thymeleaf 37 | 38 | 39 | org.springframework.boot 40 | spring-boot-starter-validation 41 | 42 | 43 | jakarta.validation 44 | jakarta.validation-api 45 | 3.0.2 46 | 47 | 48 | com.github.oshi 49 | oshi-core 50 | ${oshiVersion} 51 | 52 | 53 | net.java.dev.jna 54 | jna 55 | ${jnaVersion} 56 | 57 | 58 | net.java.dev.jna 59 | jna-platform 60 | ${jnaVersion} 61 | 62 | 63 | org.projectlombok 64 | lombok 65 | ${lombokVersion} 66 | 67 | 68 | org.ini4j 69 | ini4j 70 | ${ini4jVersion} 71 | 72 | 73 | 74 | 75 | 76 | ${project.basedir}/target 77 | ${project.build.directory}/classes 78 | 79 | 80 | org.springframework.boot 81 | spring-boot-maven-plugin 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /src/main/java/dev/leons/ward/Ward.java: -------------------------------------------------------------------------------- 1 | package dev.leons.ward; 2 | 3 | import dev.leons.ward.services.SetupService; 4 | import lombok.Getter; 5 | import org.springframework.boot.ApplicationArguments; 6 | import org.springframework.boot.SpringApplication; 7 | import org.springframework.boot.autoconfigure.SpringBootApplication; 8 | import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; 9 | import org.springframework.context.ConfigurableApplicationContext; 10 | 11 | import java.io.File; 12 | 13 | /** 14 | * Ward is a Spring Boot application class 15 | * 16 | * @author Rudolf Barbu 17 | * @version 1.0.4 18 | */ 19 | @SpringBootApplication 20 | public class Ward extends SpringBootServletInitializer { 21 | /** 22 | * Constant for determine settings file name 23 | */ 24 | public static final String SETUP_FILE_PATH = "setup.ini"; 25 | 26 | /** 27 | * Constant for determine initial application port 28 | */ 29 | public static final int INITIAL_PORT = 4000; 30 | 31 | /** 32 | * Holder for determine first launch of application 33 | */ 34 | @Getter 35 | private static boolean isFirstLaunch; 36 | 37 | /** 38 | * Holder for application context 39 | */ 40 | private static ConfigurableApplicationContext configurableApplicationContext; 41 | 42 | /** 43 | * Entry point of Ward application 44 | * 45 | * @param args Spring Boot application arguments 46 | */ 47 | public static void main(final String[] args) { 48 | 49 | isFirstLaunch = true; 50 | configurableApplicationContext = SpringApplication.run(Ward.class, args); 51 | 52 | File setupFile = new File(Ward.SETUP_FILE_PATH); 53 | 54 | if (System.getenv("WARD_NAME") != null || (System.getenv("WARD_THEME") != null) || (System.getenv("WARD_PORT") != null) || (System.getenv("WARD_FOG") != null)) { 55 | SetupService.envSetup(); 56 | } else if (setupFile.exists()) { 57 | restart(); 58 | } 59 | } 60 | 61 | /** 62 | * Restarts application 63 | */ 64 | public static void restart() { 65 | isFirstLaunch = false; 66 | ApplicationArguments args = configurableApplicationContext.getBean(ApplicationArguments.class); 67 | 68 | Thread thread = new Thread(() -> 69 | { 70 | configurableApplicationContext.close(); 71 | configurableApplicationContext = SpringApplication.run(Ward.class, args.getSourceArgs()); 72 | }); 73 | 74 | thread.setDaemon(false); 75 | thread.start(); 76 | } 77 | } -------------------------------------------------------------------------------- /src/main/java/dev/leons/ward/components/ServletComponent.java: -------------------------------------------------------------------------------- 1 | package dev.leons.ward.components; 2 | 3 | import dev.leons.ward.Ward; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; 6 | import org.springframework.boot.web.server.WebServerFactoryCustomizer; 7 | import org.springframework.stereotype.Component; 8 | 9 | import java.io.IOException; 10 | 11 | /** 12 | * ServletComponent used for application port changing 13 | * @author Rudolf Barbu 14 | * @version 1.0.3 15 | */ 16 | @Component 17 | public class ServletComponent implements WebServerFactoryCustomizer 18 | { 19 | /** 20 | * Autowired UtilitiesComponent object 21 | * Used for various utility functions 22 | */ 23 | @Autowired 24 | private UtilitiesComponent utilitiesComponent; 25 | 26 | /** 27 | * Customizes port of application 28 | * 29 | * @param tomcatServletWebServerFactory servlet factory 30 | */ 31 | @Override 32 | public void customize(final TomcatServletWebServerFactory tomcatServletWebServerFactory) 33 | { 34 | if (!Ward.isFirstLaunch()) 35 | { 36 | try 37 | { 38 | tomcatServletWebServerFactory.setPort(Integer.parseInt(utilitiesComponent.getFromIniFile("port"))); 39 | } 40 | catch (IOException exception) 41 | { 42 | exception.printStackTrace(); 43 | } 44 | } 45 | else 46 | { 47 | tomcatServletWebServerFactory.setPort(Ward.INITIAL_PORT); 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /src/main/java/dev/leons/ward/components/UtilitiesComponent.java: -------------------------------------------------------------------------------- 1 | package dev.leons.ward.components; 2 | 3 | import dev.leons.ward.Ward; 4 | import org.ini4j.Ini; 5 | import org.springframework.stereotype.Component; 6 | 7 | import java.io.File; 8 | import java.io.IOException; 9 | 10 | /** 11 | * UtilitiesComponent provides various functions, which are used in different classes 12 | * 13 | * @author Rudolf Barbu 14 | * @version 1.0.2 15 | */ 16 | @Component 17 | public class UtilitiesComponent { 18 | /** 19 | * Constant, that providing setup section name 20 | */ 21 | private static final String SECTION_NAME = "setup"; 22 | 23 | /** 24 | * Gets string data from ini file 25 | * 26 | * @param optionName option in section 27 | * @return String wth parsed data 28 | * @throws IOException if file does not exist 29 | */ 30 | @SuppressWarnings(value = "MismatchedQueryAndUpdateOfCollection") 31 | public String getFromIniFile(final String optionName) throws IOException { 32 | final File file = new File(Ward.SETUP_FILE_PATH); 33 | 34 | if (file.exists()) { 35 | final Ini ini = new Ini(file); 36 | return ini.get(SECTION_NAME, optionName, String.class); 37 | } 38 | 39 | return null; 40 | } 41 | 42 | /** 43 | * Sets string data to the ini file 44 | * 45 | * @param optionName option in section 46 | * @param value value to put 47 | * @throws IOException if file does not exist 48 | */ 49 | public void putInIniFile(final String optionName, final String value) throws IOException { 50 | final File file = new File(Ward.SETUP_FILE_PATH); 51 | 52 | if (file.exists()) { 53 | final Ini ini = new Ini(file); 54 | ini.put(SECTION_NAME, optionName, value); 55 | ini.store(); 56 | } else { 57 | throw new IOException(); 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /src/main/java/dev/leons/ward/configurations/BeanConfiguration.java: -------------------------------------------------------------------------------- 1 | package dev.leons.ward.configurations; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import oshi.SystemInfo; 6 | 7 | /** 8 | * BeanConfiguration provides bean configuration for classes, which are not components 9 | * 10 | * @author Rudolf Barbu 11 | * @version 1.0.2 12 | */ 13 | @Configuration 14 | public class BeanConfiguration 15 | { 16 | /** 17 | * @return SystemInfo object 18 | */ 19 | @Bean 20 | public SystemInfo systemInfo() 21 | { 22 | return new SystemInfo(); 23 | } 24 | } -------------------------------------------------------------------------------- /src/main/java/dev/leons/ward/controllers/ErrorController.java: -------------------------------------------------------------------------------- 1 | package dev.leons.ward.controllers; 2 | 3 | import dev.leons.ward.services.ErrorService; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.stereotype.Controller; 6 | import org.springframework.ui.Model; 7 | import org.springframework.web.bind.annotation.GetMapping; 8 | import org.springframework.web.bind.annotation.RequestMapping; 9 | 10 | import java.io.IOException; 11 | 12 | /** 13 | * ErrorController displays error pages of Ward application 14 | * 15 | * @author Rudolf Barbu 16 | * @version 1.0.2 17 | */ 18 | @Controller 19 | @RequestMapping(value = "/error") 20 | public class ErrorController implements org.springframework.boot.web.servlet.error.ErrorController 21 | { 22 | /** 23 | * Autowired ErrorService object 24 | * Used to determine error page 25 | */ 26 | @Autowired 27 | private ErrorService errorService; 28 | 29 | /** 30 | * Get request to display error page, which corresponds status code 31 | * 32 | * @return String name of html template 33 | */ 34 | @GetMapping 35 | public String getError(final Model model) throws IOException 36 | { 37 | return errorService.getError(model); 38 | } 39 | 40 | } -------------------------------------------------------------------------------- /src/main/java/dev/leons/ward/controllers/IndexController.java: -------------------------------------------------------------------------------- 1 | package dev.leons.ward.controllers; 2 | 3 | import dev.leons.ward.exceptions.ApplicationNotConfiguredException; 4 | import dev.leons.ward.services.IndexService; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.stereotype.Controller; 7 | import org.springframework.ui.Model; 8 | import org.springframework.web.bind.annotation.GetMapping; 9 | import org.springframework.web.bind.annotation.RequestMapping; 10 | 11 | import java.io.IOException; 12 | 13 | /** 14 | * IndexController displays index page of Ward application 15 | * 16 | * @author Rudolf Barbu 17 | * @version 1.0.2 18 | */ 19 | @Controller 20 | @RequestMapping(value = "/") 21 | public class IndexController 22 | { 23 | /** 24 | * Autowired IndexService object 25 | * Used for getting index page template 26 | */ 27 | @Autowired 28 | private IndexService indexService; 29 | 30 | /** 31 | * Get request to display index page 32 | * 33 | * @param model used for providing values in to html template 34 | * @return String name of html template with values from model param 35 | */ 36 | @GetMapping 37 | public String getIndex(final Model model) throws IOException, ApplicationNotConfiguredException 38 | { 39 | return indexService.getIndex(model); 40 | } 41 | } -------------------------------------------------------------------------------- /src/main/java/dev/leons/ward/controllers/InfoController.java: -------------------------------------------------------------------------------- 1 | package dev.leons.ward.controllers; 2 | 3 | import dev.leons.ward.dto.InfoDto; 4 | import dev.leons.ward.exceptions.ApplicationNotConfiguredException; 5 | import dev.leons.ward.services.InfoService; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.http.HttpStatus; 8 | import org.springframework.http.ResponseEntity; 9 | import org.springframework.web.bind.annotation.GetMapping; 10 | import org.springframework.web.bind.annotation.RequestMapping; 11 | import org.springframework.web.bind.annotation.RestController; 12 | 13 | /** 14 | * InfoController displays responses from rest API, about server 15 | * 16 | * @author Rudolf Barbu 17 | * @version 1.0.1 18 | */ 19 | @RestController 20 | @RequestMapping(value = "/api/info") 21 | public class InfoController 22 | { 23 | /** 24 | * Autowired InfoService object 25 | * Used for getting information about server 26 | */ 27 | @Autowired 28 | private InfoService infoService; 29 | 30 | /** 31 | * Get request to display current usage information for processor, RAM and storage 32 | * 33 | * @return ResponseEntity to servlet 34 | */ 35 | @GetMapping 36 | public ResponseEntity getInfo() throws ApplicationNotConfiguredException 37 | { 38 | return new ResponseEntity<>(infoService.getInfo(), HttpStatus.OK); 39 | } 40 | } -------------------------------------------------------------------------------- /src/main/java/dev/leons/ward/controllers/SetupController.java: -------------------------------------------------------------------------------- 1 | package dev.leons.ward.controllers; 2 | 3 | import dev.leons.ward.dto.ResponseDto; 4 | import dev.leons.ward.exceptions.ApplicationAlreadyConfiguredException; 5 | import dev.leons.ward.services.SetupService; 6 | import dev.leons.ward.dto.SetupDto; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.http.HttpStatus; 9 | import org.springframework.http.ResponseEntity; 10 | import org.springframework.web.bind.annotation.PostMapping; 11 | import org.springframework.web.bind.annotation.RequestBody; 12 | import org.springframework.web.bind.annotation.RequestMapping; 13 | import org.springframework.web.bind.annotation.RestController; 14 | 15 | import jakarta.validation.Valid; 16 | import java.io.IOException; 17 | 18 | /** 19 | * SetupController displays responses from rest API 20 | * 21 | * @author Rudolf Barbu 22 | * @version 1.0.1 23 | */ 24 | @RestController 25 | @RequestMapping(value = "/api/setup") 26 | public class SetupController 27 | { 28 | /** 29 | * Autowired SetupService object 30 | * Used for posting settings information in ini file 31 | */ 32 | @Autowired 33 | private SetupService setupService; 34 | 35 | /** 36 | * Posting setup info in database 37 | * 38 | * @param setupDto dto with data 39 | * @return ResponseEntity to servlet 40 | */ 41 | @PostMapping 42 | public ResponseEntity postSetup(@RequestBody @Valid final SetupDto setupDto) throws IOException, ApplicationAlreadyConfiguredException 43 | { 44 | return new ResponseEntity<>(setupService.postSetup(setupDto), HttpStatus.OK); 45 | } 46 | } -------------------------------------------------------------------------------- /src/main/java/dev/leons/ward/controllers/UptimeController.java: -------------------------------------------------------------------------------- 1 | package dev.leons.ward.controllers; 2 | 3 | import dev.leons.ward.dto.UptimeDto; 4 | import dev.leons.ward.services.UptimeService; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.http.HttpStatus; 7 | import org.springframework.http.ResponseEntity; 8 | import org.springframework.web.bind.annotation.GetMapping; 9 | import org.springframework.web.bind.annotation.RequestMapping; 10 | import org.springframework.web.bind.annotation.RestController; 11 | 12 | /** 13 | * SetupController displays responses from rest API 14 | * 15 | * @author Rudolf Barbu 16 | * @version 1.0.0 17 | */ 18 | @RestController 19 | @RequestMapping(value = "/api/uptime") 20 | public class UptimeController 21 | { 22 | /** 23 | * Autowired UptimeService object 24 | * Used for getting uptime information 25 | */ 26 | @Autowired 27 | private UptimeService uptimeService; 28 | 29 | /** 30 | * Get request to display uptime information 31 | * 32 | * @return ResponseEntity to servlet 33 | */ 34 | @GetMapping 35 | public ResponseEntity getUptime() 36 | { 37 | return new ResponseEntity<>(uptimeService.getUptime(), HttpStatus.OK); 38 | } 39 | } -------------------------------------------------------------------------------- /src/main/java/dev/leons/ward/controllers/UsageController.java: -------------------------------------------------------------------------------- 1 | package dev.leons.ward.controllers; 2 | 3 | import dev.leons.ward.dto.UsageDto; 4 | import dev.leons.ward.exceptions.ApplicationNotConfiguredException; 5 | import dev.leons.ward.services.UsageService; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.http.HttpStatus; 8 | import org.springframework.http.ResponseEntity; 9 | import org.springframework.web.bind.annotation.GetMapping; 10 | import org.springframework.web.bind.annotation.RequestMapping; 11 | import org.springframework.web.bind.annotation.RestController; 12 | 13 | /** 14 | * UsageController displays responses from rest API 15 | * 16 | * @author Rudolf Barbu 17 | * @version 1.0.1 18 | */ 19 | @RestController 20 | @RequestMapping(value = "/api/usage") 21 | public class UsageController 22 | { 23 | /** 24 | * Autowired UsageService object 25 | * Used for getting usage information 26 | */ 27 | @Autowired 28 | private UsageService usageService; 29 | 30 | /** 31 | * Get request to display current usage information for processor, RAM and storage 32 | * 33 | * @return ResponseEntity to servlet 34 | */ 35 | @GetMapping 36 | public ResponseEntity getUsage() throws ApplicationNotConfiguredException 37 | { 38 | return new ResponseEntity<>(usageService.getUsage(), HttpStatus.OK); 39 | } 40 | } -------------------------------------------------------------------------------- /src/main/java/dev/leons/ward/dto/ErrorDto.java: -------------------------------------------------------------------------------- 1 | package dev.leons.ward.dto; 2 | 3 | import lombok.Getter; 4 | 5 | import java.time.LocalDateTime; 6 | 7 | /** 8 | * ErrorDto is a container for error response 9 | * 10 | * @author Rudolf Barbu 11 | * @version 1.0.1 12 | */ 13 | @Getter 14 | public final class ErrorDto 15 | { 16 | /** 17 | * Error timestamp field 18 | */ 19 | private final String timestamp = LocalDateTime.now().toString(); 20 | 21 | /** 22 | * Error message field 23 | */ 24 | private final String errMessage; 25 | 26 | /** 27 | * Exception name field 28 | */ 29 | private final String exceptionName; 30 | 31 | /** 32 | * Setter for errMessage and exceptionName fields 33 | * 34 | * @param exception thrown exception 35 | */ 36 | public ErrorDto(final Exception exception) 37 | { 38 | this.errMessage = exception.getMessage(); 39 | this.exceptionName = exception.getClass().getName(); 40 | } 41 | } -------------------------------------------------------------------------------- /src/main/java/dev/leons/ward/dto/InfoDto.java: -------------------------------------------------------------------------------- 1 | package dev.leons.ward.dto; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | /** 7 | * InfoDto is a container for other info objects 8 | * 9 | * @author Rudolf Barbu 10 | * @version 1.0.1 11 | */ 12 | @Getter 13 | @Setter 14 | public class InfoDto 15 | { 16 | /** 17 | * Processor info dto field 18 | */ 19 | private ProcessorDto processor; 20 | 21 | /** 22 | * machine info dto field 23 | */ 24 | private MachineDto machine; 25 | 26 | /** 27 | * Storage info dto field 28 | */ 29 | private StorageDto storage; 30 | } -------------------------------------------------------------------------------- /src/main/java/dev/leons/ward/dto/MachineDto.java: -------------------------------------------------------------------------------- 1 | package dev.leons.ward.dto; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | /** 7 | * MachineDto is a values container for presenting machine principal information 8 | * 9 | * @author Rudolf Barbu 10 | * @version 1.0.0 11 | */ 12 | @Getter 13 | @Setter 14 | public class MachineDto 15 | { 16 | /** 17 | * OS info field 18 | */ 19 | private String operatingSystem; 20 | 21 | /** 22 | * Amount of total installed ram field 23 | */ 24 | private String totalRam; 25 | 26 | /** 27 | * Ram generation field 28 | */ 29 | private String ramTypeOrOSBitDepth; 30 | 31 | /** 32 | * Processes count field 33 | */ 34 | private String procCount; 35 | } -------------------------------------------------------------------------------- /src/main/java/dev/leons/ward/dto/ProcessorDto.java: -------------------------------------------------------------------------------- 1 | package dev.leons.ward.dto; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | /** 7 | * ProcessorDto is a values container for presenting processor principal information 8 | * 9 | * @author Rudolf Barbu 10 | * @version 1.0.0 11 | */ 12 | @Getter 13 | @Setter 14 | public class ProcessorDto 15 | { 16 | /** 17 | * Processor name field 18 | */ 19 | private String name; 20 | 21 | /** 22 | * Core count field 23 | */ 24 | private String coreCount; 25 | 26 | /** 27 | * Processor max frequency field 28 | */ 29 | private String clockSpeed; 30 | 31 | /** 32 | * Processor architecture field 33 | */ 34 | private String bitDepth; 35 | } -------------------------------------------------------------------------------- /src/main/java/dev/leons/ward/dto/ResponseDto.java: -------------------------------------------------------------------------------- 1 | package dev.leons.ward.dto; 2 | 3 | import lombok.Getter; 4 | 5 | /** 6 | * ResponseDto is a values container for presenting response info 7 | * 8 | * @author Rudolf Barbu 9 | * @version 1.0.0 10 | */ 11 | @Getter 12 | public final class ResponseDto 13 | { 14 | /** 15 | * Response message field 16 | */ 17 | private final String message; 18 | 19 | /** 20 | * Setter for message field 21 | * 22 | * @param message message to display 23 | */ 24 | public ResponseDto(final String message) 25 | { 26 | this.message = message; 27 | } 28 | } -------------------------------------------------------------------------------- /src/main/java/dev/leons/ward/dto/SetupDto.java: -------------------------------------------------------------------------------- 1 | package dev.leons.ward.dto; 2 | 3 | import jakarta.validation.constraints.Max; 4 | import jakarta.validation.constraints.Min; 5 | import jakarta.validation.constraints.NotEmpty; 6 | import jakarta.validation.constraints.NotNull; 7 | import jakarta.validation.constraints.Pattern; 8 | import jakarta.validation.constraints.Size; 9 | import lombok.Getter; 10 | import lombok.Setter; 11 | 12 | /** 13 | * SetupDto is a values container for setup data 14 | * 15 | * @author Rudolf Barbu 16 | * @version 1.0.3 17 | */ 18 | @Getter 19 | @Setter 20 | public class SetupDto 21 | { 22 | /** 23 | * Server name Field 24 | */ 25 | @NotNull 26 | @Size(min = 0, max = 10) 27 | private String serverName; 28 | 29 | /** 30 | * Theme name field 31 | */ 32 | @NotNull 33 | @NotEmpty 34 | @Pattern(regexp = "light|dark") 35 | private String theme; 36 | 37 | /** 38 | * Port port field 39 | */ 40 | @NotNull 41 | @NotEmpty 42 | @Min(value = 10) 43 | @Max(value = 65535) 44 | private String port; 45 | 46 | /** 47 | * Enable fog field 48 | */ 49 | @NotNull 50 | @NotEmpty 51 | @Pattern(regexp = "true|false") 52 | private String enableFog; 53 | 54 | /** 55 | * Background Color field 56 | */ 57 | @NotEmpty 58 | @Pattern(regexp = "^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$|default") 59 | private String backgroundColor; 60 | } -------------------------------------------------------------------------------- /src/main/java/dev/leons/ward/dto/StorageDto.java: -------------------------------------------------------------------------------- 1 | package dev.leons.ward.dto; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | /** 7 | * StorageDto is a values container for presenting storage principal information 8 | * 9 | * @author Rudolf Barbu 10 | * @version 1.0.0 11 | */ 12 | @Getter 13 | @Setter 14 | public class StorageDto 15 | { 16 | /** 17 | * Host0 storage name field 18 | */ 19 | private String mainStorage; 20 | 21 | /** 22 | * Amount of total installed storage field 23 | */ 24 | private String total; 25 | 26 | /** 27 | * Disk count field 28 | */ 29 | private String diskCount; 30 | 31 | /** 32 | * Total amount of virtual memory (Swap on Linux) field 33 | */ 34 | private String swapAmount; 35 | } -------------------------------------------------------------------------------- /src/main/java/dev/leons/ward/dto/UptimeDto.java: -------------------------------------------------------------------------------- 1 | package dev.leons.ward.dto; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | /** 7 | * UptimeDto is a values container for presenting uptime principal information 8 | * 9 | * @author Rudolf Barbu 10 | * @version 1.0.0 11 | */ 12 | @Getter 13 | @Setter 14 | public class UptimeDto 15 | { 16 | /** 17 | * Uptime days field 18 | */ 19 | private String days; 20 | 21 | /** 22 | * Uptime hours field 23 | */ 24 | private String hours; 25 | 26 | /** 27 | * Uptime minutes field 28 | */ 29 | private String minutes; 30 | 31 | /** 32 | * Uptime seconds field 33 | */ 34 | private String seconds; 35 | } -------------------------------------------------------------------------------- /src/main/java/dev/leons/ward/dto/UsageDto.java: -------------------------------------------------------------------------------- 1 | package dev.leons.ward.dto; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | /** 7 | * UsageDto is a values container for presenting server usage 8 | * 9 | * @author Rudolf Barbu 10 | * @version 1.0.1 11 | */ 12 | @Getter 13 | @Setter 14 | public class UsageDto 15 | { 16 | /** 17 | * Processor usage field 18 | */ 19 | private int processor; 20 | 21 | /** 22 | * Ram usage field 23 | */ 24 | private int ram; 25 | 26 | /** 27 | * Storage usage field 28 | */ 29 | private int storage; 30 | } -------------------------------------------------------------------------------- /src/main/java/dev/leons/ward/exceptions/ApplicationAlreadyConfiguredException.java: -------------------------------------------------------------------------------- 1 | package dev.leons.ward.exceptions; 2 | 3 | /** 4 | * ApplicationAlreadyConfiguredException indicates that user tried to access api, when application is already configured 5 | * 6 | * @author Rudolf Barbu 7 | * @version 1.0.0 8 | */ 9 | public class ApplicationAlreadyConfiguredException extends Exception 10 | { 11 | /** 12 | * Call super class with exception message 13 | */ 14 | public ApplicationAlreadyConfiguredException() 15 | { 16 | super("Application already configured"); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/dev/leons/ward/exceptions/ApplicationNotConfiguredException.java: -------------------------------------------------------------------------------- 1 | package dev.leons.ward.exceptions; 2 | 3 | /** 4 | * ApplicationNotSetUpException indicates that user tried to access api, without setting up the application 5 | * 6 | * @author Rudolf Barbu 7 | * @version 1.0.0 8 | */ 9 | public final class ApplicationNotConfiguredException extends Exception 10 | { 11 | /** 12 | * Call super class with exception message 13 | */ 14 | public ApplicationNotConfiguredException() 15 | { 16 | super("Set up application first"); 17 | } 18 | } -------------------------------------------------------------------------------- /src/main/java/dev/leons/ward/handlers/ControllerExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package dev.leons.ward.handlers; 2 | 3 | import dev.leons.ward.components.UtilitiesComponent; 4 | import dev.leons.ward.dto.ErrorDto; 5 | import dev.leons.ward.exceptions.ApplicationAlreadyConfiguredException; 6 | import dev.leons.ward.exceptions.ApplicationNotConfiguredException; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.core.Ordered; 9 | import org.springframework.core.annotation.Order; 10 | import org.springframework.http.HttpStatus; 11 | import org.springframework.http.ResponseEntity; 12 | import org.springframework.http.converter.HttpMessageNotReadableException; 13 | import org.springframework.ui.Model; 14 | import org.springframework.web.HttpRequestMethodNotSupportedException; 15 | import org.springframework.web.bind.MethodArgumentNotValidException; 16 | import org.springframework.web.bind.annotation.ControllerAdvice; 17 | import org.springframework.web.bind.annotation.ExceptionHandler; 18 | import org.springframework.web.bind.annotation.ResponseBody; 19 | 20 | import java.io.IOException; 21 | 22 | /** 23 | * ControllerExceptionHandler is standard exception handler for rest api, and white labels 24 | * 25 | * @author Rudolf Barbu 26 | * @version 1.0.0 27 | */ 28 | @ControllerAdvice 29 | @Order(value = Ordered.HIGHEST_PRECEDENCE) 30 | public class ControllerExceptionHandler 31 | { 32 | /** 33 | * Autowired UtilitiesComponent object 34 | * Used for various utility functions 35 | */ 36 | @Autowired 37 | private UtilitiesComponent utilitiesComponent; 38 | 39 | /** 40 | * Handles exceptions with BAD_REQUEST status, then they thrown 41 | */ 42 | @ResponseBody 43 | @ExceptionHandler(value = {ApplicationNotConfiguredException.class, ApplicationAlreadyConfiguredException.class}) 44 | public ResponseEntity applicationNotSetUpExceptionHandler(final Exception exception) 45 | { 46 | return new ResponseEntity<>(new ErrorDto(exception), HttpStatus.BAD_REQUEST); 47 | } 48 | 49 | /** 50 | * Handles exceptions with UNPROCESSABLE_ENTITY status, then they thrown 51 | */ 52 | @ResponseBody 53 | @ExceptionHandler(value = {MethodArgumentNotValidException.class, HttpMessageNotReadableException.class}) 54 | public ResponseEntity methodArgumentNotValidExceptionHandler(final Exception exception) 55 | { 56 | return new ResponseEntity<>(new ErrorDto(exception), HttpStatus.UNPROCESSABLE_ENTITY); 57 | } 58 | 59 | /** 60 | * Handles MethodArgumentNotValidException, then it thrown 61 | * Also handles all other servlet exceptions, which were not handled by others handlers 62 | * 63 | * @throws IOException if ini file is unreachable 64 | */ 65 | @ExceptionHandler(value = Exception.class) 66 | public String exceptionHandler(final Exception exception, final Model model) throws IOException 67 | { 68 | model.addAttribute("theme", utilitiesComponent.getFromIniFile("theme")); 69 | System.out.println(exception.getMessage()); 70 | return (exception instanceof HttpRequestMethodNotSupportedException) ? "error/404" : "error/500"; 71 | } 72 | } -------------------------------------------------------------------------------- /src/main/java/dev/leons/ward/services/ErrorService.java: -------------------------------------------------------------------------------- 1 | package dev.leons.ward.services; 2 | 3 | import dev.leons.ward.Ward; 4 | import dev.leons.ward.components.UtilitiesComponent; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.stereotype.Service; 7 | import org.springframework.ui.Model; 8 | 9 | import java.io.IOException; 10 | 11 | /** 12 | * ErrorService displays error pages of Ward application 13 | * 14 | * @author Rudolf Barbu 15 | * @version 1.0.1 16 | */ 17 | @Service 18 | public class ErrorService 19 | { 20 | /** 21 | * Autowired UtilitiesComponent object 22 | * Used for various utility functions 23 | */ 24 | @Autowired 25 | private UtilitiesComponent utilitiesComponent; 26 | 27 | /** 28 | * Returns 404 error page 29 | * 30 | * @param model container for strings 31 | * @return template name 32 | * @throws IOException if ini file is unreachable 33 | */ 34 | public String getError(final Model model) throws IOException 35 | { 36 | if (Ward.isFirstLaunch()) 37 | { 38 | return "setup"; 39 | } 40 | 41 | model.addAttribute("theme", utilitiesComponent.getFromIniFile("theme")); 42 | return "error/404"; 43 | } 44 | } -------------------------------------------------------------------------------- /src/main/java/dev/leons/ward/services/IndexService.java: -------------------------------------------------------------------------------- 1 | package dev.leons.ward.services; 2 | 3 | import dev.leons.ward.Ward; 4 | import dev.leons.ward.components.UtilitiesComponent; 5 | import dev.leons.ward.exceptions.ApplicationNotConfiguredException; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Service; 8 | import org.springframework.ui.Model; 9 | 10 | import java.io.IOException; 11 | import java.io.InputStream; 12 | import java.util.Properties; 13 | 14 | /** 15 | * IndexService displays index page of Ward application 16 | * 17 | * @author Rudolf Barbu 18 | * @version 1.0.1 19 | */ 20 | @Service 21 | public class IndexService 22 | { 23 | /** 24 | * Autowired InfoService object 25 | * Used for getting machine information for html template 26 | */ 27 | @Autowired 28 | private InfoService infoService; 29 | 30 | /** 31 | * Autowired UptimeService object 32 | * Used for getting uptime for html template 33 | */ 34 | @Autowired 35 | private UptimeService uptimeService; 36 | 37 | /** 38 | * Autowired UtilitiesComponent object 39 | * Used for various utility functions 40 | */ 41 | @Autowired 42 | private UtilitiesComponent utilitiesComponent; 43 | 44 | /** 45 | * Gets project version information 46 | * 47 | * @return MavenDto with filled field 48 | * @throws IOException if file does not exists 49 | */ 50 | private String getVersion() throws IOException 51 | { 52 | Properties properties = new Properties(); 53 | InputStream inputStream = getClass().getResourceAsStream("/META-INF/maven/dev.leons/ward/pom.properties"); 54 | 55 | if (inputStream != null) 56 | { 57 | properties.load(inputStream); 58 | String version = properties.getProperty("version"); 59 | 60 | return "Ward: v" + version; 61 | } 62 | else 63 | { 64 | return "Developer mode"; 65 | } 66 | } 67 | 68 | /** 69 | * Fills model and returns template name 70 | * 71 | * @param model strings container 72 | * @return template name 73 | */ 74 | public String getIndex(final Model model) throws IOException, ApplicationNotConfiguredException 75 | { 76 | if (Ward.isFirstLaunch()) 77 | { 78 | return "setup"; 79 | } 80 | 81 | updateDefaultsInSetupFile(); 82 | 83 | model.addAttribute("theme", utilitiesComponent.getFromIniFile("theme")); 84 | model.addAttribute("serverName", utilitiesComponent.getFromIniFile("serverName")); 85 | model.addAttribute("enableFog", utilitiesComponent.getFromIniFile("enableFog")); 86 | model.addAttribute("backgroundColor", utilitiesComponent.getFromIniFile("backgroundColor")); 87 | 88 | model.addAttribute("info", infoService.getInfo()); 89 | model.addAttribute("uptime", uptimeService.getUptime()); 90 | model.addAttribute("version", getVersion()); 91 | 92 | return "index"; 93 | } 94 | 95 | private void updateDefaultsInSetupFile() throws IOException { 96 | if (utilitiesComponent.getFromIniFile("enableFog") == null) { 97 | utilitiesComponent.putInIniFile("enableFog", "true"); 98 | } 99 | if (utilitiesComponent.getFromIniFile("backgroundColor") == null) { 100 | utilitiesComponent.putInIniFile("backgroundColor", "#303030"); 101 | } 102 | } 103 | } -------------------------------------------------------------------------------- /src/main/java/dev/leons/ward/services/InfoService.java: -------------------------------------------------------------------------------- 1 | package dev.leons.ward.services; 2 | 3 | import dev.leons.ward.Ward; 4 | import dev.leons.ward.dto.InfoDto; 5 | import dev.leons.ward.dto.MachineDto; 6 | import dev.leons.ward.dto.ProcessorDto; 7 | import dev.leons.ward.dto.StorageDto; 8 | import dev.leons.ward.components.UtilitiesComponent; 9 | import dev.leons.ward.exceptions.ApplicationNotConfiguredException; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.stereotype.Service; 12 | import oshi.SystemInfo; 13 | import oshi.hardware.CentralProcessor; 14 | import oshi.hardware.GlobalMemory; 15 | import oshi.hardware.HWDiskStore; 16 | import oshi.hardware.PhysicalMemory; 17 | import oshi.software.os.OperatingSystem; 18 | 19 | import java.util.Arrays; 20 | import java.util.List; 21 | import java.util.Optional; 22 | 23 | /** 24 | * InfoService provides various information about machine, such as processor name, core count, Ram amount, etc. 25 | * 26 | * @author Rudolf Barbu 27 | * @version 1.0.2 28 | */ 29 | @Service 30 | public class InfoService 31 | { 32 | /** 33 | * Autowired SystemInfo object 34 | * Used for getting machine information 35 | */ 36 | @Autowired 37 | private SystemInfo systemInfo; 38 | 39 | /** 40 | * Autowired UtilitiesComponent object 41 | * Used for various utility functions 42 | */ 43 | @Autowired 44 | private UtilitiesComponent utilitiesComponent; 45 | 46 | /** 47 | * Converts frequency to most readable format 48 | * 49 | * @param hertzArray raw frequency array values in hertz for each logical processor 50 | * @return String with formatted frequency and postfix 51 | */ 52 | private String getConvertedFrequency(final long[] hertzArray) 53 | { 54 | long totalFrequency = Arrays.stream(hertzArray).sum(); 55 | long hertz = totalFrequency / hertzArray.length; 56 | 57 | if ((hertz / 1E+6) > 999) 58 | { 59 | return (Math.round((hertz / 1E+9) * 10.0) / 10.0) + " GHz"; 60 | } 61 | else 62 | { 63 | return Math.round(hertz / 1E+6) + " MHz"; 64 | } 65 | } 66 | 67 | /** 68 | * Converts capacity to most readable format 69 | * 70 | * @param bits raw capacity value in bits 71 | * @return String with formatted capacity and postfix 72 | */ 73 | private String getConvertedCapacity(final long bits) 74 | { 75 | if ((bits / 1.049E+6) > 999) 76 | { 77 | if ((bits / 1.074E+9) > 999) 78 | { 79 | return (Math.round((bits / 1.1E+12) * 10.0) / 10.0) + " TiB"; 80 | } 81 | else 82 | { 83 | return Math.round(bits / 1.074E+9) + " GiB"; 84 | } 85 | } 86 | else 87 | { 88 | return Math.round(bits / 1.049E+6) + " MiB"; 89 | } 90 | } 91 | 92 | /** 93 | * Gets processor information 94 | * 95 | * @return ProcessorDto with filled fields 96 | */ 97 | private ProcessorDto getProcessor() { 98 | ProcessorDto processorDto = new ProcessorDto(); 99 | CentralProcessor centralProcessor = systemInfo.getHardware().getProcessor(); 100 | 101 | // Extract processor name 102 | String name = centralProcessor.getProcessorIdentifier().getName().split("@")[0].trim(); 103 | processorDto.setName(name); 104 | 105 | // Set core count 106 | int coreCount = centralProcessor.getLogicalProcessorCount(); 107 | processorDto.setCoreCount(coreCount + (coreCount > 1 ? " Cores" : " Core")); 108 | 109 | // Set clock speed 110 | processorDto.setClockSpeed(getConvertedFrequency(centralProcessor.getCurrentFreq())); 111 | 112 | // Set bit depth 113 | String bitDepth = centralProcessor.getProcessorIdentifier().isCpu64bit() ? "64-bit" : "32-bit"; 114 | processorDto.setBitDepth(bitDepth); 115 | 116 | return processorDto; 117 | } 118 | 119 | /** 120 | * Gets machine information 121 | * 122 | * @return MachineDto with filled fields 123 | */ 124 | private MachineDto getMachine() { 125 | MachineDto machineDto = new MachineDto(); 126 | 127 | OperatingSystem operatingSystem = systemInfo.getOperatingSystem(); 128 | OperatingSystem.OSVersionInfo osVersionInfo = operatingSystem.getVersionInfo(); 129 | GlobalMemory globalMemory = systemInfo.getHardware().getMemory(); 130 | 131 | String osDescription = operatingSystem.getFamily() + " " + osVersionInfo.getVersion(); 132 | machineDto.setOperatingSystem(osDescription); 133 | 134 | long totalRam = globalMemory.getTotal(); 135 | machineDto.setTotalRam(getConvertedCapacity(totalRam) + " RAM"); 136 | 137 | Optional physicalMemoryOptional = globalMemory.getPhysicalMemory().stream().findFirst(); 138 | String ramTypeOrOSBitDepth; 139 | if (physicalMemoryOptional.isPresent()) { 140 | ramTypeOrOSBitDepth = physicalMemoryOptional.get().getMemoryType(); 141 | } else { 142 | ramTypeOrOSBitDepth = operatingSystem.getBitness() + "-bit"; 143 | } 144 | machineDto.setRamTypeOrOSBitDepth(ramTypeOrOSBitDepth); 145 | 146 | int processCount = operatingSystem.getProcessCount(); 147 | String procCount = processCount + ((processCount > 1) ? " Procs" : " Proc"); 148 | machineDto.setProcCount(procCount); 149 | 150 | return machineDto; 151 | } 152 | 153 | /** 154 | * Gets storage information 155 | * 156 | * @return StorageDto with filled fields 157 | */ 158 | private StorageDto getStorage() 159 | { 160 | StorageDto storageDto = new StorageDto(); 161 | List hwDiskStores = systemInfo.getHardware().getDiskStores(); 162 | GlobalMemory globalMemory = systemInfo.getHardware().getMemory(); 163 | 164 | // Retrieve main storage model 165 | String mainStorage = hwDiskStores.isEmpty() ? "Undefined" 166 | : hwDiskStores.get(0).getModel().replaceAll("\\(.+?\\)", "").trim(); 167 | storageDto.setMainStorage(mainStorage); 168 | 169 | long total = hwDiskStores.stream().mapToLong(HWDiskStore::getSize).sum(); 170 | storageDto.setTotal(getConvertedCapacity(total) + " Total"); 171 | 172 | int diskCount = hwDiskStores.size(); 173 | storageDto.setDiskCount(diskCount + (diskCount > 1 ? " Disks" : " Disk")); 174 | 175 | storageDto.setSwapAmount(getConvertedCapacity(globalMemory.getVirtualMemory().getSwapTotal()) + " Swap"); 176 | 177 | return storageDto; 178 | } 179 | 180 | /** 181 | * Used to deliver dto to corresponding controller 182 | * 183 | * @return InfoDto filled with server info 184 | */ 185 | public InfoDto getInfo() throws ApplicationNotConfiguredException 186 | { 187 | if (!Ward.isFirstLaunch()) 188 | { 189 | InfoDto infoDto = new InfoDto(); 190 | 191 | infoDto.setProcessor(getProcessor()); 192 | infoDto.setMachine(getMachine()); 193 | infoDto.setStorage(getStorage()); 194 | 195 | return infoDto; 196 | } 197 | else 198 | { 199 | throw new ApplicationNotConfiguredException(); 200 | } 201 | } 202 | } -------------------------------------------------------------------------------- /src/main/java/dev/leons/ward/services/SetupService.java: -------------------------------------------------------------------------------- 1 | package dev.leons.ward.services; 2 | 3 | import dev.leons.ward.Ward; 4 | import dev.leons.ward.dto.ResponseDto; 5 | import dev.leons.ward.dto.SetupDto; 6 | import dev.leons.ward.exceptions.ApplicationAlreadyConfiguredException; 7 | import org.ini4j.Ini; 8 | import org.springframework.stereotype.Service; 9 | 10 | import java.io.File; 11 | import java.io.IOException; 12 | 13 | /** 14 | * SetupService manipulating setup data 15 | * 16 | * @author Rudolf Barbu 17 | * @version 1.0.2 18 | */ 19 | @Service 20 | public class SetupService { 21 | /** 22 | * Constant, that providing setup section name 23 | */ 24 | private static final String SECTION_NAME = "setup"; 25 | 26 | /** 27 | * Puts new data in ini file 28 | * 29 | * @param file ini file 30 | * @param optionName option in section 31 | * @throws IOException if file does not exists 32 | */ 33 | private static void putInIniFile(final File file, final String optionName, final String value) throws IOException { 34 | Ini ini = new Ini(file); 35 | ini.put(SECTION_NAME, optionName, value); 36 | ini.store(); 37 | } 38 | 39 | /** 40 | * Fills setup data in ini file 41 | * 42 | * @param setupDto user settings data 43 | * @return ResponseEntityWrapperAsset filled with ResponseDto 44 | * @throws IOException IoException if file is fot found, and cant be created 45 | */ 46 | public ResponseDto postSetup(final SetupDto setupDto) throws IOException, ApplicationAlreadyConfiguredException { 47 | if (Ward.isFirstLaunch()) { 48 | File file = new File(Ward.SETUP_FILE_PATH); 49 | 50 | if (file.createNewFile()) { 51 | putInIniFile(file, "serverName", setupDto.getServerName()); 52 | putInIniFile(file, "theme", setupDto.getTheme()); 53 | putInIniFile(file, "port", setupDto.getPort()); 54 | putInIniFile(file, "enableFog", setupDto.getEnableFog()); 55 | putInIniFile(file, "backgroundColor", setupDto.getBackgroundColor()); 56 | 57 | Ward.restart(); 58 | } else { 59 | throw new IOException(); 60 | } 61 | } else { 62 | throw new ApplicationAlreadyConfiguredException(); 63 | } 64 | 65 | return new ResponseDto("Settings saved correctly"); 66 | } 67 | 68 | public static ResponseDto envSetup() { 69 | if (Ward.isFirstLaunch()) { 70 | try { 71 | File file = new File(Ward.SETUP_FILE_PATH); 72 | if (file.exists()) { 73 | file.delete(); 74 | } 75 | if (file.createNewFile()) { 76 | String servername = (System.getenv("WARD_NAME") != null) ? System.getenv("WARD_NAME") : "Ward"; 77 | String theme = (System.getenv("WARD_THEME") != null) ? System.getenv("WARD_THEME").toLowerCase() : "light"; 78 | String port = (System.getenv("WARD_PORT") != null) ? System.getenv("WARD_PORT") : "4000"; 79 | String enableFog = (System.getenv("WARD_FOG") != null) ? System.getenv("WARD_FOG") : "true"; 80 | String backgroundColor = (System.getenv("WARD_BACKGROUND") != null) ? System.getenv("WARD_BACKGROUND") : "default"; 81 | 82 | putInIniFile(file, "serverName", servername); 83 | putInIniFile(file, "theme", theme); 84 | putInIniFile(file, "port", port); 85 | putInIniFile(file, "enableFog", enableFog); 86 | putInIniFile(file, "backgroundColor", backgroundColor); 87 | 88 | Ward.restart(); 89 | } else { 90 | throw new IOException(); 91 | } 92 | 93 | } catch (IOException e) { 94 | e.printStackTrace(); 95 | } 96 | } 97 | 98 | return new ResponseDto("Settings saved correctly"); 99 | } 100 | } -------------------------------------------------------------------------------- /src/main/java/dev/leons/ward/services/UptimeService.java: -------------------------------------------------------------------------------- 1 | package dev.leons.ward.services; 2 | 3 | import dev.leons.ward.dto.UptimeDto; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.stereotype.Service; 6 | import oshi.SystemInfo; 7 | 8 | @Service 9 | public class UptimeService 10 | { 11 | @Autowired 12 | private SystemInfo systemInfo; 13 | 14 | /** 15 | * Gets uptime information 16 | * 17 | * @return UptimeDto with filled fields 18 | */ 19 | public UptimeDto getUptime() 20 | { 21 | UptimeDto uptimeDto = new UptimeDto(); 22 | 23 | long uptimeInSeconds = systemInfo.getOperatingSystem().getSystemUptime(); 24 | 25 | uptimeDto.setDays(String.format("%02d", (int) uptimeInSeconds / 86400)); 26 | uptimeDto.setHours(String.format("%02d", (int) (uptimeInSeconds % 86400) / 3600)); 27 | uptimeDto.setMinutes(String.format("%02d", (int) (uptimeInSeconds / 60) % 60)); 28 | uptimeDto.setSeconds(String.format("%02d", (int) uptimeInSeconds % 60)); 29 | 30 | return uptimeDto; 31 | } 32 | } -------------------------------------------------------------------------------- /src/main/java/dev/leons/ward/services/UsageService.java: -------------------------------------------------------------------------------- 1 | package dev.leons.ward.services; 2 | 3 | import dev.leons.ward.Ward; 4 | import dev.leons.ward.dto.UsageDto; 5 | import dev.leons.ward.exceptions.ApplicationNotConfiguredException; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Service; 8 | import oshi.SystemInfo; 9 | import oshi.hardware.CentralProcessor; 10 | import oshi.hardware.GlobalMemory; 11 | import oshi.software.os.FileSystem; 12 | import oshi.software.os.OSFileStore; 13 | import oshi.util.Util; 14 | 15 | import java.util.Arrays; 16 | 17 | /** 18 | * UsageService provides principal information of processor, RAM and storage usage to rest controller 19 | * 20 | * @author Rudolf Barbu 21 | * @version 1.0.3 22 | */ 23 | @Service 24 | public class UsageService 25 | { 26 | /** 27 | * Autowired SystemInfo object 28 | * Used for getting usage information 29 | */ 30 | @Autowired 31 | private SystemInfo systemInfo; 32 | 33 | /** 34 | * Gets processor usage 35 | * 36 | * @return int that display processor usage 37 | */ 38 | private int getProcessor() { 39 | CentralProcessor centralProcessor = systemInfo.getHardware().getProcessor(); 40 | long[] prevTicksArray = centralProcessor.getSystemCpuLoadTicks(); 41 | long prevTotalTicks = Arrays.stream(prevTicksArray).sum(); 42 | long prevIdleTicks = prevTicksArray[CentralProcessor.TickType.IDLE.getIndex()]; 43 | 44 | Util.sleep(1000); 45 | 46 | long[] currTicksArray = centralProcessor.getSystemCpuLoadTicks(); 47 | long currTotalTicks = Arrays.stream(currTicksArray).sum(); 48 | long currIdleTicks = currTicksArray[CentralProcessor.TickType.IDLE.getIndex()]; 49 | 50 | long idleTicksDelta = currIdleTicks - prevIdleTicks; 51 | long totalTicksDelta = currTotalTicks - prevTotalTicks; 52 | 53 | // Handle possible division by zero 54 | if (totalTicksDelta == 0) { 55 | return 0; // or handle in a way suitable for your application 56 | } 57 | 58 | // Calculate CPU usage percentage 59 | return (int) ((1 - (double) idleTicksDelta / totalTicksDelta) * 100); 60 | } 61 | 62 | /** 63 | * Gets ram usage 64 | * 65 | * @return int that display ram usage 66 | */ 67 | private int getRam() { 68 | GlobalMemory globalMemory = systemInfo.getHardware().getMemory(); 69 | long totalMemory = globalMemory.getTotal(); 70 | long availableMemory = globalMemory.getAvailable(); 71 | 72 | // Handle possible division by zero 73 | if (totalMemory == 0) { 74 | return 0; // or handle in a way suitable for your application 75 | } 76 | 77 | // Calculate RAM usage percentage 78 | return (int) (100 - ((double) availableMemory / totalMemory * 100)); 79 | } 80 | 81 | /** 82 | * Gets storage usage 83 | * 84 | * @return int that display storage usage 85 | */ 86 | private int getStorage() { 87 | FileSystem fileSystem = systemInfo.getOperatingSystem().getFileSystem(); 88 | 89 | // Calculate total storage and free storage for all drives 90 | long totalStorage = 0; 91 | long freeStorage = 0; 92 | for (OSFileStore fileStore : fileSystem.getFileStores()) { 93 | totalStorage += fileStore.getTotalSpace(); 94 | freeStorage += fileStore.getFreeSpace(); 95 | } 96 | 97 | // Handle possible division by zero 98 | if (totalStorage == 0) { 99 | return 0; // or handle in a way suitable for your application 100 | } 101 | 102 | // Calculate total storage usage percentage for all drives 103 | return (int) Math.round(((double) (totalStorage - freeStorage) / totalStorage) * 100); 104 | } 105 | 106 | /** 107 | * Used to deliver dto to corresponding controller 108 | * 109 | * @return ResponseEntityWrapperAsset filled with usageDto 110 | */ 111 | public UsageDto getUsage() throws ApplicationNotConfiguredException 112 | { 113 | if (!Ward.isFirstLaunch()) 114 | { 115 | UsageDto usageDto = new UsageDto(); 116 | 117 | usageDto.setProcessor(getProcessor()); 118 | usageDto.setRam(getRam()); 119 | usageDto.setStorage(getStorage()); 120 | 121 | return usageDto; 122 | } 123 | else 124 | { 125 | throw new ApplicationNotConfiguredException(); 126 | } 127 | } 128 | } -------------------------------------------------------------------------------- /src/main/resources/static/css/animations.css: -------------------------------------------------------------------------------- 1 | /* 2 | Animations file 3 | Used for define animations of project 4 | 5 | Every category must follow convention: 6 | * Category must begins with "animation" word 7 | * Further should be followed by animation property name 8 | 9 | Every entry must follow convention: 10 | * Must begins with category name 11 | * Further should be followed by tag/class/id/animation name/etc. 12 | 13 | By example: --animation-duration-wiggle 14 | */ 15 | 16 | :root 17 | { 18 | /* animation-duration */ 19 | --animation-duration-fade-in-setup-div: 0.4s; 20 | --animation-duration-fade-in-square: 0.5s; 21 | --animation-duration-wiggle-usage-value: 0.6s; 22 | --animation-duration-fade-in-triangle: 0.5s; 23 | --animation-duration-fade-in-error-div: 0.8s; 24 | 25 | /* animation-delay */ 26 | --animation-delay-chart-triangle-grid-div: 1s; 27 | --animation-delay-usage-value-first: 0.2s; 28 | --animation-delay-usage-value-second: 0.4s; 29 | --animation-delay-usage-value-third: 0.6s; 30 | } 31 | 32 | @keyframes fade-in-setup-div 33 | { 34 | 0% 35 | { 36 | opacity: 0; 37 | } 38 | 100% 39 | { 40 | opacity: 1; 41 | } 42 | } 43 | 44 | @keyframes fade-in-square 45 | { 46 | 0% 47 | { 48 | top: 0.000rem; 49 | opacity: 0; 50 | } 51 | 100% 52 | { 53 | top: 0.563rem; 54 | opacity: 1; 55 | } 56 | } 57 | 58 | @keyframes fade-out-square 59 | { 60 | 0% 61 | { 62 | top: 0.563rem; 63 | opacity: 1; 64 | } 65 | 100% 66 | { 67 | top: 0.000rem; 68 | opacity: 0; 69 | } 70 | } 71 | 72 | @keyframes wiggle-usage-value 73 | { 74 | 0% 75 | { 76 | top: 0.000rem; 77 | } 78 | 50% 79 | { 80 | top: -2rem; 81 | } 82 | 100% 83 | { 84 | top: 0.000rem; 85 | } 86 | } 87 | 88 | @keyframes fade-in-cloud-left 89 | { 90 | 0% 91 | { 92 | left: -5.000rem; 93 | } 94 | 100% 95 | { 96 | left: 0.000rem; 97 | } 98 | } 99 | 100 | @keyframes fade-out-cloud-left 101 | { 102 | 0% 103 | { 104 | left: 0.000rem; 105 | } 106 | 100% 107 | { 108 | left: -5.000rem; 109 | } 110 | } 111 | 112 | @keyframes fade-in-cloud-right 113 | { 114 | 0% 115 | { 116 | left: 17.875rem; 117 | } 118 | 100% 119 | { 120 | left: 12.875rem; 121 | } 122 | } 123 | 124 | @keyframes fade-out-cloud-right 125 | { 126 | 0% 127 | { 128 | left: 12.875rem; 129 | } 130 | 100% 131 | { 132 | left: 17.875rem; 133 | } 134 | } 135 | 136 | @keyframes fade-in-triangle 137 | { 138 | 0% 139 | { 140 | top: 0.000rem; 141 | opacity: 0; 142 | } 143 | 100% 144 | { 145 | top: 0.563rem; 146 | opacity: 1; 147 | } 148 | } 149 | 150 | @keyframes fade-out-triangle 151 | { 152 | 0% 153 | { 154 | top: 0.563rem; 155 | opacity: 1; 156 | } 157 | 100% 158 | { 159 | top: 0.000rem; 160 | opacity: 0; 161 | } 162 | } 163 | 164 | @keyframes fade-in-error-div 165 | { 166 | 0% 167 | { 168 | bottom: 3.125rem; 169 | opacity: 0; 170 | } 171 | 100% 172 | { 173 | bottom: 7.500rem; 174 | opacity: 1; 175 | } 176 | } -------------------------------------------------------------------------------- /src/main/resources/static/css/assets/dhtmlx.dark.min.css: -------------------------------------------------------------------------------- 1 | .dhtmlx_message_area{position:fixed;right:5px;width:250px;z-index:1000}.dhtmlx-info{min-width:350px;min-height:35px;padding:4px 4px 4px 20px;font-family:Tahoma;z-index:10000;margin:5px;margin-bottom:10px;-webkit-transition:all .5s ease;-moz-transition:all .5s ease;-o-transition:all .5s ease;transition:all .5s ease}.dhtmlx-info.hidden{height:0;min-height:0;padding-top:0;padding-bottom:0;border-width:0;margin-top:0;margin-bottom:0;overflow:hidden}.dhtmlx_modal_box{overflow:hidden;display:inline-block;min-width:300px;width:300px;text-align:center;position:fixed;background-color:#fff;background:-webkit-linear-gradient(top,#fff 1%,#d0d0d0 99%);background:-moz-linear-gradient(top,#fff 1%,#d0d0d0 99%);box-shadow:0 0 14px #888;font-family:Tahoma;z-index:20000;border-radius:6px;border:1px solid #fff}.dhtmlx_popup_title{border-top-left-radius:5px;border-top-right-radius:5px;border-width:0;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAoCAMAAAAIaGBFAAAAhFBMVEVwcHBubm5sbGxqampoaGhmZmZlZWVjY2NhYWFfX19dXV1bW1taWlpYWFhWVlZUVFRSUlJRUVFPT09NTU1LS0tJSUlHR0dGRkZERERCQkJAQEA+Pj49PT09PT0+Pj5AQEBBQUFDQ0NERERGRkZHR0dJSUlKSkpMTExMTEw5OTk5OTk5OTkny8YEAAAAQklEQVQImQXBCRJCAAAAwKVSQqdyjSPXNP7/QLsIhA6OTiJnF7GrRCpzc/fw9PKW+/gqlCq1RqvTG/yMJrPF6m/bAVEhAxxnHG0oAAAAAElFTkSuQmCC);background-image:-webkit-linear-gradient(top,#707070 1%,#3d3d3d 70%,#4c4c4c 97%,#393939 97%);background-image:-moz-linear-gradient(top,#707070 1%,#3d3d3d 70%,#4c4c4c 97%,#393939 97%)}.dhtmlx-info,.dhtmlx_button,.dhtmlx_popup_button{user-select:none;-webkit-user-select:none;-moz-user-select:-moz-none;cursor:pointer}.dhtmlx_popup_text{overflow:hidden}.dhtmlx_popup_controls{border-radius:6px;padding:5px}.dhtmlx_button,.dhtmlx_popup_button{height:30px;line-height:30px;display:inline-block;margin:0 5px;border-radius:6px;color:#fff}.dhtmlx_popup_button{min-width:120px}div.dhx_modal_cover{background-color:#000;cursor:default;opacity:.2;position:fixed;z-index:19999;left:0;top:0;width:100%;height:100%;border:none;zoom:1}.dhtmlx-info img,.dhtmlx_modal_box img{float:left;margin-right:20px}.dhtmlx-info img{margin-left:-10px}.dhtmlx-alert-error .dhtmlx_popup_title,.dhtmlx-confirm-error .dhtmlx_popup_title{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAsCAIAAAArRUU2AAAATklEQVR4nIWLuw2AMBBDjVuQiBT2oWbRDATrnB0KQOJoqPzRe3BrHI6dcBASYREKovtK6/6DsDOX+stN+3H1YX9ciRgnYq5EWYhS2dftBIuLT4JyIrPCAAAAAElFTkSuQmCC)}.dhtmlx-alert-error,.dhtmlx-confirm-error{border:1px solid red}.dhtmlx_button,.dhtmlx_popup_button{box-shadow:0 0 4px #888;border:1px solid #838383}.dhtmlx_button input,.dhtmlx_popup_button div{border:1px solid #fff;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAeCAMAAADaS4T1AAAAYFBMVEVwcHBtbW1ra2toaGhmZmZjY2NhYWFeXl5cXFxaWlpXV1dVVVVSUlJQUFBNTU1LS0tJSUlGRkZERERBQUE/Pz88PDw9PT0+Pj5AQEBCQkJDQ0NFRUVHR0dISEhKSkpMTEzqthaMAAAAMklEQVQImQXBhQ2AMAAAsOIMlwWH/8+kRSKVyRVKlVrQaHV6g9FktlhFm93hdLk9Xt8PIfgBvdUqyskAAAAASUVORK5CYII=);background-image:-webkit-linear-gradient(top,#707070 1%,#3d3d3d 70%,#4c4c4c 99%);background-image:-moz-linear-gradient(top,#707070 1%,#3d3d3d 70%,#4c4c4c 99%);border-radius:6px;font-size:15px;-moz-box-sizing:content-box;box-sizing:content-box;color:#fff;padding:0;margin:0;vertical-align:top;height:28px;line-height:28px}.dhtmlx_button input:active,.dhtmlx_button input:focus,.dhtmlx_popup_button div:active,.dhtmlx_popup_button div:focus{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAeCAMAAADaS4T1AAAAXVBMVEVwcHBubm5tbW1sbGxra2tpaWloaGhnZ2dmZmZlZWVjY2NiYmJhYWFgYGBfX19dXV1cXFxbW1taWlpZWVlXV1dWVlZVVVVUVFRTU1NRUVFQUFBPT09OTk5NTU1LS0tT9SY0AAAAMUlEQVQImQXBhQGAMAAAIGxnx2z9/00BiVQmVyhVakGj1ekNRpPZYhVtdofT5fZ4fT8hpwG05JjexgAAAABJRU5ErkJggg==);background-image:-webkit-linear-gradient(top,#707070 1%,#4c4c4c 99%);background-image:-moz-linear-gradient(top,#707070 1%,#4c4c4c 99%)}.dhtmlx_popup_title{color:#fff;text-shadow:1px 1px #000;height:40px;line-height:40px;font-size:20px}.dhtmlx_popup_text{margin:15px 15px 5px 15px;font-size:14px;color:#000;min-height:30px;border-radius:6px}.dhtmlx-error,.dhtmlx-info{font-size:14px;color:#fff;box-shadow:0 4px 4px -4px #000;border-radius:5px;background-color:#000;background-color:rgba(0,0,0,.8)}.dhtmlx-error{color:red} -------------------------------------------------------------------------------- /src/main/resources/static/css/assets/dhtmlx.light.min.css: -------------------------------------------------------------------------------- 1 | .dhtmlx_message_area{position:fixed;right:5px;width:250px;z-index:1000}.dhtmlx-info{min-width:350px;min-height:30px;padding:4px 4px 4px 20px;font-family:Tahoma;z-index:10000;margin:5px;margin-bottom:10px;-webkit-transition:all .5s ease;-moz-transition:all .5s ease;-o-transition:all .5s ease;transition:all .5s ease}.dhtmlx-info.hidden{height:0;min-height:0;padding-top:0;padding-bottom:0;border-width:0;margin-top:0;margin-bottom:0;overflow:hidden}.dhtmlx_modal_box{overflow:hidden;display:inline-block;min-width:300px;width:300px;text-align:center;position:fixed;background-color:#fff;background:-webkit-linear-gradient(top,#fff 1%,#d0d0d0 99%);background:-moz-linear-gradient(top,#fff 1%,#d0d0d0 99%);box-shadow:0 0 14px #888;font-family:Tahoma;z-index:20000;border-radius:6px;border:1px solid #fff}.dhtmlx_popup_title{border-top-left-radius:5px;border-top-right-radius:5px;border-width:0;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAoCAMAAAAIaGBFAAAAhFBMVEVwcHBubm5sbGxqampoaGhmZmZlZWVjY2NhYWFfX19dXV1bW1taWlpYWFhWVlZUVFRSUlJRUVFPT09NTU1LS0tJSUlHR0dGRkZERERCQkJAQEA+Pj49PT09PT0+Pj5AQEBBQUFDQ0NERERGRkZHR0dJSUlKSkpMTExMTEw5OTk5OTk5OTkny8YEAAAAQklEQVQImQXBCRJCAAAAwKVSQqdyjSPXNP7/QLsIhA6OTiJnF7GrRCpzc/fw9PKW+/gqlCq1RqvTG/yMJrPF6m/bAVEhAxxnHG0oAAAAAElFTkSuQmCC);background-image:-webkit-linear-gradient(top,#707070 1%,#3d3d3d 70%,#4c4c4c 97%,#393939 97%);background-image:-moz-linear-gradient(top,#707070 1%,#3d3d3d 70%,#4c4c4c 97%,#393939 97%)}.dhtmlx-info,.dhtmlx_button,.dhtmlx_popup_button{user-select:none;-webkit-user-select:none;-moz-user-select:-moz-none;cursor:pointer}.dhtmlx_popup_text{overflow:hidden}.dhtmlx_popup_controls{border-radius:6px;padding:5px}.dhtmlx_button,.dhtmlx_popup_button{height:30px;line-height:30px;display:inline-block;margin:0 5px;border-radius:6px;color:#fff}.dhtmlx_popup_button{min-width:120px}div.dhx_modal_cover{background-color:#000;cursor:default;opacity:.2;position:fixed;z-index:19999;left:0;top:0;width:100%;height:100%;border:none;zoom:1}.dhtmlx-info img,.dhtmlx_modal_box img{float:left;margin-right:20px}.dhtmlx-alert-error .dhtmlx_popup_title,.dhtmlx-confirm-error .dhtmlx_popup_title{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAsCAIAAAArRUU2AAAATklEQVR4nIWLuw2AMBBDjVuQiBT2oWbRDATrnB0KQOJoqPzRe3BrHI6dcBASYREKovtK6/6DsDOX+stN+3H1YX9ciRgnYq5EWYhS2dftBIuLT4JyIrPCAAAAAElFTkSuQmCC)}.dhtmlx-alert-error,.dhtmlx-confirm-error{border:1px solid red}.dhtmlx_button,.dhtmlx_popup_button{box-shadow:0 0 4px #888;border:1px solid #838383}.dhtmlx_button input,.dhtmlx_popup_button div{border:1px solid #fff;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAeCAMAAADaS4T1AAAAYFBMVEVwcHBtbW1ra2toaGhmZmZjY2NhYWFeXl5cXFxaWlpXV1dVVVVSUlJQUFBNTU1LS0tJSUlGRkZERERBQUE/Pz88PDw9PT0+Pj5AQEBCQkJDQ0NFRUVHR0dISEhKSkpMTEzqthaMAAAAMklEQVQImQXBhQ2AMAAAsOIMlwWH/8+kRSKVyRVKlVrQaHV6g9FktlhFm93hdLk9Xt8PIfgBvdUqyskAAAAASUVORK5CYII=);background-image:-webkit-linear-gradient(top,#707070 1%,#3d3d3d 70%,#4c4c4c 99%);background-image:-moz-linear-gradient(top,#707070 1%,#3d3d3d 70%,#4c4c4c 99%);border-radius:6px;font-size:15px;font-weight:400;-moz-box-sizing:content-box;box-sizing:content-box;color:#fff;padding:0;margin:0;vertical-align:top;height:28px;line-height:28px}.dhtmlx_button input:active,.dhtmlx_button input:focus,.dhtmlx_popup_button div:active,.dhtmlx_popup_button div:focus{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAeCAMAAADaS4T1AAAAXVBMVEVwcHBubm5tbW1sbGxra2tpaWloaGhnZ2dmZmZlZWVjY2NiYmJhYWFgYGBfX19dXV1cXFxbW1taWlpZWVlXV1dWVlZVVVVUVFRTU1NRUVFQUFBPT09OTk5NTU1LS0tT9SY0AAAAMUlEQVQImQXBhQGAMAAAIGxnx2z9/00BiVQmVyhVakGj1ekNRpPZYhVtdofT5fZ4fT8hpwG05JjexgAAAABJRU5ErkJggg==);background-image:-webkit-linear-gradient(top,#707070 1%,#4c4c4c 99%);background-image:-moz-linear-gradient(top,#707070 1%,#4c4c4c 99%)}.dhtmlx_popup_title{color:#fff;text-shadow:1px 1px #000;height:40px;line-height:40px;font-size:20px}.dhtmlx_popup_text{margin:15px 15px 5px 15px;font-size:14px;color:#000;min-height:30px;border-radius:6px}.dhtmlx-error,.dhtmlx-info{font-size:14px;color:#000;box-shadow:0 0 10px #888;padding:0;background-color:#fff;border-radius:3px;border:1px solid #fff}.dhtmlx-info div{padding:5px 10px 5px 10px;background-color:#fff;border-radius:3px}.dhtmlx-error{background-color:#d81b1b;border:1px solid #ff3c3c;box-shadow:0 0 10px #000}.dhtmlx-error div{background-color:#d81b1b;border:1px solid #940000;color:#fff} -------------------------------------------------------------------------------- /src/main/resources/static/css/colors.css: -------------------------------------------------------------------------------- 1 | /* 2 | Colors file 3 | Used for define colors of project 4 | 5 | Every category must follow convention: 6 | * Category must contain only color name 7 | 8 | Every entry must follow convention: 9 | * Must begins with category name 10 | * Further should be followed by tint/opacity/etc. 11 | 12 | By example: --grey-light 13 | */ 14 | 15 | :root 16 | { 17 | /* white */ 18 | --white: rgba(255, 255, 255, 1); 19 | --white-opacity-40: rgba(255, 255, 255, 0.4); 20 | --white-opacity-70: rgba(255, 255, 255, 0.7); 21 | --white-opacity-90: rgba(255, 255, 255, 0.9); 22 | 23 | /* black */ 24 | --black: rgba(0, 0, 0, 1); 25 | --black-opacity-10: rgba(0, 0, 0, 0.1); 26 | 27 | /* grey */ 28 | --grey-light: rgba(188, 188, 188, 1); 29 | --grey: rgba(121, 121, 121, 1); 30 | --grey-opacity-90: rgba(121, 121, 121, 0.9); 31 | --grey-opacity-70: rgba(121, 121, 121, 0.7); 32 | --grey-dimmed: rgba(90, 90, 90, 1); 33 | --grey-dark: rgba(60, 60, 60, 1); 34 | 35 | /* blue */ 36 | --blue-light: rgba(121, 131, 247, 1); 37 | --blue-form: rgba(230, 232, 254, 1); 38 | --blue: rgba(89, 101, 249, 1); 39 | 40 | /* red */ 41 | --red-light: rgba(255, 117, 117, 1); 42 | --red-form: rgba(249, 226, 226, 1); 43 | --red: rgba(255, 89, 89, 1); 44 | 45 | /* green */ 46 | --green-light: rgba(70, 191, 157, 1); 47 | --green-form: rgba(212, 242, 225, 1); 48 | --green: rgba(8, 193, 141, 1); 49 | 50 | /* purple */ 51 | --purple-light: rgba(228, 227, 239, 1); 52 | } -------------------------------------------------------------------------------- /src/main/resources/static/css/dimensions.css: -------------------------------------------------------------------------------- 1 | /* 2 | Dimensions file 3 | Used for define dimensions of project 4 | 5 | Every category must follow convention: 6 | * Category must contain only css property name 7 | 8 | Every entry must follow convention: 9 | * Must begins with category name 10 | * Further should be followed by tag/class/id/etc. 11 | 12 | By example: --height-body 13 | */ 14 | 15 | :root { 16 | /* top */ 17 | --top-logo: 2.188rem; 18 | --top-logo-description: 5.3rem; 19 | --top-clouds-first: 2.875rem; 20 | --top-clouds-second: 2.875rem; 21 | --top-main-settings-input: 0.125rem; 22 | --top-main-settings-underline: 0.313rem; 23 | --top-main-settings-select: 0.938rem; 24 | --top-label-additional-settings: 2.3rem; 25 | --top-additional-settings: 1rem; 26 | --top-theme-buttons-input: 1.938rem; 27 | --top-background-settings: 2.938rem; 28 | --top-button-squares-grid: 0.222rem; 29 | --top-port: 2.7rem; 30 | --top-header: 1.5rem; 31 | --top-label-hw-info: 0.562rem; 32 | --top-info-label: 4.188rem; 33 | --top-inner-dot: 0.375rem; 34 | --top-detailed-hw-info-div: 1.168rem; 35 | --top-announcement: 3.813rem; 36 | --top-uptime-rectangle-grid: 1.925rem; 37 | --top-chart-label: 1.5rem; 38 | --top-chart-triangle-grid: 0.5rem; 39 | --top-chart-rectangle-grid: 1.906rem; 40 | --top-chart-container: 3.375rem; 41 | --top-code: 1.813rem; 42 | --top-title: 3.5rem; 43 | --top-explanation: 6.688rem; 44 | 45 | /* bottom */ 46 | --bottom-form-squares-grid: 0.813rem; 47 | --bottom-submit: 1.125rem; 48 | --bottom-usage: 4.625rem; 49 | --bottom-hw-usage-div: 0.25rem; 50 | --bottom-values-grid-div-p: 0.25rem; 51 | --bottom-project-version: 1.25rem; 52 | --bottom-error-div: 7.5rem; 53 | --bottom-advice: 0.563rem; 54 | 55 | /* left */ 56 | --left-clouds-second: 12.875rem; 57 | --left-form-squares-grid: 9.25rem; 58 | --left-main-settings: 1.5rem; 59 | --left-button-squares-grid-first: 1.5rem; 60 | --left-button-squares-grid-second: 19.688rem; 61 | --left-background-settings: 1.5rem; 62 | --left-theme-buttons-first: 1.5rem; 63 | --left-background-settings-color-selector: 1.5rem; 64 | --left-port: 1.5rem; 65 | --left-submit: 6.563rem; 66 | --left-header: 1.5rem; 67 | --left-label-hw-info: 4.375rem; 68 | --left-usage: 1.5rem; 69 | --left-inner-dot: 0.375rem; 70 | --left-detailed-hw-info-first: 0.822rem; 71 | --left-detailed-hw-info-second: 8.104rem; 72 | --left-detailed-hw-info-third: 15.385rem; 73 | --left-dividers-first: 7.313rem; 74 | --left-dividers-second: 14.563rem; 75 | --left-uptime-rectangle-grid: 2.23rem; 76 | --left-chart-label: 1.5rem; 77 | --left-chart-triangle-grid-first: 34.375rem; 78 | --left-chart-triangle-grid-second: 38.25rem; 79 | --left-chart-triangle-grid-third: 42.125rem; 80 | --left-chart-rectangle-grid-first: 33.25rem; 81 | --left-chart-rectangle-grid-second: 37.125rem; 82 | --left-chart-rectangle-grid-third: 41rem; 83 | --left-chart-container: 1.5rem; 84 | --left-error-div: 13.25rem; 85 | --left-code: 1.813rem; 86 | --left-title: 1.813rem; 87 | --left-explanation: 1.813rem; 88 | 89 | /* margin */ 90 | --margin-hardware-icon: 0.65rem; 91 | 92 | /* margin-right */ 93 | --margin-right-form-squares-grid-div: 0.488rem; 94 | --margin-right-theme-buttons-first: 1.938rem; 95 | --margin-right-usage-value: 2.937rem; 96 | --margin-right-values-grid-div: 0.125rem; 97 | --margin-right-labels-grid-div: 0.125rem; 98 | 99 | /* margin-bottom */ 100 | --margin-bottom-label-main-settings: 0.438rem; 101 | --margin-bottom-card: 1.875rem; 102 | --margin-bottom-labels-grid-div: 0.313rem; 103 | 104 | /* height */ 105 | --height-body: 100%; 106 | --height-setup: 26.706rem; 107 | --height-setup-div: 32.706rem; 108 | --height-clouds: 8.281rem; 109 | --height-clouds-img: 5.438rem; 110 | --height-background: 8.281rem; 111 | --height-form: 24.425rem; 112 | --height-form-squares-grid-div: 0.625rem; 113 | --height-main-settings: 1.875rem; 114 | --height-main-settings-underline: 0.313rem; 115 | --height-main-settings-select: 1.875rem; 116 | --height-theme-buttons-input: 2.188rem; 117 | --height-background-settings: 2.188rem; 118 | --height-button-squares-grid-div: 0.625rem; 119 | --height-port: 3.125rem; 120 | --height-submit: 1.875rem; 121 | --height-index-xl: 35.031rem; 122 | --height-index-lg: 53.438rem; 123 | --height-index-md: 53.438rem; 124 | --height-hw-logo: 3.75rem; 125 | --height-usage: 5.313rem; 126 | --height-main-hw-info: 100%; 127 | --height-usage-value-span: 5.8rem; 128 | --height-usage-underline: 0.313rem; 129 | --height-footer: 3.125rem; 130 | --height-inner-dot: 0.75rem; 131 | --height-detailed-hw-info-div: 1.063rem; 132 | --height-dividers-div: 3.125rem; 133 | --height-uptime: 8.27rem; 134 | --height-values-grid-div: 3.188rem; 135 | --height-labels-grid-div: 0.813rem; 136 | --height-chart-rectangle-grid-div: 0.625rem; 137 | --height-chart-container: 11.688rem; 138 | --height-error: 25.75rem; 139 | --height-error-img: 19.313rem; 140 | --height-error-div: 12.125rem; 141 | --height-hardware-icon: 2.5rem; 142 | 143 | /* max-height */ 144 | --max-height-card: 16.562rem; 145 | 146 | /* min-height */ 147 | --min-height-card: 16.562rem; 148 | 149 | /* width */ 150 | --width-body: 100%; 151 | --width-dhtmlx-message-area: 21.875rem; 152 | --width-setup-div: 21.875rem; 153 | --width-logo: 21.875rem; 154 | --width-logo-description: 21.875rem; 155 | --width-clouds: 21.875rem; 156 | --width-clouds-img: 4.375rem; 157 | --width-background: 21.875rem; 158 | --width-form: 21.875rem; 159 | --width-form-squares-grid-div: 0.625rem; 160 | --width-main-settings: 18.875rem; 161 | --width-main-settings-input: 18.875rem; 162 | --width-main-settings-underline: 18.875rem; 163 | --width-main-settings-select: 18.875rem; 164 | --width-theme-buttons-input: 9.063rem; 165 | --width-background-settings-input: 9.063rem; 166 | --width-button-squares-grid-div: 0.625rem; 167 | --width-port: 18.875rem; 168 | --width-submit: 8.75rem; 169 | --width-hw-logo: 3.75rem; 170 | --width-usage: 18.875rem; 171 | --width-usage-value-span: 2.224rem; 172 | --width-info-label: 9.5rem; 173 | --width-usage-underline: 9.5rem; 174 | --width-footer: 100%; 175 | --width-inner-dot: 0.75rem; 176 | --width-detailed-hw-info-div: 5.625rem; 177 | --width-dividers-div: 0.063rem; 178 | --width-announcement: 21.875rem; 179 | --width-uptime: 100%; 180 | --width-values-grid-div: 3.75rem; 181 | --width-labels-grid-div: 3.75rem; 182 | --day-width-values-grid-div: 5rem; 183 | --day-width-labels-grid-div: 5rem; 184 | --width-chart-rectangle-grid-div: 3.125rem; 185 | --width-chart-container: 42.625rem; 186 | --width-error-img: 19.313rem; 187 | --width-error-div: 23.875rem; 188 | --width-advice: 23.875rem; 189 | --width-hardware-icon: 2.5rem; 190 | 191 | /* max-width */ 192 | --max-width-setup: 71.25rem; 193 | --max-width-index-xl: 71.25rem; 194 | --max-width-index-lg: 47.5rem; 195 | --max-width-index-md: 23.75rem; 196 | --max-width-col-sm-12-col-md-6-col-lg-6-col-xl-4: 23.75rem; 197 | --max-width-col-lg-12-col-xl-8: 47.5rem; 198 | 199 | /* min-width */ 200 | --min-width-setup: 71.25rem; 201 | --min-width-index-xl: 71.25rem; 202 | --min-width-index-lg: 47.5rem; 203 | --min-width-index-md: 23.75rem; 204 | --min-width-col-sm-12-col-md-6-col-lg-6-col-xl-4: 23.75rem; 205 | --min-width-col-lg-12-col-xl-8: 47.5rem; 206 | --min-width-error: 71.25rem; 207 | 208 | /* border */ 209 | --border-chart-container: 0.063rem; 210 | 211 | /* border-width */ 212 | --border-width-chart-triangle-grid-div: 0.438rem 0.438rem 0rem 0.438rem; 213 | 214 | /* border-radius */ 215 | --border-radius-setup-div: 1.25rem; 216 | --border-radius-port: 0rem 0rem 0.625rem 0.625rem; 217 | --border-radius-card: 1.25rem; 218 | --border-radius-hw-logo: 50%; 219 | --border-radius-inner-dot: 50%; 220 | --border-radius-error-img: 50%; 221 | --border-radius-error-div: 1.25rem; 222 | 223 | /* letter-spacing */ 224 | --letter-spacing-2px: 0.125rem; 225 | --letter-spacing-5px: 0.313rem; 226 | --letter-spacing-10px: 0.625rem; 227 | 228 | /* transition */ 229 | --transition-all: color 0.2s, background 0.2s, transform 0.07s, opacity 0.4s; 230 | 231 | /* transform */ 232 | --transform-form-squares-grid-second: scale(1.3); 233 | --transform-theme-buttons-input-active: scale(0.9); 234 | --transform-submit-active: scale(0.9); 235 | --transform-chart-rectangle-grid-div-active: scale(0.9); 236 | } 237 | -------------------------------------------------------------------------------- /src/main/resources/static/css/fonts.css: -------------------------------------------------------------------------------- 1 | /* 2 | Fonts file 3 | Used for define fonts of project 4 | 5 | Every category must follow convention: 6 | * Category must begins with "font" word 7 | * Further should be followed by font property name 8 | 9 | Every entry must follow convention: 10 | * Must begins with category name 11 | * Further should be followed by size/weight/family/etc. 12 | 13 | By example: --font-weight-regular 14 | */ 15 | 16 | :root 17 | { 18 | /* font-family */ 19 | --font-family-roboto: roboto; 20 | 21 | /* font-size */ 22 | --font-size-9pt: 0.563em; 23 | --font-size-10pt: 0.625em; 24 | --font-size-11pt: 0.688em; 25 | --font-size-12pt: 0.750em; 26 | --font-size-13pt: 0.813em; 27 | --font-size-14pt: 0.875em; 28 | --font-size-18pt: 1.125em; 29 | --font-size-21pt: 1.313em; 30 | --font-size-31pt: 1.938em; 31 | --font-size-42pt: 2.625em; 32 | --font-size-62pt: 3.875em; 33 | 34 | /* font-weight */ 35 | --font-weight-regular: 400; 36 | --font-weight-bold: 700; 37 | } 38 | 39 | @font-face 40 | { 41 | font-family: roboto; 42 | font-weight: 400; 43 | src: url(/fonts/roboto/regular.woff2) format('woff2'); 44 | } 45 | 46 | @font-face 47 | { 48 | font-family: roboto; 49 | font-weight: 700; 50 | src: url(/fonts/roboto/bold.woff2) format('woff2'); 51 | } -------------------------------------------------------------------------------- /src/main/resources/static/css/gradients.css: -------------------------------------------------------------------------------- 1 | /* 2 | Gradients file 3 | Used for define gradients of project 4 | 5 | Every category must follow convention: 6 | * Category must contain only gradient type name 7 | 8 | Every entry must follow convention: 9 | * Must begins with category name 10 | * Further should be followed by tag/class/id/etc. 11 | 12 | By example: --linear-gradient-uptime 13 | */ 14 | 15 | :root 16 | { 17 | /* linear-gradient */ 18 | --linear-gradient-form-light: linear-gradient(45deg, var(--blue-form) 0%, var(--red-form) 50%, var(--green-form) 100%); 19 | --linear-gradient-form-dark: linear-gradient(45deg, var(--grey) 0%, var(--grey-dimmed) 50%, var(--grey) 100%); 20 | --linear-gradient-uptime-light: linear-gradient(45deg, var(--blue-form) 0%, var(--red-form) 50%, var(--green-form) 100%); 21 | --linear-gradient-uptime-dark: linear-gradient(45deg, var(--grey) 0%, var(--grey-dimmed) 50%, var(--grey) 100%); 22 | } -------------------------------------------------------------------------------- /src/main/resources/static/css/layout.css: -------------------------------------------------------------------------------- 1 | /* 2 | Layout css file 3 | New classes, indexes and overrides must be defined here 4 | 5 | Every category must follow convention: 6 | * Category must contain page name (Exception are base classes) 7 | * Page name must be followed by word "elements" 8 | 9 | By example: index elements 10 | */ 11 | 12 | /* base elements */ 13 | * { 14 | font-family: var(--font-family-roboto); 15 | transition: var(--transition-all); 16 | } 17 | 18 | body { 19 | position: fixed; 20 | top: 0; 21 | left: 0; 22 | height: var(--height-body); 23 | width: var(--width-body); 24 | background: var(--background-body); 25 | } 26 | 27 | .logo { 28 | position: absolute; 29 | top: var(--top-logo); 30 | z-index: 1; 31 | width: var(--width-logo); 32 | text-align: center; 33 | letter-spacing: var(--letter-spacing-10px); 34 | font-size: var(--font-size-42pt); 35 | font-weight: var(--font-weight-regular); 36 | color: var(--color-logo); 37 | } 38 | 39 | .logo-description { 40 | position: absolute; 41 | top: var(--top-logo-description); 42 | z-index: 1; 43 | width: var(--width-logo-description); 44 | text-align: center; 45 | letter-spacing: var(--letter-spacing-2px); 46 | font-size: var(--font-size-9pt); 47 | font-weight: var(--font-weight-regular); 48 | color: var(--color-logo-description); 49 | } 50 | 51 | .clouds { 52 | height: var(--height-clouds); 53 | width: var(--width-clouds); 54 | overflow: hidden; 55 | } 56 | 57 | .clouds > img { 58 | position: relative; 59 | z-index: 1; 60 | height: var(--height-clouds-img); 61 | width: var(--width-clouds-img); 62 | } 63 | 64 | .clouds > .first { 65 | top: var(--top-clouds-first); 66 | } 67 | 68 | .clouds > .second { 69 | top: var(--top-clouds-second); 70 | left: var(--left-clouds-second); 71 | } 72 | 73 | .background { 74 | position: absolute; 75 | top: 0; 76 | height: var(--height-background); 77 | width: var(--width-background); 78 | } 79 | 80 | /* setup elements */ 81 | .dhtmlx_message_area { 82 | width: var(--width-dhtmlx-message-area); 83 | } 84 | 85 | .setup { 86 | margin-top: calc((100vh / 2) - (var(--height-setup) / 2)); 87 | max-width: var(--max-width-setup); 88 | min-width: var(--min-width-setup); 89 | } 90 | 91 | .setup-div { 92 | display: block; 93 | position: relative; 94 | margin: auto; 95 | height: var(--height-setup-div); 96 | width: var(--width-setup-div); 97 | opacity: 0; 98 | background: white; 99 | border-radius: var(--border-radius-setup-div); 100 | overflow: hidden; 101 | box-shadow: var(--box-shadow-setup-div) var(--black-opacity-10); 102 | animation: fade-in-setup-div; 103 | animation-duration: var(--animation-duration-fade-in-setup-div); 104 | animation-fill-mode: forwards; 105 | } 106 | 107 | .form { 108 | position: absolute; 109 | bottom: 0; 110 | left: 0; 111 | height: var(--height-form); 112 | width: var(--width-form); 113 | background: var(--background-form); 114 | } 115 | 116 | .form-squares-grid { 117 | position: relative; 118 | bottom: var(--bottom-form-squares-grid); 119 | left: var(--left-form-squares-grid); 120 | } 121 | 122 | .form-squares-grid > div { 123 | display: inline-block; 124 | margin-right: var(--margin-right-form-squares-grid-div); 125 | height: var(--height-form-squares-grid-div); 126 | width: var(--width-form-squares-grid-div); 127 | box-shadow: var(--box-shadow-form-squares-grid-div) var(--black-opacity-10); 128 | } 129 | 130 | .form-squares-grid > .first { 131 | background: var(--background-form-squares-grid-first); 132 | } 133 | 134 | .form-squares-grid > .second { 135 | background: var(--background-form-squares-grid-second); 136 | transform: var(--transform-form-squares-grid-second); 137 | } 138 | 139 | .form-squares-grid > .third { 140 | background: var(--background-form-squares-grid-third); 141 | } 142 | 143 | .label-main-settings { 144 | position: relative; 145 | margin-bottom: var(--margin-bottom-label-main-settings); 146 | text-align: center; 147 | letter-spacing: var(--letter-spacing-2px); 148 | font-size: var(--font-size-9pt); 149 | font-weight: var(--font-weight-regular); 150 | color: var(--color-label-main-settings); 151 | } 152 | 153 | .main-settings { 154 | position: relative; 155 | left: var(--left-main-settings); 156 | height: var(--height-main-settings); 157 | width: var(--width-main-settings); 158 | background: var(--background-main-settings); 159 | } 160 | 161 | .main-settings > input { 162 | position: relative; 163 | top: var(--top-main-settings-input); 164 | width: var(--width-main-settings-input); 165 | text-align: center; 166 | font-size: var(--font-size-14pt); 167 | font-weight: var(--font-weight-regular); 168 | color: var(--color-main-settings-input); 169 | background: var(--background-main-settings-input); 170 | border: 0; 171 | outline: none; 172 | } 173 | 174 | .main-settings > input::placeholder { 175 | color: var(--color-main-settings-input-placeholder); 176 | } 177 | 178 | .main-settings > input::-webkit-input-placeholder { 179 | color: var(--color-main-settings-input-placeholder); 180 | } 181 | 182 | .main-settings > input::-moz-placeholder { 183 | opacity: 1; 184 | } 185 | 186 | .main-settings > input::-ms-clear { 187 | display: none; 188 | } 189 | 190 | .main-settings > select { 191 | position: relative; 192 | top: var(--top-main-settings-select); 193 | height: var(--height-main-settings-select); 194 | width: var(--width-main-settings-select); 195 | font-size: var(--font-size-14pt); 196 | font-weight: var(--font-weight-regular); 197 | color: var(--color-main-settings-input); 198 | background: var(--background-main-settings-select); 199 | border: 0; 200 | outline: none; 201 | } 202 | 203 | .main-settings-underline { 204 | position: relative; 205 | top: var(--top-main-settings-underline); 206 | height: var(--height-main-settings-underline); 207 | width: var(--width-main-settings-underline); 208 | background: var(--background-main-settings-underline); 209 | box-shadow: var(--box-shadow-main-settings-underline) var(--black-opacity-10); 210 | } 211 | 212 | .label-additional-settings { 213 | position: relative; 214 | top: var(--top-label-additional-settings); 215 | text-align: center; 216 | letter-spacing: var(--letter-spacing-2px); 217 | font-size: var(--font-size-9pt); 218 | font-weight: var(--font-weight-regular); 219 | color: var(--color-label-additional-settings); 220 | } 221 | 222 | .additional-settings { 223 | position: relative; 224 | top: var(--top-additional-settings); 225 | } 226 | 227 | .button-squares-grid { 228 | position: relative; 229 | top: var(--top-button-squares-grid); 230 | } 231 | 232 | .button-squares-grid > div { 233 | display: inline-block; 234 | position: absolute; 235 | height: var(--height-button-squares-grid-div); 236 | width: var(--width-button-squares-grid-div); 237 | opacity: 0; 238 | box-shadow: var(--box-shadow-button-squares-grid-div) var(--black-opacity-10); 239 | } 240 | 241 | .button-squares-grid > .first { 242 | left: var(--left-button-squares-grid-first); 243 | background: var(--background-button-squares-grid-first); 244 | animation: fade-in-square; 245 | animation-duration: var(--animation-duration-fade-in-square); 246 | animation-fill-mode: forwards; 247 | } 248 | 249 | .button-squares-grid > .second { 250 | left: var(--left-button-squares-grid-second); 251 | visibility: hidden; 252 | background: var(--background-button-squares-grid-second); 253 | } 254 | 255 | .theme-buttons > input { 256 | position: relative; 257 | top: var(--top-theme-buttons-input); 258 | height: var(--height-theme-buttons-input); 259 | width: var(--width-theme-buttons-input); 260 | letter-spacing: var(--letter-spacing-2px); 261 | font-size: var(--font-size-14pt); 262 | font-weight: var(--font-weight-regular); 263 | color: var(--color-theme-buttons-input); 264 | border: 0; 265 | outline: none; 266 | box-shadow: var(--box-shadow-theme-buttons-input) var(--black-opacity-10); 267 | } 268 | 269 | .theme-buttons > input:active { 270 | transform: var(--transform-theme-buttons-input-active); 271 | } 272 | 273 | .theme-buttons > .first { 274 | left: var(--left-theme-buttons-first); 275 | margin-right: var(--margin-right-theme-buttons-first); 276 | background: var(--background-theme-buttons-first); 277 | } 278 | 279 | .theme-buttons > .second { 280 | background: var(--background-theme-buttons-second); 281 | } 282 | 283 | .additional-settings > label { 284 | top: var(--top-background-settings); 285 | left: var(--left-background-settings); 286 | height: var(--height-background-settings); 287 | white-space: nowrap; 288 | } 289 | 290 | .additional-settings > label > input { 291 | vertical-align: middle; 292 | position: relative; 293 | left: var(--left-background-settings); 294 | border-style: none; 295 | } 296 | 297 | .additional-settings > label > span { 298 | vertical-align: middle; 299 | position: relative; 300 | } 301 | 302 | .additional-settings > .color-selector { 303 | display: block; 304 | position: relative; 305 | margin-top: var(--height-background-settings); 306 | left: var(--left-background-settings-color-selector); 307 | width: var(--width-background-settings-input); 308 | background: var(--background-background-settings-color-selector); 309 | box-shadow: var(--box-shadow-background-settings-input) var(--black-opacity-10); 310 | } 311 | 312 | .port { 313 | position: relative; 314 | top: var(--top-port); 315 | left: var(--left-port); 316 | height: var(--height-port); 317 | width: var(--width-port); 318 | text-align: center; 319 | letter-spacing: var(--letter-spacing-5px); 320 | font-size: var(--font-size-14pt); 321 | font-weight: var(--font-weight-regular); 322 | color: var(--color-port); 323 | background: var(--background-port); 324 | border-radius: var(--border-radius-port); 325 | border: 0; 326 | outline: none; 327 | } 328 | 329 | .port::placeholder { 330 | letter-spacing: 0; 331 | color: var(--color-port-placeholder); 332 | } 333 | 334 | .port::-webkit-input-placeholder { 335 | letter-spacing: 0; 336 | color: var(--color-port-placeholder); 337 | } 338 | 339 | .port::-moz-placeholder { 340 | letter-spacing: 0; 341 | opacity: 1; 342 | } 343 | 344 | .port::-ms-clear { 345 | display: none; 346 | } 347 | 348 | .submit { 349 | position: absolute; 350 | bottom: var(--bottom-submit); 351 | left: var(--left-submit); 352 | height: var(--height-submit); 353 | width: var(--width-submit); 354 | letter-spacing: var(--letter-spacing-2px); 355 | font-size: var(--font-size-14pt); 356 | font-weight: var(--font-weight-regular); 357 | color: var(--color-submit); 358 | background: var(--background-submit); 359 | border: 0; 360 | border-radius: 0.625rem; 361 | outline: none; 362 | box-shadow: var(--box-shadow-submit) var(--black-opacity-10); 363 | } 364 | 365 | .submit:active { 366 | transform: var(--transform-submit-active); 367 | } 368 | 369 | /* index elements */ 370 | .index { 371 | margin-top: calc((100vh / 2) - (var(--height-index-xl) / 2)); 372 | max-width: var(--max-width-index-xl); 373 | min-width: var(--min-width-index-xl); 374 | } 375 | 376 | @media only screen and (max-width: 75rem) { 377 | .index { 378 | margin-top: calc((100vh / 2) - (var(--height-index-lg) / 2)); 379 | max-width: var(--max-width-index-lg); 380 | min-width: var(--min-width-index-lg); 381 | } 382 | } 383 | 384 | @media only screen and (max-width: 48rem) { 385 | .index { 386 | margin-top: calc((100vh / 2) - (var(--height-index-md) / 2)); 387 | max-width: var(--max-width-index-md); 388 | min-width: var(--min-width-index-md); 389 | } 390 | 391 | .sm-hidden { 392 | visibility: hidden; 393 | } 394 | } 395 | 396 | .col-sm-12.col-md-6.col-lg-6.col-xl-4 { 397 | max-width: var(--max-width-col-sm-12-col-md-6-col-lg-6-col-xl-4); 398 | min-width: var(--min-width-col-sm-12-col-md-6-col-lg-6-col-xl-4); 399 | } 400 | 401 | .col-lg-12.col-xl-8 { 402 | max-width: var(--max-width-col-lg-12-col-xl-8); 403 | min-width: var(--min-width-col-lg-12-col-xl-8); 404 | } 405 | 406 | .card { 407 | margin-bottom: var(--margin-bottom-card); 408 | max-height: var(--max-height-card); 409 | min-height: var(--min-height-card); 410 | opacity: 0; 411 | border: none; 412 | border-radius: var(--border-radius-card); 413 | overflow: hidden; 414 | background: var(--background-card); 415 | box-shadow: var(--box-shadow-card) var(--black-opacity-10); 416 | } 417 | 418 | .header { 419 | position: relative; 420 | display: flex; 421 | top: var(--top-header); 422 | left: var(--left-header); 423 | } 424 | 425 | .hw-logo { 426 | height: var(--height-hw-logo); 427 | width: var(--width-hw-logo); 428 | border-radius: var(--border-radius-hw-logo); 429 | } 430 | 431 | .hw-logo.first { 432 | background: var(--background-hw-logo-first); 433 | } 434 | 435 | .hw-logo.second { 436 | background: var(--background-hw-logo-second); 437 | } 438 | 439 | .hw-logo.third { 440 | background: var(--background-hw-logo-third); 441 | } 442 | 443 | .label-hw-info { 444 | position: absolute; 445 | top: var(--top-label-hw-info); 446 | left: var(--left-label-hw-info); 447 | } 448 | 449 | .hw-type { 450 | font-size: var(--font-size-18pt); 451 | font-weight: var(--font-weight-bold); 452 | color: var(--color-hw-type); 453 | } 454 | 455 | .hw-name { 456 | font-size: var(--font-size-12pt); 457 | font-weight: var(--font-weight-regular); 458 | color: var(--color-hw-name); 459 | } 460 | 461 | .usage { 462 | position: absolute; 463 | height: var(--height-usage); 464 | width: var(--width-usage); 465 | bottom: var(--bottom-usage); 466 | left: var(--left-usage); 467 | } 468 | 469 | .main-hw-info { 470 | position: absolute; 471 | right: 0; 472 | height: var(--height-main-hw-info); 473 | } 474 | 475 | .hw-usage > div { 476 | position: absolute; 477 | right: 0; 478 | bottom: var(--bottom-hw-usage-div); 479 | font-size: var(--font-size-62pt); 480 | font-weight: var(--font-weight-bold); 481 | } 482 | 483 | .usage-value { 484 | display: flex; 485 | margin-right: var(--margin-right-usage-value); 486 | } 487 | 488 | .usage-value > span { 489 | position: relative; 490 | height: var(--height-usage-value-span); 491 | width: var(--width-usage-value-span); 492 | color: var(--color-usage-value-span); 493 | animation: wiggle-usage-value; 494 | animation-duration: var(--animation-duration-wiggle-usage-value); 495 | } 496 | 497 | .usage-value > .first { 498 | animation-delay: var(--animation-delay-usage-value-first); 499 | } 500 | 501 | .usage-value > .second { 502 | animation-delay: var(--animation-delay-usage-value-second); 503 | } 504 | 505 | .usage-value > .third { 506 | animation-delay: var(--animation-delay-usage-value-third); 507 | } 508 | 509 | .usage-postfix { 510 | color: var(--color-usage-postfix); 511 | } 512 | 513 | .info-label { 514 | position: relative; 515 | top: var(--top-info-label); 516 | width: var(--width-info-label); 517 | text-align: center; 518 | font-size: var(--font-size-9pt); 519 | font-weight: var(--font-weight-regular); 520 | color: var(--color-info-label); 521 | background: transparent; 522 | } 523 | 524 | .usage-underline { 525 | position: absolute; 526 | right: 0; 527 | bottom: 0; 528 | height: var(--height-usage-underline); 529 | width: var(--width-usage-underline); 530 | } 531 | 532 | .usage-underline.first { 533 | background: var(--background-usage-underline-first); 534 | } 535 | 536 | .usage-underline.second { 537 | background: var(--background-usage-underline-second); 538 | } 539 | 540 | .usage-underline.third { 541 | background: var(--background-usage-underline-third); 542 | } 543 | 544 | .footer { 545 | position: absolute; 546 | bottom: 0; 547 | left: 0; 548 | height: var(--height-footer); 549 | width: var(--width-footer); 550 | } 551 | 552 | .footer.first { 553 | background: var(--background-footer-first); 554 | } 555 | 556 | .footer.second { 557 | background: var(--background-footer-second); 558 | } 559 | 560 | .footer.third { 561 | background: var(--background-footer-third); 562 | } 563 | 564 | .inner-dot { 565 | position: absolute; 566 | top: var(--top-inner-dot); 567 | left: var(--left-inner-dot); 568 | height: var(--height-inner-dot); 569 | width: var(--width-inner-dot); 570 | border-radius: var(--border-radius-inner-dot); 571 | } 572 | 573 | .detailed-hw-info { 574 | position: absolute; 575 | } 576 | 577 | .detailed-hw-info > div { 578 | display: inline-block; 579 | position: absolute; 580 | top: var(--top-detailed-hw-info-div); 581 | height: var(--height-detailed-hw-info-div); 582 | width: var(--width-detailed-hw-info-div); 583 | text-align: center; 584 | font-size: var(--font-size-14pt); 585 | font-weight: var(--font-weight-regular); 586 | color: var(--color-detailed-hw-info-div); 587 | } 588 | 589 | .detailed-hw-info > .first { 590 | left: var(--left-detailed-hw-info-first); 591 | } 592 | 593 | .detailed-hw-info > .second { 594 | left: var(--left-detailed-hw-info-second); 595 | } 596 | 597 | .detailed-hw-info > .third { 598 | left: var(--left-detailed-hw-info-third); 599 | } 600 | 601 | .dividers { 602 | position: absolute; 603 | } 604 | 605 | .dividers > div { 606 | display: inline-block; 607 | position: absolute; 608 | height: var(--height-dividers-div); 609 | width: var(--width-dividers-div); 610 | background: var(--background-dividers-div); 611 | } 612 | 613 | .dividers > .first { 614 | left: var(--left-dividers-first); 615 | } 616 | 617 | .dividers > .second { 618 | left: var(--left-dividers-second); 619 | } 620 | 621 | .uptime { 622 | position: absolute; 623 | bottom: 0; 624 | left: 0; 625 | height: var(--height-uptime); 626 | width: var(--width-uptime); 627 | background: var(--background-uptime); 628 | } 629 | 630 | .uptime-rectangle-grid { 631 | position: absolute; 632 | top: var(--top-uptime-rectangle-grid); 633 | left: var(--left-uptime-rectangle-grid); 634 | } 635 | 636 | .values-grid > div { 637 | display: inline-block; 638 | margin-right: var(--margin-right-values-grid-div); 639 | height: var(--height-values-grid-div); 640 | width: var(--width-values-grid-div); 641 | text-align: center; 642 | font-size: var(--font-size-42pt); 643 | font-weight: var(--font-weight-bold); 644 | color: var(--color-values-grid-div); 645 | background: var(--background-values-grid-div); 646 | border-radius: 2px 647 | } 648 | 649 | .values-grid > div:first-child { 650 | width: var(--day-width-values-grid-div); 651 | } 652 | 653 | .values-grid > div > p { 654 | position: relative; 655 | bottom: var(--bottom-values-grid-div-p); 656 | } 657 | 658 | .labels-grid > div { 659 | display: inline-block; 660 | margin-right: var(--margin-right-labels-grid-div); 661 | margin-bottom: var(--margin-bottom-labels-grid-div); 662 | height: var(--height-labels-grid-div); 663 | width: var(--width-labels-grid-div); 664 | text-align: center; 665 | font-size: var(--font-size-9pt); 666 | font-weight: var(--font-weight-regular); 667 | color: var(--color-labels-grid-div); 668 | background: var(--background-labels-grid-div); 669 | border-radius: 2px 670 | } 671 | 672 | .labels-grid > div:first-child { 673 | width: var(--day-width-labels-grid-div); 674 | } 675 | 676 | .chart-label { 677 | position: absolute; 678 | top: var(--top-chart-label); 679 | left: var(--left-chart-label); 680 | font-size: var(--font-size-18pt); 681 | font-weight: var(--font-weight-bold); 682 | color: var(--color-chart-label); 683 | } 684 | 685 | .chart-triangle-grid { 686 | position: absolute; 687 | top: var(--top-chart-triangle-grid); 688 | } 689 | 690 | .chart-triangle-grid > div { 691 | position: absolute; 692 | border-style: solid; 693 | border-width: var(--border-width-chart-triangle-grid-div); 694 | opacity: 0; 695 | animation: fade-in-triangle; 696 | animation-duration: var(--animation-duration-fade-in-triangle); 697 | animation-delay: var(--animation-delay-chart-triangle-grid-div); 698 | animation-fill-mode: forwards; 699 | } 700 | 701 | .chart-triangle-grid > .first { 702 | left: var(--left-chart-triangle-grid-first); 703 | border-color: var(--border-color-chart-triangle-grid-first) transparent; 704 | } 705 | 706 | .chart-triangle-grid > .second { 707 | left: var(--left-chart-triangle-grid-second); 708 | border-color: var(--border-color-chart-triangle-grid-second) transparent; 709 | } 710 | 711 | .chart-triangle-grid > .third { 712 | left: var(--left-chart-triangle-grid-third); 713 | border-color: var(--border-color-chart-triangle-grid-third) transparent; 714 | } 715 | 716 | .chart-rectangle-grid { 717 | position: absolute; 718 | top: var(--top-chart-rectangle-grid); 719 | } 720 | 721 | .chart-rectangle-grid > div { 722 | display: inline-block; 723 | position: absolute; 724 | height: var(--height-chart-rectangle-grid-div); 725 | width: var(--width-chart-rectangle-grid-div); 726 | cursor: pointer; 727 | } 728 | 729 | .chart-rectangle-grid > div:active { 730 | transform: var(--transform-chart-rectangle-grid-div-active); 731 | } 732 | 733 | .chart-rectangle-grid > .first { 734 | left: var(--left-chart-rectangle-grid-first); 735 | background: var(--background-chart-rectangle-grid-first); 736 | } 737 | 738 | .chart-rectangle-grid > .second { 739 | left: var(--left-chart-rectangle-grid-second); 740 | background: var(--background-chart-rectangle-grid-second); 741 | } 742 | 743 | .chart-rectangle-grid > .third { 744 | left: var(--left-chart-rectangle-grid-third); 745 | background: var(--background-chart-rectangle-grid-third); 746 | } 747 | 748 | .chart-container { 749 | position: absolute; 750 | top: var(--top-chart-container); 751 | left: var(--left-chart-container); 752 | height: var(--height-chart-container); 753 | width: var(--width-chart-container); 754 | overflow: hidden; 755 | border: var(--border-chart-container) solid var(--grey-light); 756 | } 757 | 758 | #project-version { 759 | position: relative; 760 | bottom: var(--bottom-project-version); 761 | opacity: 0; 762 | font-size: var(--font-size-12pt); 763 | font-weight: var(--font-weight-regular); 764 | color: var(--color-project-version); 765 | } 766 | 767 | /* error classes */ 768 | .error { 769 | margin-top: calc((100vh / 2) - (var(--height-error) / 2)); 770 | max-width: var(--min-width-error); 771 | min-width: var(--min-width-error); 772 | } 773 | 774 | .error-img { 775 | display: block; 776 | position: relative; 777 | z-index: 1; 778 | margin: auto; 779 | height: var(--height-error-img); 780 | width: var(--width-error-img); 781 | object-fit: cover; 782 | border-radius: var(--border-radius-error-img); 783 | box-shadow: var(--box-shadow-error-img) var(--black-opacity-10); 784 | } 785 | 786 | .error-div { 787 | position: relative; 788 | left: var(--left-error-div); 789 | z-index: 1; 790 | height: var(--height-error-div); 791 | width: var(--width-error-div); 792 | opacity: 0; 793 | border-radius: var(--border-radius-error-div); 794 | background: var(--background-error-div); 795 | box-shadow: var(--box-shadow-error-div) var(--black-opacity-10); 796 | animation: fade-in-error-div; 797 | animation-duration: var(--animation-duration-fade-in-error-div); 798 | animation-fill-mode: forwards; 799 | } 800 | 801 | .error-div > div { 802 | position: absolute; 803 | } 804 | 805 | .code { 806 | top: var(--top-code); 807 | left: var(--left-code); 808 | font-size: var(--font-size-21pt); 809 | font-weight: var(--font-weight-bold); 810 | color: var(--color-code); 811 | } 812 | 813 | .title { 814 | top: var(--top-title); 815 | left: var(--left-title); 816 | font-size: var(--font-size-31pt); 817 | font-weight: var(--font-weight-bold); 818 | color: var(--color-title); 819 | } 820 | 821 | .explanation { 822 | top: var(--top-explanation); 823 | left: var(--left-explanation); 824 | } 825 | 826 | .explanation > div { 827 | font-size: var(--font-size-13pt); 828 | font-weight: var(--font-weight-regular); 829 | color: var(--color-explanation-div); 830 | } 831 | 832 | .advice { 833 | width: var(--width-advice); 834 | bottom: var(--bottom-advice); 835 | text-align: center; 836 | font-size: var(--font-size-11pt); 837 | font-weight: var(--font-weight-regular); 838 | color: var(--color-advice); 839 | } 840 | 841 | .hardware-icon { 842 | width: var(--width-hardware-icon); 843 | height: var(--height-hardware-icon); 844 | margin: var(--margin-hardware-icon); 845 | } -------------------------------------------------------------------------------- /src/main/resources/static/css/shadows.css: -------------------------------------------------------------------------------- 1 | /* 2 | Shadows file 3 | Used for define shadows of project 4 | 5 | Every category must follow convention: 6 | * Category must contain only shadow type name 7 | 8 | Every entry must follow convention: 9 | * Must begins with category name 10 | * Further should be followed by tag/class/id/etc. 11 | 12 | By example: --box-shadow-card 13 | */ 14 | 15 | :root 16 | { 17 | /* box-shadow */ 18 | --box-shadow-setup-div: 0.000rem 0.313rem 0.625rem 0.000rem; 19 | --box-shadow-form-squares-grid-div: 0.000rem 0.188rem 0.313rem 0.000rem; 20 | --box-shadow-main-settings-underline: 0.000rem 0.188rem 0.313rem 0.000rem; 21 | --box-shadow-button-squares-grid-div: 0.000rem 0.188rem 0.313rem 0.000rem; 22 | --box-shadow-theme-buttons-input: 0.000rem 0.188rem 0.313rem 0.000rem; 23 | --box-shadow-background-settings-input: 0.000rem 0.188rem 0.313rem 0.000rem; 24 | --box-shadow-submit: 0.000rem 0.188rem 0.313rem 0.000rem; 25 | --box-shadow-card: 0.000rem 0.313rem 0.625rem 0.000rem; 26 | --box-shadow-uptime-squares-grid-div: 0.000rem 0.188rem 0.313rem 0.000rem; 27 | --box-shadow-error-img: 0.000rem 0.188rem 0.313rem 0.000rem; 28 | --box-shadow-error-div: 0.000rem 0.313rem 0.625rem 0.000rem; 29 | } -------------------------------------------------------------------------------- /src/main/resources/static/css/themes.css: -------------------------------------------------------------------------------- 1 | /* 2 | Themes file 3 | Used for define themes of project 4 | 5 | Every category must follow convention: 6 | * Category must contain only theme name 7 | 8 | Every subcategory must follow convention: 9 | * Subcategory must contain only css property name 10 | 11 | Every entry must follow convention: 12 | * Must begins with subcategory name 13 | * Further should be followed by tag/class/id/etc. 14 | 15 | By example: --color-body 16 | */ 17 | 18 | /* light */ 19 | html[theme = "light"] 20 | { 21 | /* color */ 22 | --color-logo: var(--white); 23 | --color-logo-description: var(--white); 24 | --color-label-main-settings: var(--grey); 25 | --color-main-settings-input: var(--grey); 26 | --color-main-settings-input-placeholder: var(--grey); 27 | --color-label-additional-settings: var(--grey); 28 | --color-theme-buttons-input: var(--grey); 29 | --color-port: var(--grey); 30 | --color-port-placeholder: var(--grey-light); 31 | --color-submit: var(--white); 32 | --color-hw-type: var(--black); 33 | --color-hw-name: var(--grey); 34 | --color-usage-value-span: var(--grey-light); 35 | --color-usage-postfix: var(--black); 36 | --color-info-label: var(--grey-light); 37 | --color-detailed-hw-info-div: var(--white); 38 | --color-announcement: var(--white); 39 | --color-uptime-dashboard-logo: var(--grey-light); 40 | --color-uptime-dashboard-logo-description: var(--grey-light); 41 | --color-values-grid-div: var(--grey); 42 | --color-labels-grid-div: var(--grey-light); 43 | --color-chart-label: var(--black); 44 | --color-project-version: var(--grey); 45 | --color-code: var(--black); 46 | --color-title: var(--black); 47 | --color-explanation-div: var(--grey); 48 | --color-advice: var(--grey-light); 49 | 50 | /* background */ 51 | --background-body: var(--purple-light); 52 | --background-form: var(--linear-gradient-form-light); 53 | --background-form-squares-grid-first: var(--blue-light); 54 | --background-form-squares-grid-second: var(--red-light); 55 | --background-form-squares-grid-third: var(--green-light); 56 | --background-main-settings: var(--white); 57 | --background-main-settings-input: var(--white); 58 | --background-main-settings-select: var(--white); 59 | --background-main-settings-underline: var(--blue-light); 60 | --background-button-squares-grid-first: var(--purple-light); 61 | --background-button-squares-grid-second: var(--grey-light); 62 | --background-theme-buttons-first: var(--purple-light); 63 | --background-theme-buttons-second: var(--grey-light); 64 | --background-background-settings-color-selector: var(--grey-light); 65 | --background-port: var(--white); 66 | --background-submit: var(--green-light); 67 | --background-card: var(--white); 68 | --background-hw-logo-first: var(--blue-light); 69 | --background-hw-logo-second: var(--red-light); 70 | --background-hw-logo-third: var(--green-light); 71 | --background-usage-underline-first: var(--blue-light); 72 | --background-usage-underline-second: var(--red-light); 73 | --background-usage-underline-third: var(--green-light); 74 | --background-footer-first: var(--blue-light); 75 | --background-footer-second: var(--red-light); 76 | --background-footer-third: var(--green-light); 77 | --background-dividers-div: var(--white); 78 | --background-uptime: var(--linear-gradient-uptime-light); 79 | --background-values-grid-div: var(--white-opacity-70); 80 | --background-labels-grid-div: var(--white-opacity-90); 81 | --background-chart-rectangle-grid-first: var(--blue-light); 82 | --background-chart-rectangle-grid-second: var(--red-light); 83 | --background-chart-rectangle-grid-third: var(--green-light); 84 | --background-error-div: var(--white); 85 | 86 | /* border-color */ 87 | --border-color-chart-triangle-grid-first: var(--blue); 88 | --border-color-chart-triangle-grid-second: var(--red); 89 | --border-color-chart-triangle-grid-third: var(--green); 90 | } 91 | 92 | /* dark */ 93 | html[theme = "dark"] 94 | { 95 | /* color */ 96 | --color-logo: var(--white); 97 | --color-logo-description: var(--white); 98 | --color-label-main-settings: var(--white); 99 | --color-main-settings-input: var(--white); 100 | --color-main-settings-input-placeholder: var(--grey-light); 101 | --color-label-additional-settings: var(--white); 102 | --color-theme-buttons-input: var(--grey); 103 | --color-port: var(--white); 104 | --color-port-placeholder: var(--grey-light); 105 | --color-submit: var(--white); 106 | --color-hw-type: var(--white); 107 | --color-hw-name: var(--white); 108 | --color-usage-value-span: var(--white); 109 | --color-usage-postfix: var(--white); 110 | --color-info-label: var(--white); 111 | --color-detailed-hw-info-div: var(--white); 112 | --color-announcement: var(--white); 113 | --color-uptime-dashboard-logo: var(--grey-light); 114 | --color-uptime-dashboard-logo-description: var(--white); 115 | --color-values-grid-div: var(--white); 116 | --color-labels-grid-div: var(--white); 117 | --color-chart-label: var(--white); 118 | --color-project-version: var(--white); 119 | --color-code: var(--white); 120 | --color-title: var(--white); 121 | --color-explanation-div: var(--grey); 122 | --color-advice: var(--grey-light); 123 | 124 | /* background */ 125 | --background-body: var(--grey-light); 126 | --background-form: var(--linear-gradient-form-dark); 127 | --background-form-squares-grid-first: var(--grey-light); 128 | --background-form-squares-grid-second: var(--grey-light); 129 | --background-form-squares-grid-third: var(--grey-light); 130 | --background-main-settings: var(--grey); 131 | --background-main-settings-input: var(--grey); 132 | --background-main-settings-select: var(--grey); 133 | --background-main-settings-underline: var(--grey-light); 134 | --background-button-squares-grid-first: var(--purple-light); 135 | --background-button-squares-grid-second: var(--grey-light); 136 | --background-theme-buttons-first: var(--purple-light); 137 | --background-theme-buttons-second: var(--grey-light); 138 | --background-background-settings-color-selector: var(--grey-light); 139 | --background-port: var(--grey); 140 | --background-submit: var(--grey-light); 141 | --background-card: var(--grey-dark); 142 | --background-hw-logo-first: var(--blue-light); 143 | --background-hw-logo-second: var(--red-light); 144 | --background-hw-logo-third: var(--green-light); 145 | --background-usage-underline-first: var(--blue-light); 146 | --background-usage-underline-second: var(--red-light); 147 | --background-usage-underline-third: var(--green-light); 148 | --background-footer-first: var(--blue); 149 | --background-footer-second: var(--red); 150 | --background-footer-third: var(--green); 151 | --background-dividers-div: var(--grey-dark); 152 | --background-uptime: var(--grey-dark); 153 | --background-values-grid-div: var(--grey-opacity-70); 154 | --background-labels-grid-div: var(--grey-opacity-90); 155 | --background-chart-rectangle-grid-first: var(--blue-light); 156 | --background-chart-rectangle-grid-second: var(--red-light); 157 | --background-chart-rectangle-grid-third: var(--green-light); 158 | --background-error-div: var(--grey-dark); 159 | 160 | /* border-color */ 161 | --border-color-chart-triangle-grid-first: var(--blue); 162 | --border-color-chart-triangle-grid-second: var(--red); 163 | --border-color-chart-triangle-grid-third: var(--green); 164 | } -------------------------------------------------------------------------------- /src/main/resources/static/fonts/roboto/bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Akttoer/Ward_CN/90b8902e1e244497399341890d7065a6d2b11e03/src/main/resources/static/fonts/roboto/bold.woff2 -------------------------------------------------------------------------------- /src/main/resources/static/fonts/roboto/regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Akttoer/Ward_CN/90b8902e1e244497399341890d7065a6d2b11e03/src/main/resources/static/fonts/roboto/regular.woff2 -------------------------------------------------------------------------------- /src/main/resources/static/img/error/404.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Akttoer/Ward_CN/90b8902e1e244497399341890d7065a6d2b11e03/src/main/resources/static/img/error/404.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/error/500.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Akttoer/Ward_CN/90b8902e1e244497399341890d7065a6d2b11e03/src/main/resources/static/img/error/500.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/ico/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Akttoer/Ward_CN/90b8902e1e244497399341890d7065a6d2b11e03/src/main/resources/static/img/ico/favicon.ico -------------------------------------------------------------------------------- /src/main/resources/static/img/icons/disk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Akttoer/Ward_CN/90b8902e1e244497399341890d7065a6d2b11e03/src/main/resources/static/img/icons/disk.png -------------------------------------------------------------------------------- /src/main/resources/static/img/icons/memory.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Akttoer/Ward_CN/90b8902e1e244497399341890d7065a6d2b11e03/src/main/resources/static/img/icons/memory.png -------------------------------------------------------------------------------- /src/main/resources/static/img/icons/processor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Akttoer/Ward_CN/90b8902e1e244497399341890d7065a6d2b11e03/src/main/resources/static/img/icons/processor.png -------------------------------------------------------------------------------- /src/main/resources/static/img/logo/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Akttoer/Ward_CN/90b8902e1e244497399341890d7065a6d2b11e03/src/main/resources/static/img/logo/background.png -------------------------------------------------------------------------------- /src/main/resources/static/img/logo/clouds/left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Akttoer/Ward_CN/90b8902e1e244497399341890d7065a6d2b11e03/src/main/resources/static/img/logo/clouds/left.png -------------------------------------------------------------------------------- /src/main/resources/static/img/logo/clouds/right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Akttoer/Ward_CN/90b8902e1e244497399341890d7065a6d2b11e03/src/main/resources/static/img/logo/clouds/right.png -------------------------------------------------------------------------------- /src/main/resources/static/js/assets/dhtmlx.min.js: -------------------------------------------------------------------------------- 1 | window.dhtmlx||(window.dhtmlx={}),function(){var e=null;function t(t,n){var i=t.callback;o(!1),t.box.parentNode.removeChild(t.box),e=t.box=null,i&&i(n)}function n(n){if(e){var o=(n=n||event).which||event.keyCode;return dhtmlx.message.keyboard&&(13!=o&&32!=o||t(e,!0),27==o&&t(e,!1)),n.preventDefault&&n.preventDefault(),!(n.cancelBubble=!0)}}function o(e){o.cover||(o.cover=document.createElement("DIV"),o.cover.onkeydown=n,o.cover.className="dhx_modal_cover",document.body.appendChild(o.cover));document.body.scrollHeight;o.cover.style.display=e?"inline-block":"none"}function i(e,t){return"
"+e+"
"}function d(d,r,l){var a=d.tagName?d:function(n,o,d){var r=document.createElement("DIV");r.className=" dhtmlx_modal_box dhtmlx-"+n.type,r.setAttribute("dhxbox",1);var l="";if(n.width&&(r.style.width=n.width),n.height&&(r.style.height=n.height),n.title&&(l+='
'+n.title+"
"),l+='
'+(n.content?"":n.text)+'
',o&&(l+=i(n.ok||"OK",!0)),d&&(l+=i(n.cancel||"Cancel",!1)),n.buttons)for(var a=0;a",r.innerHTML=l,n.content){var c=n.content;"string"==typeof c&&(c=document.getElementById(c)),"none"==c.style.display&&(c.style.display=""),r.childNodes[n.title?1:0].appendChild(c)}return r.onclick=function(e){var o=(e=e||event).target||e.srcElement;if(o.className||(o=o.parentNode),"dhtmlx_popup_button"==o.className){var i=o.getAttribute("result");t(n,i="true"==i||"false"!=i&&i)}},n.box=r,(o||d)&&(e=n),r}(d,r,l);d.hidden||o(!0),document.body.appendChild(a);var c=d.left||Math.abs(Math.floor(((window.innerWidth||document.documentElement.offsetWidth)-a.offsetWidth)/2)),u=d.top||Math.abs(Math.floor(((window.innerHeight||document.documentElement.offsetHeight)-a.offsetHeight)/2));return"top"==d.position?a.style.top="-3px":a.style.top=u+"px",a.style.left=c+"px",a.onkeydown=n,a.focus(),d.hidden&&dhtmlx.modalbox.hide(a),a}function r(e){return d(e,!0,!1)}function l(e){return d(e,!0,!0)}function a(e){return d(e)}function c(e,t,n){return"object"!=typeof e&&("function"==typeof t&&(n=t,t=""),e={text:e,type:t,callback:n}),e}document.attachEvent?document.attachEvent("onkeydown",n):document.addEventListener("keydown",n,!0),dhtmlx.alert=function(){var e=c.apply(this,arguments);return e.type=e.type||"confirm",r(e)},dhtmlx.confirm=function(){var e=c.apply(this,arguments);return e.type=e.type||"alert",l(e)},dhtmlx.modalbox=function(){var e=c.apply(this,arguments);return e.type=e.type||"alert",a(e)},dhtmlx.modalbox.hide=function(e){for(;e&&e.getAttribute&&!e.getAttribute("dhxbox");)e=e.parentNode;e&&(e.parentNode.removeChild(e),o(!1))};var u=dhtmlx.message=function(e,t,n,o){switch((e=function(e,t,n,o){return"object"!=typeof e&&(e={text:e,type:t,expire:n,id:o}),e.id=e.id||u.uid(),e.expire=e.expire||u.expire,e}.apply(this,arguments)).type=e.type||"info",e.type.split("-")[0]){case"alert":return r(e);case"confirm":return l(e);case"modalbox":return a(e);default:return function(e){u.area||(u.area=document.createElement("DIV"),u.area.className="dhtmlx_message_area",u.area.style[u.position]="5px",document.body.appendChild(u.area)),u.hide(e.id);var t=document.createElement("DIV");return t.innerHTML="
"+e.text+"
",t.className="dhtmlx-info dhtmlx-"+e.type,t.onclick=function(){u.hide(e.id),e=null},"bottom"==u.position&&u.area.firstChild?u.area.insertBefore(t,u.area.firstChild):u.area.appendChild(t),e.expire>0&&(u.timers[e.id]=window.setTimeout(function(){u.hide(e.id)},e.expire)),u.pull[e.id]=t,t=null,e.id}(e)}};u.seed=(new Date).valueOf(),u.uid=function(){return u.seed++},u.expire=4e3,u.keyboard=!0,u.position="top",u.pull={},u.timers={},u.hideAll=function(){for(var e in u.pull)u.hide(e)},u.hide=function(e){var t=u.pull[e];t&&t.parentNode&&(window.setTimeout(function(){t.parentNode.removeChild(t),t=null},2e3),t.className+=" hidden",u.timers[e]&&window.clearTimeout(u.timers[e]),delete u.pull[e])}}(); -------------------------------------------------------------------------------- /src/main/resources/static/js/assets/vanta.min.js: -------------------------------------------------------------------------------- 1 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports._vantaEffect=t():e._vantaEffect=t()}("undefined"!=typeof self?self:this,(function(){return function(e){var t={};function i(o){if(t[o])return t[o].exports;var n=t[o]={i:o,l:!1,exports:{}};return e[o].call(n.exports,n,n.exports,i),n.l=!0,n.exports}return i.m=e,i.c=t,i.d=function(e,t,o){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:o})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(i.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)i.d(o,n,function(t){return e[t]}.bind(null,n));return o},i.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="",i(i.s=9)}([function(e,t,i){"use strict";function o(e,t){for(let i in t)t.hasOwnProperty(i)&&(e[i]=t[i]);return e}function n(){return"undefined"!=typeof navigator?/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)||window.innerWidth<600:null}i.d(t,"c",(function(){return o})),i.d(t,"e",(function(){return n})),i.d(t,"i",(function(){return s})),i.d(t,"h",(function(){return r})),i.d(t,"g",(function(){return h})),i.d(t,"f",(function(){return a})),i.d(t,"a",(function(){return u})),i.d(t,"b",(function(){return l})),i.d(t,"d",(function(){return c})),Number.prototype.clamp=function(e,t){return Math.min(Math.max(this,e),t)};const s=e=>e[Math.floor(Math.random()*e.length)];function r(e,t){return null==e&&(e=0),null==t&&(t=1),e+Math.random()*(t-e)}function h(e,t){return null==e&&(e=0),null==t&&(t=1),Math.floor(e+Math.random()*(t-e+1))}const a=e=>document.querySelector(e),u=e=>"number"==typeof e?"#"+("00000"+e.toString(16)).slice(-6):e,l=(e,t=1)=>{const i=u(e),o=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(i),n=o?{r:parseInt(o[1],16),g:parseInt(o[2],16),b:parseInt(o[3],16)}:null;return"rgba("+n.r+","+n.g+","+n.b+","+t+")"},c=e=>.299*e.r+.587*e.g+.114*e.b},function(e,t,i){"use strict";i.d(t,"a",(function(){return r}));var o=i(0);const n="object"==typeof window;let s=n&&window.THREE||{};n&&!window.VANTA&&(window.VANTA={});const r=n&&window.VANTA||{};r.register=(e,t)=>r[e]=e=>new t(e),r.version="0.5.15";const h=function(){return Array.prototype.unshift.call(arguments,"[VANTA]"),console.error.apply(this,arguments)};r.VantaBase=class{constructor(e={}){if(!n)return!1;r.current=this,this.windowMouseMoveWrapper=this.windowMouseMoveWrapper.bind(this),this.windowTouchWrapper=this.windowTouchWrapper.bind(this),this.resize=this.resize.bind(this),this.animationLoop=this.animationLoop.bind(this),this.restart=this.restart.bind(this);const t="function"==typeof this.getDefaultOptions?this.getDefaultOptions():this.defaultOptions;if(this.options=Object(o.c)({mouseControls:!0,touchControls:!0,minHeight:200,minWidth:200,scale:1,scaleMobile:1},t),(e instanceof HTMLElement||"string"==typeof e)&&(e={el:e}),Object(o.c)(this.options,e),this.options.THREE&&(s=this.options.THREE),this.el=this.options.el,null==this.el)h('Instance needs "el" param!');else if(!(this.options.el instanceof HTMLElement)){const e=this.el;if(this.el=Object(o.f)(e),!this.el)return void h("Cannot find element",e)}this.prepareEl(),this.initThree(),this.setSize();try{this.init()}catch(e){return h("Init error",e),this.renderer&&this.renderer.domElement&&this.el.removeChild(this.renderer.domElement),void(this.options.backgroundColor&&(console.log("[VANTA] Falling back to backgroundColor"),this.el.style.background=Object(o.a)(this.options.backgroundColor)))}this.initMouse(),this.resize(),this.animationLoop();const i=window.addEventListener;i("resize",this.resize),window.requestAnimationFrame(this.resize),this.options.mouseControls&&(i("scroll",this.windowMouseMoveWrapper),i("mousemove",this.windowMouseMoveWrapper)),this.options.touchControls&&(i("touchstart",this.windowTouchWrapper),i("touchmove",this.windowTouchWrapper))}setOptions(e={}){Object(o.c)(this.options,e)}prepareEl(){let e,t;if("undefined"!=typeof Node&&Node.TEXT_NODE)for(e=0;e=0&&n>=0&&o<=i.width&&n<=i.height&&(this.mouseX=o,this.mouseY=n,this.options.mouseEase||this.triggerMouseMove(o,n))}windowTouchWrapper(e){if(1===e.touches.length){const t=this.getCanvasElement();if(!t)return!1;const i=t.getBoundingClientRect(),o=e.touches[0].clientX-i.left,n=e.touches[0].clientY-i.top;o>=0&&n>=0&&o<=i.width&&n<=i.height&&(this.mouseX=o,this.mouseY=n,this.options.mouseEase||this.triggerMouseMove(o,n))}}triggerMouseMove(e,t){this.uniforms&&(this.uniforms.iMouse.value.x=e/this.scale,this.uniforms.iMouse.value.y=t/this.scale);const i=e/this.width,o=t/this.height;"function"==typeof this.onMouseMove&&this.onMouseMove(i,o)}setSize(){this.scale||(this.scale=1),Object(o.e)()&&this.options.scaleMobile?this.scale=this.options.scaleMobile:this.options.scale&&(this.scale=this.options.scale),this.width=Math.max(this.el.offsetWidth,this.options.minWidth),this.height=Math.max(this.el.offsetHeight,this.options.minHeight)}initMouse(){(!this.mouseX&&!this.mouseY||this.mouseX===this.options.minWidth/2&&this.mouseY===this.options.minHeight/2)&&(this.mouseX=this.width/2,this.mouseY=this.height/2,this.triggerMouseMove(this.mouseX,this.mouseY))}resize(){this.setSize(),this.camera&&(this.camera.aspect=this.width/this.height,"function"==typeof this.camera.updateProjectionMatrix&&this.camera.updateProjectionMatrix()),this.renderer&&(this.renderer.setSize(this.width,this.height),this.renderer.setPixelRatio(window.devicePixelRatio/this.scale)),"function"==typeof this.onResize&&this.onResize()}isOnScreen(){const e=this.el.offsetHeight,t=this.el.getBoundingClientRect(),i=window.pageYOffset||(document.documentElement||document.body.parentNode||document.body).scrollTop,o=t.top+i;return o-window.innerHeight<=i&&i<=o+e}animationLoop(){return this.t||(this.t=0),this.t+=1,this.t2||(this.t2=0),this.t2+=this.options.speed||1,this.uniforms&&(this.uniforms.iTime.value=.016667*this.t2),this.options.mouseEase&&(this.mouseEaseX=this.mouseEaseX||this.mouseX||0,this.mouseEaseY=this.mouseEaseY||this.mouseY||0,Math.abs(this.mouseEaseX-this.mouseX)+Math.abs(this.mouseEaseY-this.mouseY)>.1&&(this.mouseEaseX+=.05*(this.mouseX-this.mouseEaseX),this.mouseEaseY+=.05*(this.mouseY-this.mouseEaseY),this.triggerMouseMove(this.mouseEaseX,this.mouseEaseY))),(this.isOnScreen()||this.options.forceAnimate)&&("function"==typeof this.onUpdate&&this.onUpdate(),this.scene&&this.camera&&(this.renderer.render(this.scene,this.camera),this.renderer.setClearColor(this.options.backgroundColor,this.options.backgroundAlpha)),this.fps&&this.fps.update&&this.fps.update(),"function"==typeof this.afterRender&&this.afterRender()),this.req=window.requestAnimationFrame(this.animationLoop)}restart(){if(this.scene)for(;this.scene.children.length;)this.scene.remove(this.scene.children[0]);"function"==typeof this.onRestart&&this.onRestart(),this.init()}init(){"function"==typeof this.onInit&&this.onInit()}destroy(){"function"==typeof this.onDestroy&&this.onDestroy();const e=window.removeEventListener;e("touchstart",this.windowTouchWrapper),e("touchmove",this.windowTouchWrapper),e("scroll",this.windowMouseMoveWrapper),e("mousemove",this.windowMouseMoveWrapper),e("resize",this.resize),window.cancelAnimationFrame(this.req),this.renderer&&(this.renderer.domElement&&this.el.removeChild(this.renderer.domElement),this.renderer=null,this.scene=null)}},t.b=r.VantaBase},function(e,t,i){"use strict";i.d(t,"b",(function(){return r}));var o=i(1),n=i(0);i.d(t,"a",(function(){return o.a}));let s="object"==typeof window&&window.THREE;class r extends o.b{constructor(e){(s=e.THREE||s).Color.prototype.toVector=function(){return new s.Vector3(this.r,this.g,this.b)},super(e),this.updateUniforms=this.updateUniforms.bind(this)}init(){this.mode="shader",this.uniforms={iTime:{type:"f",value:1},iResolution:{type:"v2",value:new s.Vector2(1,1)},iDpr:{type:"f",value:window.devicePixelRatio||1},iMouse:{type:"v2",value:new s.Vector2(this.mouseX||0,this.mouseY||0)}},super.init(),this.fragmentShader&&this.initBasicShader()}setOptions(e){super.setOptions(e),this.updateUniforms()}initBasicShader(e=this.fragmentShader,t=this.vertexShader){t||(t="uniform float uTime;\nuniform vec2 uResolution;\nvoid main() {\n gl_Position = vec4( position, 1.0 );\n}"),this.updateUniforms(),"function"==typeof this.valuesChanger&&this.valuesChanger();const i=new s.ShaderMaterial({uniforms:this.uniforms,vertexShader:t,fragmentShader:e}),o=this.options.texturePath;o&&(this.uniforms.iTex={type:"t",value:(new s.TextureLoader).load(o)});const n=new s.Mesh(new s.PlaneGeometry(2,2),i);this.scene.add(n),this.camera=new s.Camera,this.camera.position.z=1}updateUniforms(){const e={};let t,i;for(t in this.options)i=this.options[t],-1!==t.toLowerCase().indexOf("color")?e[t]={type:"v3",value:new s.Color(i).toVector()}:"number"==typeof i&&(e[t]={type:"f",value:i});return Object(n.c)(this.uniforms,e)}resize(){super.resize(),this.uniforms.iResolution.value.x=this.width/this.scale,this.uniforms.iResolution.value.y=this.height/this.scale}}},,,,,,,function(e,t,i){"use strict";i.r(t);var o=i(2);class n extends o.b{}t.default=o.a.register("FOG",n),n.prototype.defaultOptions={highlightColor:16761600,midtoneColor:16719616,lowlightColor:2949375,baseColor:16772075,blurFactor:.6,speed:1,zoom:1,scale:2,scaleMobile:4},n.prototype.fragmentShader="uniform vec2 iResolution;\nuniform vec2 iMouse;\nuniform float iTime;\n\nuniform float blurFactor;\nuniform vec3 baseColor;\nuniform vec3 lowlightColor;\nuniform vec3 midtoneColor;\nuniform vec3 highlightColor;\nuniform float zoom;\n\nfloat random (in vec2 _st) {\n return fract(sin(dot(_st.xy,\n vec2(12.9898,78.233)))*\n 43758.5453123);\n}\n\n// Based on Morgan McGuire @morgan3d\n// https://www.shadertoy.com/view/4dS3Wd\nfloat noise (in vec2 _st) {\n vec2 i = floor(_st);\n vec2 f = fract(_st);\n\n // Four corners in 2D of a tile\n float a = random(i);\n float b = random(i + vec2(1.0, 0.0));\n float c = random(i + vec2(0.0, 1.0));\n float d = random(i + vec2(1.0, 1.0));\n\n vec2 u = f * f * (3.0 - 2.0 * f);\n\n return mix(a, b, u.x) +\n (c - a)* u.y * (1.0 - u.x) +\n (d - b) * u.x * u.y;\n}\n\n#define NUM_OCTAVES 6\n\nfloat fbm ( in vec2 _st) {\n float v = 0.0;\n float a = blurFactor;\n vec2 shift = vec2(100.0);\n // Rotate to reduce axial bias\n mat2 rot = mat2(cos(0.5), sin(0.5),\n -sin(0.5), cos(0.50));\n for (int i = 0; i < NUM_OCTAVES; ++i) {\n v += a * noise(_st);\n _st = rot * _st * 2.0 + shift;\n a *= (1. - blurFactor);\n }\n return v;\n}\n\nvoid main() {\n vec2 st = gl_FragCoord.xy / iResolution.xy*3.;\n st.x *= 0.7 * iResolution.x / iResolution.y ; // Still keep it more landscape than square\n st *= zoom;\n\n // st += st * abs(sin(iTime*0.1)*3.0);\n vec3 color = vec3(0.0);\n\n vec2 q = vec2(0.);\n q.x = fbm( st + 0.00*iTime);\n q.y = fbm( st + vec2(1.0));\n\n vec2 dir = vec2(0.15,0.126);\n vec2 r = vec2(0.);\n r.x = fbm( st + 1.0*q + vec2(1.7,9.2)+ dir.x*iTime );\n r.y = fbm( st + 1.0*q + vec2(8.3,2.8)+ dir.y*iTime);\n\n float f = fbm(st+r);\n\n color = mix(baseColor,\n lowlightColor,\n clamp((f*f)*4.0,0.0,1.0));\n\n color = mix(color,\n midtoneColor,\n clamp(length(q),0.0,1.0));\n\n color = mix(color,\n highlightColor,\n clamp(length(r.x),0.0,1.0));\n\n vec3 finalColor = mix(baseColor, color, f*f*f+.6*f*f+.5*f);\n gl_FragColor = vec4(finalColor,1.0);\n}\n"}])})); -------------------------------------------------------------------------------- /src/main/resources/static/js/background.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | /** 4 | * Initializes dynamic background 5 | */ 6 | function backgroundInitialization() 7 | { 8 | if (html.getAttribute("enableFog") == "true") 9 | { 10 | background = VANTA.FOG({el: "#background", blurFactor: 0.40, zoom: 1.50}); 11 | if (html.getAttribute("theme") == "light") 12 | { 13 | background.setOptions 14 | ({ 15 | highlightColor: 0xCAC7E8, 16 | midtoneColor: 0xBBB7ED, 17 | lowlightColor: 0xE4E3EF, 18 | baseColor: 0xE4E3EF 19 | }); 20 | } 21 | else 22 | { 23 | background.setOptions 24 | ({ 25 | highlightColor: 0x797979, 26 | midtoneColor: 0xFFFFFF, 27 | lowlightColor: 0xBCBCBC, 28 | baseColor: 0xBCBCBC 29 | }); 30 | } 31 | } 32 | else 33 | { 34 | if (background){ 35 | background.destroy(); 36 | } 37 | if (html.getAttribute("backgroundColor") == "default" ) 38 | { 39 | document.body.style.backgroundColor = html.getAttribute("theme") == "light" ? "#e5e5e5" : "#292929" 40 | } 41 | else 42 | { 43 | document.body.style.backgroundColor = html.getAttribute("backgroundColor") 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /src/main/resources/static/js/chart.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | /** 4 | * Initializes labels and datasets 5 | */ 6 | function chartInitialization() 7 | { 8 | let processorRectangle = document.getElementById("processor-rectangle"); 9 | let ramRectangle = document.getElementById("ram-rectangle"); 10 | let storageRectangle = document.getElementById("storage-rectangle"); 11 | 12 | let ctx = document.getElementById("chart-body").getContext("2d"); 13 | 14 | processorTriangle = document.getElementById("processor-triangle"); 15 | ramTriangle = document.getElementById("ram-triangle"); 16 | storageTriangle = document.getElementById("storage-triangle"); 17 | 18 | let dataLight = 19 | { 20 | data: 21 | { 22 | labels: ["", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""], 23 | datasets: 24 | [ 25 | { 26 | borderWidth: 1.5, 27 | borderColor: "rgba(89, 101, 249, 1)", 28 | pointRadius: 2, 29 | pointHoverRadius: 3, 30 | pointBackgroundColor: "rgba(255, 255, 255, 1)", 31 | pointHoverBackgroundColor: "rgba(230, 232, 254, 1)", 32 | backgroundColor: "rgba(230, 232, 254, 0.3)", 33 | data: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 34 | }, 35 | { 36 | borderWidth: 1.5, 37 | borderColor: "rgba(255, 89, 89, 1)", 38 | pointRadius: 2, 39 | pointHoverRadius: 3, 40 | pointBackgroundColor: "rgba(255, 255, 255, 1)", 41 | pointHoverBackgroundColor: "rgba(249, 226, 226, 1)", 42 | backgroundColor: "rgba(249, 226, 226, 0.3)", 43 | data: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 44 | }, 45 | { 46 | borderWidth: 1.5, 47 | borderColor: "rgba(8, 193, 141, 1)", 48 | pointRadius: 2, 49 | pointHoverRadius: 3, 50 | pointBackgroundColor: "rgba(255, 255, 255, 1)", 51 | pointHoverBackgroundColor: "rgba(212, 242, 225, 1)", 52 | backgroundColor: "rgba(212, 242, 225, 0.3)", 53 | data: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 54 | } 55 | ] 56 | } 57 | } 58 | let dataDark = 59 | { 60 | data: 61 | { 62 | labels: ["", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""], 63 | datasets: 64 | [ 65 | { 66 | borderWidth: 1.5, 67 | borderColor: "rgba(89, 101, 249, 1)", 68 | pointRadius: 2, 69 | pointHoverRadius: 3, 70 | pointBackgroundColor: "rgba(255, 255, 255, 1)", 71 | pointHoverBackgroundColor: "rgba(230, 232, 254, 1)", 72 | backgroundColor: "rgba(230, 232, 254, 0.3)", 73 | data: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 74 | }, 75 | { 76 | borderWidth: 1.5, 77 | borderColor: "rgba(255, 89, 89, 1)", 78 | pointRadius: 2, 79 | pointHoverRadius: 3, 80 | pointBackgroundColor: "rgba(255, 255, 255, 1)", 81 | pointHoverBackgroundColor: "rgba(249, 226, 226, 1)", 82 | backgroundColor: "rgba(249, 226, 226, 0.3)", 83 | data: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 84 | }, 85 | { 86 | borderWidth: 1.5, 87 | borderColor: "rgba(8, 193, 141, 1)", 88 | pointRadius: 2, 89 | pointHoverRadius: 3, 90 | pointBackgroundColor: "rgba(255, 255, 255, 1)", 91 | pointHoverBackgroundColor: "rgba(212, 242, 225, 1)", 92 | backgroundColor: "rgba(212, 242, 225, 0.3)", 93 | data: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 94 | } 95 | ] 96 | } 97 | } 98 | let options = 99 | { 100 | type: "line", 101 | options: 102 | { 103 | maintainAspectRatio: false, 104 | legend: 105 | { 106 | display: false 107 | }, 108 | elements: 109 | { 110 | line: 111 | { 112 | tension: 0 113 | } 114 | }, 115 | scales: 116 | { 117 | yAxes: 118 | [ 119 | { 120 | ticks: 121 | { 122 | display: false, 123 | suggestedMin: 0, 124 | suggestedMax: 100 125 | }, 126 | gridLines: 127 | { 128 | drawTicks: false 129 | } 130 | } 131 | ], 132 | xAxes: 133 | [ 134 | { 135 | ticks: 136 | { 137 | display: false 138 | }, 139 | gridLines: 140 | { 141 | drawTicks: false 142 | } 143 | } 144 | ] 145 | }, 146 | animation: 147 | { 148 | duration: 150 149 | } 150 | } 151 | }; 152 | 153 | chart = new Chart(ctx, Object.assign((html.getAttribute("theme") == "light") ? dataLight : dataDark, options)); 154 | 155 | processorRectangle.addEventListener("click", function(event) {hideDataset(event.target || event.srcElement)}); 156 | ramRectangle.addEventListener("click", function(event) {hideDataset(event.target || event.srcElement)}); 157 | storageRectangle.addEventListener("click", function(event) {hideDataset(event.target || event.srcElement)}); 158 | } 159 | 160 | /** 161 | * Updates datasets shifting previous values 162 | * 163 | * @param {*} datasets datasets to update 164 | * @param {*} usageData new data 165 | */ 166 | function chartTick(usageData) 167 | { 168 | let datasets = chart.data.datasets; 169 | 170 | for (let i = 0; i < datasets.length; i++) 171 | { 172 | let dataset = datasets[i].data; 173 | let usageDataArray = Object.values(usageData); 174 | 175 | for (let k = 0; k < dataset.length - 1; k++) 176 | { 177 | dataset[k] = dataset[k + 1]; 178 | } 179 | dataset[dataset.length - 1] = usageDataArray[i]; 180 | } 181 | 182 | chart.update(); 183 | } 184 | 185 | /** 186 | * Hides chosen dataset from chart 187 | * 188 | * @param {*} element dataset to hide 189 | */ 190 | function hideDataset(element) 191 | { 192 | switch (String(element.id)) 193 | { 194 | case "processor-rectangle": 195 | { 196 | processorTriangle.style.animation = (chart.getDatasetMeta(0).hidden) ? "fade-in-triangle 0.5s forwards" : "fade-out-triangle 0.5s forwards"; 197 | 198 | chart.getDatasetMeta(0).hidden = (chart.getDatasetMeta(0).hidden) ? false : true; 199 | break; 200 | } 201 | case "ram-rectangle": 202 | { 203 | ramTriangle.style.animation = (chart.getDatasetMeta(1).hidden) ? "fade-in-triangle 0.5s forwards" : "fade-out-triangle 0.5s forwards"; 204 | 205 | chart.getDatasetMeta(1).hidden = (chart.getDatasetMeta(1).hidden) ? false : true; 206 | break; 207 | } 208 | case "storage-rectangle": 209 | { 210 | storageTriangle.style.animation = (chart.getDatasetMeta(2).hidden) ? "fade-in-triangle 0.5s forwards" : "fade-out-triangle 0.5s forwards"; 211 | 212 | chart.getDatasetMeta(2).hidden = (chart.getDatasetMeta(2).hidden) ? false : true; 213 | break; 214 | } 215 | } 216 | 217 | chart.update(); 218 | } -------------------------------------------------------------------------------- /src/main/resources/static/js/globals.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | /** 4 | * Used to determine html tag object 5 | */ 6 | let html; 7 | 8 | /** 9 | * Used to determine background object 10 | */ 11 | let background; 12 | 13 | 14 | /** 15 | * Used to determine background color 16 | */ 17 | let backgroundColor; 18 | 19 | /** 20 | * Used to determine if we enable the fog 21 | */ 22 | let enableFog; 23 | 24 | /** 25 | * Light theme square 26 | */ 27 | let lightThemeSquare; 28 | 29 | /** 30 | * Dark theme square 31 | */ 32 | let darkThemeSquare; 33 | 34 | /** 35 | * Used to set up server name 36 | */ 37 | let serverName; 38 | 39 | /** 40 | * Used to set up application port 41 | */ 42 | let port; 43 | 44 | /** 45 | * Used for sending setup request 46 | */ 47 | let setupXHR; 48 | 49 | /** 50 | * Used for sending usage requests 51 | */ 52 | let usageXHR; 53 | 54 | /** 55 | * Used for sending info requests 56 | */ 57 | let infoXHR; 58 | 59 | /** 60 | * Used for sending uptime requests 61 | */ 62 | let uptimeXHR; 63 | 64 | /** 65 | * Used to hold values of processor usage 66 | */ 67 | let processorLabelsArray; 68 | 69 | /** 70 | * Used to hold value of clock speed 71 | */ 72 | let currentClockSpeed; 73 | 74 | /** 75 | * Used to hold values tens of processor usage 76 | */ 77 | let ramLabelsArray; 78 | 79 | /** 80 | * Used to hold value of processes count 81 | */ 82 | let currentProcCount; 83 | 84 | /** 85 | * Used to hold values ones of processor usage 86 | */ 87 | let storageLabelsArray; 88 | 89 | /** 90 | * Used to hold values of total storage 91 | */ 92 | let currentTotalStorage 93 | 94 | /** 95 | * Used to hold values of disk count 96 | */ 97 | let currentDiskCount 98 | 99 | /** 100 | * Used to manipulate processor triangle div 101 | */ 102 | let processorTriangle; 103 | 104 | /** 105 | * Used to manipulate ram triangle div 106 | */ 107 | let ramTriangle; 108 | 109 | /** 110 | * Used to manipulate storage triangle div 111 | */ 112 | let storageTriangle; 113 | 114 | /** 115 | * Used to determine left cloud 116 | */ 117 | let cloudLeft 118 | 119 | /** 120 | * Used to determine right cloud 121 | */ 122 | let cloudRight 123 | 124 | /** 125 | * Used to display current days of uptime 126 | */ 127 | let days; 128 | 129 | /** 130 | * Used to display current hours of uptime 131 | */ 132 | let hours; 133 | 134 | /** 135 | * Used to display current minutes of uptime 136 | */ 137 | let minutes; 138 | 139 | /** 140 | * Used to display current seconds of uptime 141 | */ 142 | let seconds; 143 | 144 | /** 145 | * Used to handle chart object, displays usage for 15 seconds 146 | */ 147 | let chart; 148 | 149 | /** 150 | * Initialises html object and theme value 151 | */ 152 | function globalsInitialization() 153 | { 154 | html = document.getElementById("html"); 155 | } -------------------------------------------------------------------------------- /src/main/resources/static/js/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | /** 4 | * Initializes uptime, labels and chart values 5 | */ 6 | function indexInitialization() 7 | { 8 | showCards(); 9 | 10 | currentClockSpeed = document.getElementById("currentClockSpeed"); 11 | currentProcCount = document.getElementById("currentProcCount"); 12 | currentTotalStorage = document.getElementById("currentTotalStorage"); 13 | currentDiskCount = document.getElementById("currentDiskCount"); 14 | 15 | cloudLeft = document.getElementById("cloud-left"); 16 | cloudRight = document.getElementById("cloud-right"); 17 | 18 | days = document.getElementById("uptime-days"); 19 | hours = document.getElementById("uptime-hours"); 20 | minutes = document.getElementById("uptime-minutes"); 21 | seconds = document.getElementById("uptime-seconds"); 22 | 23 | usageXHR = new XMLHttpRequest(); 24 | infoXHR = new XMLHttpRequest(); 25 | uptimeXHR = new XMLHttpRequest(); 26 | 27 | sendUsageRequest(); 28 | } 29 | 30 | /** 31 | * Changes cards opacity with random sequence 32 | */ 33 | function showCards() 34 | { 35 | let cards = document.getElementsByClassName("card"); 36 | let versionLabel = document.getElementById("project-version"); 37 | 38 | let randomSequenceArray = getRandomSequenceArray(); 39 | 40 | for (let i = 0; i < cards.length; i++) 41 | { 42 | setTimeout(function() 43 | { 44 | cards[randomSequenceArray[i]].style.opacity = "1"; 45 | 46 | if (randomSequenceArray[i] == 4) 47 | { 48 | versionLabel.style.opacity = "1"; 49 | } 50 | }, 70 * i); 51 | } 52 | } 53 | 54 | /** 55 | * Generates random sequence 56 | */ 57 | function getRandomSequenceArray() 58 | { 59 | let buffer = []; 60 | 61 | while (buffer.length < 5) 62 | { 63 | let randomNumber = Math.floor(Math.random() * 5); 64 | 65 | if ((buffer.indexOf(randomNumber) === -1)) 66 | { 67 | buffer.push(randomNumber); 68 | } 69 | } 70 | 71 | return buffer; 72 | } 73 | 74 | /** 75 | * Sending ajax request to receive usage info 76 | */ 77 | function sendUsageRequest() 78 | { 79 | usageXHR.onreadystatechange = function() 80 | { 81 | if ((this.readyState == 4) && (this.status == 200)) 82 | { 83 | let response = JSON.parse(this.response); 84 | 85 | labelsTick(response); 86 | chartTick(response); 87 | 88 | sendInfoRequest(); 89 | } 90 | } 91 | 92 | usageXHR.open("GET", "/api/usage"); 93 | usageXHR.send(); 94 | } 95 | 96 | /** 97 | * Sending ajax request to receive info about server 98 | */ 99 | function sendInfoRequest() 100 | { 101 | infoXHR.onreadystatechange = function() 102 | { 103 | if ((this.readyState == 4) && (this.status == 200)) 104 | { 105 | let response = JSON.parse(this.response); 106 | 107 | currentClockSpeed.innerHTML = response.processor.clockSpeed; 108 | currentProcCount.innerHTML = response.machine.procCount; 109 | currentTotalStorage.innerHTML = response.storage.total; 110 | currentDiskCount.innerHTML = response.storage.diskCount; 111 | 112 | sendUptimeRequest(); 113 | } 114 | } 115 | 116 | infoXHR.open("GET", "/api/info"); 117 | infoXHR.send(); 118 | } 119 | 120 | /** 121 | * Sending ajax request to receive server uptime 122 | */ 123 | function sendUptimeRequest() 124 | { 125 | infoXHR.onreadystatechange = function() 126 | { 127 | if ((this.readyState == 4) && (this.status == 200)) 128 | { 129 | let response = JSON.parse(this.response); 130 | 131 | days.innerHTML = response.days; 132 | hours.innerHTML = response.hours; 133 | minutes.innerHTML = response.minutes; 134 | seconds.innerHTML = response.seconds; 135 | 136 | sendUsageRequest() 137 | } 138 | } 139 | 140 | infoXHR.open("GET", "/api/uptime"); 141 | infoXHR.send(); 142 | } 143 | 144 | /** 145 | * Animates clouds 146 | * 147 | * @param {*} new page 148 | */ 149 | function setCloudAnimation(newSquareScale) 150 | { 151 | switch (newSquareScale) 152 | { 153 | case 1: 154 | { 155 | cloudLeft.style.animation = "fade-in-cloud-left 0.3s forwards"; 156 | cloudRight.style.animation = "fade-in-cloud-right 0.3s forwards"; 157 | break; 158 | } 159 | case 2: 160 | { 161 | cloudLeft.style.animation = "fade-out-cloud-left 0.3s forwards"; 162 | cloudRight.style.animation = "fade-out-cloud-right 0.3s forwards"; 163 | break; 164 | } 165 | } 166 | } 167 | 168 | /** 169 | * Changes opacity of control 170 | * 171 | * @param {*} new page 172 | */ 173 | function setControlOpacity(newSquareScale) 174 | { 175 | switch (newSquareScale) 176 | { 177 | case 1: 178 | { 179 | firstControl.style.opacity = "0.5"; 180 | secondControl.style.opacity = "1"; 181 | break; 182 | } 183 | case 2: 184 | { 185 | firstControl.style.opacity = "1"; 186 | secondControl.style.opacity = "0.5"; 187 | break; 188 | } 189 | } 190 | } -------------------------------------------------------------------------------- /src/main/resources/static/js/labels.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | /** 4 | * Initializes labels span arrays 5 | */ 6 | function labelsInitialization() 7 | { 8 | processorLabelsArray = 9 | [ 10 | document.getElementById("processor-hundreds"), 11 | document.getElementById("processor-tens"), 12 | document.getElementById("processor-ones") 13 | ]; 14 | ramLabelsArray = 15 | [ 16 | document.getElementById("ram-hundreds"), 17 | document.getElementById("ram-tens"), 18 | document.getElementById("ram-ones") 19 | ]; 20 | storageLabelsArray = 21 | [ 22 | document.getElementById("storage-hundreds"), 23 | document.getElementById("storage-tens"), 24 | document.getElementById("storage-ones") 25 | ]; 26 | } 27 | 28 | /** 29 | * Updates labels values 30 | * 31 | * @param {*} usageData usage value 32 | */ 33 | function labelsTick(usageData) 34 | { 35 | let usageDataArray = Object.values(usageData); 36 | 37 | for (let i = 0; i < usageDataArray.length; i++) 38 | { 39 | switch (i) 40 | { 41 | case 0: 42 | { 43 | formatLabels(processorLabelsArray, usageDataArray[i]); 44 | break; 45 | } 46 | case 1: 47 | { 48 | formatLabels(ramLabelsArray, usageDataArray[i]); 49 | break; 50 | } 51 | case 2: 52 | { 53 | formatLabels(storageLabelsArray, usageDataArray[i]); 54 | break; 55 | } 56 | } 57 | } 58 | } 59 | 60 | /** 61 | * Distributes values to spans and changes their color 62 | * 63 | * @param {*} labelArray array with domObjects 64 | * @param {*} usageData usage value to distribute 65 | */ 66 | function formatLabels(labelArray, usageData) 67 | { 68 | let usageDataString = String(usageData); 69 | 70 | switch (usageDataString.length) 71 | { 72 | case 1: 73 | { 74 | labelArray[0].innerHTML = 0; 75 | labelArray[0].style.color = (html.getAttribute("theme") == "light") ? "rgba(188, 188, 188, 1)" : "rgba(121, 121, 121, 1)"; 76 | labelArray[1].innerHTML = 0; 77 | labelArray[1].style.color = (html.getAttribute("theme") == "light") ? "rgba(188, 188, 188, 1)" : "rgba(121, 121, 121, 1)"; 78 | labelArray[2].innerHTML = usageDataString[0]; 79 | labelArray[2].style.color = (html.getAttribute("theme") == "light") ? "rgba(0, 0, 0, 1)" : "rgba(255, 255, 255, 1)"; 80 | break; 81 | } 82 | case 2: 83 | { 84 | labelArray[0].innerHTML = 0; 85 | labelArray[0].style.color = (html.getAttribute("theme") == "light") ? "rgba(188, 188, 188, 1)" : "rgba(121, 121, 121, 1)"; 86 | labelArray[1].innerHTML = usageDataString[0]; 87 | labelArray[1].style.color = (html.getAttribute("theme") == "light") ? "rgba(0, 0, 0, 1)" : "rgba(255, 255, 255, 1)"; 88 | labelArray[2].innerHTML = usageDataString[1]; 89 | labelArray[2].style.color = (html.getAttribute("theme") == "light") ? "rgba(0, 0, 0, 1)" : "rgba(255, 255, 255, 1)"; 90 | break; 91 | } 92 | default: 93 | { 94 | labelArray[0].innerHTML = usageDataString[0]; 95 | labelArray[0].style.color = (html.getAttribute("theme") == "light") ? "rgba(0, 0, 0, 1)" : "rgba(255, 255, 255, 1)"; 96 | labelArray[1].innerHTML = usageDataString[1]; 97 | labelArray[1].style.color = (html.getAttribute("theme") == "light") ? "rgba(0, 0, 0, 1)" : "rgba(255, 255, 255, 1)"; 98 | labelArray[2].innerHTML = usageDataString[2]; 99 | labelArray[2].style.color = (html.getAttribute("theme") == "light") ? "rgba(0, 0, 0, 1)" : "rgba(255, 255, 255, 1)"; 100 | } 101 | } 102 | } -------------------------------------------------------------------------------- /src/main/resources/static/js/setup.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | /** 4 | * Initializes dom objects 5 | */ 6 | function setupInitialization() 7 | { 8 | setAlertStyle("light"); 9 | 10 | let lightTheme = document.getElementById("light-theme"); 11 | let darkTheme = document.getElementById("dark-theme"); 12 | let submit = document.getElementById("submit"); 13 | 14 | lightThemeSquare = document.getElementById("light-theme-square"); 15 | darkThemeSquare = document.getElementById("dark-theme-square"); 16 | 17 | serverName = document.getElementById("server-name"); 18 | port = document.getElementById("port"); 19 | enableFog = document.getElementById("fog-toggle"); 20 | backgroundColor = document.getElementById("color-selector"); 21 | 22 | setupXHR = new XMLHttpRequest(); 23 | 24 | lightTheme.addEventListener("click", function(event) {changeTheme(event.target || event.srcElement)}); 25 | darkTheme.addEventListener("click", function(event) {changeTheme(event.target || event.srcElement)}); 26 | submit.addEventListener("click", function(event) {sendSetupRequest(event.target || event.srcElement)}); 27 | enableFog.addEventListener("change", function(event) {toggleFog()}); 28 | backgroundColor.addEventListener("input", function(event) {changeBackgroundColor()}); 29 | } 30 | 31 | /** 32 | * Changes theme 33 | */ 34 | function changeTheme(element) 35 | { 36 | if (String(element.id) == "light-theme") 37 | { 38 | html.setAttribute("theme", "light"); 39 | setAlertStyle("light"); 40 | 41 | lightThemeSquare.style.animation = "fade-in-square 0.5s forwards"; 42 | darkThemeSquare.style.animation = "fade-out-square 0.5s forwards"; 43 | 44 | background.setOptions 45 | ({ 46 | highlightColor: 0xCAC7E8, 47 | midtoneColor: 0xBBB7ED, 48 | lowlightColor: 0xE4E3EF, 49 | baseColor: 0xE4E3EF 50 | }); 51 | } 52 | else 53 | { 54 | html.setAttribute("theme", "dark"); 55 | setAlertStyle("dark"); 56 | 57 | darkThemeSquare.style.visibility = "visible"; 58 | 59 | lightThemeSquare.style.animation = "fade-out-square 0.5s forwards"; 60 | darkThemeSquare.style.animation = "fade-in-square 0.5s forwards"; 61 | 62 | background.setOptions 63 | ({ 64 | highlightColor: 0x797979, 65 | midtoneColor: 0xFFFFFF, 66 | lowlightColor: 0xBCBCBC, 67 | baseColor: 0xBCBCBC 68 | }); 69 | } 70 | let color = html.getAttribute("theme") == "light" ? "#e5e5e5" : "#303030"; 71 | html.setAttribute("backgroundColor", color); 72 | backgroundColor.value = color; 73 | document.body.style.backgroundColor = color; 74 | } 75 | 76 | /** 77 | * Changes alert style 78 | * 79 | * @param {*} style name 80 | */ 81 | function setAlertStyle(styleName) 82 | { 83 | let links = document.getElementsByTagName("link"); 84 | 85 | for (let i = 0; i < links.length; i++) 86 | { 87 | if ((links[i].getAttribute("title") == "light") || (links[i].getAttribute("title") == "dark")) 88 | { 89 | links[i].disabled = (links[i].getAttribute("title") != styleName); 90 | } 91 | } 92 | } 93 | 94 | /** 95 | * Sends settings request 96 | */ 97 | function sendSetupRequest() 98 | { 99 | setupXHR.open("POST", "/api/setup"); 100 | setupXHR.setRequestHeader("Content-Type", "application/json"); 101 | 102 | setupXHR.onreadystatechange = function() 103 | { 104 | if (this.readyState == 4) 105 | { 106 | if (this.status == 200) 107 | { 108 | submit.value = "LOADING"; 109 | window.location = "http://" + window.location.hostname + ":" + port.value; 110 | } 111 | else 112 | { 113 | let message = 114 | { 115 | text: "Fill the form correctly", 116 | type: ("") 117 | } 118 | 119 | dhtmlx.message(message); 120 | } 121 | } 122 | } 123 | 124 | let data = 125 | { 126 | "serverName": serverName.value, 127 | "theme": html.getAttribute("theme"), 128 | "port": port.value, 129 | "enableFog": String(enableFog.checked), 130 | "backgroundColor": backgroundColor.value 131 | } 132 | 133 | setupXHR.send(JSON.stringify(data)); 134 | 135 | } 136 | 137 | /** 138 | * Toggles fog 139 | */ 140 | function toggleFog() 141 | { 142 | html.setAttribute("enableFog", String(enableFog.checked)); 143 | backgroundInitialization(); 144 | backgroundColor.disabled = enableFog.checked; 145 | } 146 | 147 | /** 148 | * Change background color 149 | */ 150 | function changeBackgroundColor() 151 | { 152 | html.setAttribute("backgroundColor", backgroundColor.value); 153 | document.body.style.backgroundColor = backgroundColor.value; 154 | } -------------------------------------------------------------------------------- /src/main/resources/templates/error/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 |
26 |
404
27 |
哎呀! 你好像迷路了...
28 |
29 |
您查找的页面不存在.
30 |
所以你是怎么到这的?
31 |
32 |
You're drunk, 回到主页
33 |
34 |
35 | 36 | 37 | -------------------------------------------------------------------------------- /src/main/resources/templates/error/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 |
26 |
500
27 |
我们出现了问题...
28 |
29 |
请给我们一些时间来修理这个问题.
30 |
你现在可以出去享受一下阳光.
31 |
一切交给我们就好.
32 |
33 |
你可以提交一个问题到 Github
34 |
35 |
36 | 37 | 38 | -------------------------------------------------------------------------------- /src/main/resources/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 |
30 |
31 |
32 |
33 | 36 |
37 |
CPU
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | 0 46 | 0 47 | 0 48 |
49 |
%
50 |
51 |

CPU使用率

52 |
53 |
54 |
55 | 66 |
67 |
68 |
69 |
70 |
71 | 74 |
75 |
内存
76 |
77 | 78 |
79 |
80 |
81 |
82 |
83 |
84 | 0 85 | 0 86 | 0 87 |
88 |
%
89 |
90 |

内存使用率

91 |
92 |
93 |
94 | 105 |
106 |
107 |
108 |
109 |
110 | 113 |
114 |
磁盘
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 | 0 123 | 0 124 | 0 125 |
126 |
%
127 |
128 |
磁盘使用率
129 |
130 |
131 |
132 | 143 |
144 |
145 | 146 |
147 |
148 | 149 |
服务器已运行时间
150 |
151 | 152 | 153 |
154 | 155 |
156 |
157 |
158 |

159 |

160 |

161 |

162 |
163 |
164 |
165 |
小时
166 |
分钟
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
硬件利用率 (%)
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 | 188 |
189 | 190 |
191 |
192 |
193 |
194 |
195 | 196 | 197 | 198 | -------------------------------------------------------------------------------- /src/main/resources/templates/setup.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Welcome 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 36 | 37 | 38 | 39 |
40 |
41 | 42 |
服务器仪表盘
43 |
44 | 45 | 46 |
47 | 48 |
49 |
50 |
51 |
52 |
53 |
54 |
主要设置
55 |
56 | 57 |
58 |
59 |
其他设置
60 |
61 |
62 |
63 |
64 |
65 |
66 | 67 | 68 |
69 | 70 | 71 | 72 |
73 | 74 |
75 |
76 |
77 | 78 | 79 | 80 | --------------------------------------------------------------------------------