diff --git a/package.json b/package.json index adc1a7d..f9d41d1 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,7 @@ "@types/node": "^13.1.0", "@types/react": "^16.9.17", "@types/react-dom": "^16.9.4", + "@types/react-gauge-chart": "^0.3.1", "@types/react-router-dom": "^5.1.3", "@types/webpack-env": "^1.14.1", "auto-launch": "^5.0.5", @@ -73,6 +74,7 @@ "prettier": "^1.19.1", "react": "^16.12.0", "react-dom": "^16.12.0", + "react-gauge-chart": "^0.4.0", "react-router-dom": "^5.1.2", "react-scripts": "3.3.0", "sass": "^1.24.0", diff --git a/src/components/SceneSelector.tsx b/src/components/SceneSelector.tsx index f16b932..82dfc7f 100644 --- a/src/components/SceneSelector.tsx +++ b/src/components/SceneSelector.tsx @@ -6,6 +6,7 @@ import { getTranslation } from "../contexts/LocaleContext"; const cpuTitleText = getTranslation("sceneSelector.cpuTitle", "CPU"); const gpuTitleText = getTranslation("sceneSelector.gpuTitle", "GPU"); const powerTitleText = getTranslation("sceneSelector.powerTitle", "Power"); +const statusTitleText = getTranslation("sceneSelector.statusTitle", "Status"); const presetsTitleText = getTranslation("sceneSelector.presetsTitle", "Presets"); const settingsTitleText = getTranslation("sceneSelector.settingsTitle", "Settings"); const releasesTitleText = getTranslation("sceneSelector.releasesTitle", "Releases"); @@ -40,6 +41,7 @@ function SceneSelector() { <Tabs tabName={cpuTitleText} tabLocation="/cpu" currentLocation={currentLocation} /> <Tabs tabName={gpuTitleText} tabLocation="/gpu" currentLocation={currentLocation} /> <Tabs tabName={powerTitleText} tabLocation="/power" currentLocation={currentLocation} /> + <Tabs tabName={statusTitleText} tabLocation="/status" currentLocation={currentLocation} /> <Tabs tabName={presetsTitleText} tabLocation="/presets" currentLocation={currentLocation} /> <Tabs tabName={settingsTitleText} tabLocation="/settings" currentLocation={currentLocation} /> <li> diff --git a/src/contexts/RyzenAdjContext.tsx b/src/contexts/RyzenAdjContext.tsx index 23f7997..8e36175 100644 --- a/src/contexts/RyzenAdjContext.tsx +++ b/src/contexts/RyzenAdjContext.tsx @@ -215,7 +215,7 @@ const createRyzenAdjCommandLine = function(preset: RyzenAdjOptionListType): Arra return commandLine; }; -const ryzenAdjProcess = function(parameters: Array<string>): Promise<string> { +export const ryzenAdjProcess = function(parameters: Array<string>): Promise<string> { return new Promise((res, rej) => { const child = window.require("child_process").execFile; const executablePath = getRyzenAdjExecutablePath(); diff --git a/src/contexts/RyzenControllerAppContext.tsx b/src/contexts/RyzenControllerAppContext.tsx index 7620551..0f5fde0 100644 --- a/src/contexts/RyzenControllerAppContext.tsx +++ b/src/contexts/RyzenControllerAppContext.tsx @@ -202,6 +202,36 @@ const RyzenControllerSettingsDefinitions: RyzenControllerSettingDefinitionList = }); }, }, + statusUpdateInterval: { + displayTitle: true, + name: getTranslation("appContext.statusUpdateInterval.name", "Status Update Interval"), + type: "range", + default: 2000, + short_description: getTranslation( + "appContext.statusUpdateInterval.shortDesc", + "Define how often the status page shall update (in milliseconds)" + ), + description: getTranslation( + "appContext.statusUpdateInterval.desc", + "The default value is 2000ms. The minimum value is 500ms" + ), + compatibility: { + linux: true, + win32: true, + }, + apply(seconds) { + // @ts-ignore + let parsedSeconds: number = parseInt(seconds); + if (!isNumber(parsedSeconds)) { + return new Promise((resolve, reject) => { + reject("ERROR: Value must be of number type."); + }); + } + return new Promise((resolve, reject) => { + resolve(true); + }); + }, + }, ryzenAdjPath: { displayTitle: true, name: getTranslation("appContext.ryzenAdjPath.name", "RyzenAdj path"), @@ -308,6 +338,7 @@ const defaultRyzenControllerAppContext: RyzenControllerAppContextType = { minimizeOnLaunch: false, minimizeToTray: false, reApplyPeriodically: false, + statusUpdateInterval: 2000, ryzenAdjPath: "", onLaptopPluggedIn: false, onLaptopPluggedOut: false, diff --git a/src/locales/ch.json b/src/locales/ch.json index f217118..62cb364 100644 --- a/src/locales/ch.json +++ b/src/locales/ch.json @@ -115,5 +115,16 @@ "ryzenAdjBottomBar.invalidPreset": "无法套用无效的预设", "settingForm.windowsBinFileType": "Windows可执行文件", "presetOnlineBtn.presetInvalidOrObsolete": "预设 {presetName} 无效或已过时", - "sysInfoCards.unableToGetSysInfo": "无法获取系统信息:" + "sysInfoCards.unableToGetSysInfo": "无法获取系统信息:", + "appContext.statusUpdateInterval.name": "状态更新间隔", + "appContext.statusUpdateInterval.shortDesc": "定义状态页的更新频率(以毫秒计)。", + "appContext.statusUpdateInterval.desc": "默认值是2000ms。最小值是500ms", + "sceneSelector.statusTitle": "状况", + "statusScene.noData": "没有数据显示", + "statusScene.thmValueCore": "核心温度", + "statusScene.pptValueApu": "封装功耗", + "statusScene.showRawData": "显示原始数据", + "statusScene.tableParameter": "参数", + "statusScene.tableValue": "当前值", + "statusScene.tableMaxValue": "最大值" } diff --git a/src/locales/de.json b/src/locales/de.json index 015d61b..0f05b5a 100644 --- a/src/locales/de.json +++ b/src/locales/de.json @@ -27,6 +27,7 @@ "appContext.minimizeOnLaunch.name": "Minimieren", "appContext.ryzenAdjPath.name": "RyzenAdj Pfad", "sceneSelector.settingsTitle": "Einstellungen", + "sceneSelector.statusTitle": "Status", "sceneSelector.powerTitle": "Leistung", "ryzenAdj.slowTime.desc": "Dies definiert die Periode der konstanten Energiezufuhr zum Sockel während der Boostfreien Phase.", "ryzenAdj.slowTime.label": "Package Power Tracking (PPT) - Slow period (Langsame Phase)", @@ -60,6 +61,9 @@ "appContext.reApplyPeriodically.name": "Periodisch erneut anwenden", "ryzenAdj.tctlTemp.label": "Temperatur Limit (°C)", "appContext.reApplyPeriodically.shortDesc": "Erlaubt dir die RyzenAdj Einstellungen periodisch erneut anzuwenden (\"alle X Sekunden\").", + "appContext.statusUpdateInterval.name": "Status Update Interval", + "appContext.statusUpdateInterval.shortDesc": "Legt fest wie häufig die Status-Seite neue Daten abruft (in Millisekunden)", + "appContext.statusUpdateInterval.desc": "Der Standardwert ist 2000ms. Der Mindestwert ist 500ms", "PresetsScene.onlinePresetTitle": "Online Presets", "PresetsScene.localPresetTitle": "Lokale Presets", "PresetsScene.autoApplyTitle": "Presets unter bestimmten Bedingungen automatisch anwenden", @@ -115,5 +119,12 @@ "appContext.ryzenAdjPath.wrongPath": "Der Pfad zu ryzenadj.exe ist falsch. Bitte korrigiere diesen in den Tab für Einstellungen.", "ryzenAdjBottomBar.invalidPreset": "Kann ungültige Presets nicht anwenden", "presetOnlineBtn.presetLoaded": "Preset {presetName} wurde geladen", - "presetButtons.mustWaitForSignatureGen": "Du musst warten, bis die Laptop-Signatur generiert wurde" + "presetButtons.mustWaitForSignatureGen": "Du musst warten, bis die Laptop-Signatur generiert wurde", + "statusScene.noData": "Keine Daten verfügbar", + "statusScene.thmValueCore": "Core Temperatur", + "statusScene.pptValueApu": "Package Power", + "statusScene.showRawData": "Rohdaten anzeigen", + "statusScene.tableParameter": "Parameter", + "statusScene.tableValue": "Aktueller Wert", + "statusScene.tableMaxValue": "Max. Wert" } diff --git a/src/locales/en.json b/src/locales/en.json index c7f5b7c..70d4f1a 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -28,6 +28,7 @@ "appContext.ryzenAdjPath.name": "RyzenAdj path", "sceneSelector.settingsTitle": "Settings", "sceneSelector.powerTitle": "Power", + "sceneSelector.statusTitle": "Status", "ryzenAdj.slowTime.desc": "This defines the period to be used out of boost period to deliver a constant power to be delivered to the socket.", "ryzenAdj.slowTime.label": "Package Power Tracking (PPT) - Slow period", "ryzenAdj.minFclkFrequency.desc": "Infinity Fabric is AMD's marketing term for the bus connection that connects processor dies (GPU/CPU). This defines the bus's min. clock limit.", @@ -58,6 +59,9 @@ "sceneSelector.releasesTitle": "Releases", "ryzenAdj.tctlTemp.desc": "The temperature the CPU can reach before boost levels off.", "appContext.reApplyPeriodically.name": "Re-apply periodically", + "appContext.statusUpdateInterval.name": "Status Update Interval", + "appContext.statusUpdateInterval.shortDesc": "Define how often the status page shall update (in milliseconds)", + "appContext.statusUpdateInterval.desc": "The default value is 2000ms. The minimum value is 500ms", "ryzenAdj.tctlTemp.label": "Temperature Limit (°C)", "appContext.reApplyPeriodically.shortDesc": "Allow you to re-apply RyzenAdj settings periodically (every X seconds).", "PresetsScene.onlinePresetTitle": "Online Presets", @@ -115,5 +119,12 @@ "appContext.ryzenAdjPath.wrongPath": "Path to ryzenadj.exe is wrong, please fix it in settings tab.", "ryzenAdjBottomBar.invalidPreset": "Unable to apply invalid preset", "presetOnlineBtn.presetLoaded": "Preset \"{presetName}\" has been loaded", - "presetButtons.mustWaitForSignatureGen": "You must wait for laptop signature to be generated" + "presetButtons.mustWaitForSignatureGen": "You must wait for laptop signature to be generated", + "statusScene.noData": "No data to show", + "statusScene.thmValueCore": "Core Temperature", + "statusScene.pptValueApu": "Package Power Consumption", + "statusScene.showRawData": "Show raw data", + "statusScene.tableParameter": "Parameter", + "statusScene.tableValue": "Current value", + "statusScene.tableMaxValue": "Max. value" } diff --git a/src/locales/es.json b/src/locales/es.json index e86fadb..5c23477 100644 --- a/src/locales/es.json +++ b/src/locales/es.json @@ -116,5 +116,16 @@ "PresetsScene.errorWhileSendingVote": "Error al enviar voto", "sysInfoCards.unableToGetSysInfo": "No se puede obtener información del sistema:", "presetButtons.mustWaitForSignatureGen": "Debe esperar a que se genere la firma de la computadora portátil", - "settingForm.windowsBinFileType": "Ejecutable de Windows" + "settingForm.windowsBinFileType": "Ejecutable de Windows", + "appContext.statusUpdateInterval.name": "Intervalo de actualización de estado", + "appContext.statusUpdateInterval.shortDesc": "Definir la frecuencia de actualización de la página de estado (en milisegundos)", + "appContext.statusUpdateInterval.desc": "El valor por defecto es de 2000ms. El valor mínimo es de 500ms", + "sceneSelector.statusTitle": "Estado", + "statusScene.noData": "no hay información para mostrar", + "statusScene.thmValueCore": "Temperatura del núcleo", + "statusScene.pptValueApu": "Consumo de energía del paquete", + "statusScene.showRawData": "Mostrar datos en bruto", + "statusScene.tableParameter": "Parámetro", + "statusScene.tableValue": "Valor actual", + "statusScene.tableMaxValue": "Valor máximo" } diff --git a/src/locales/fr.json b/src/locales/fr.json index 17b4211..335e7cd 100644 --- a/src/locales/fr.json +++ b/src/locales/fr.json @@ -115,5 +115,16 @@ "appContext.ryzenAdjPath.wrongPath": "Le chemin vers ryzenadj.exe est invalide, veuillez le corriger dans l'onglet paramètres.", "ryzenAdjBottomBar.invalidPreset": "Preset corrompu, impossible de l'appliquer", "presetOnlineBtn.presetLoaded": "Le preset \"{presetName}\" est chargé", - "presetButtons.mustWaitForSignatureGen": "Vous devez attendre que la signature de votre PC ai été généré." + "presetButtons.mustWaitForSignatureGen": "Vous devez attendre que la signature de votre PC ai été généré.", + "appContext.statusUpdateInterval.name": "Intervalle de mise à jour du statut", + "appContext.statusUpdateInterval.shortDesc": "Définissez la fréquence de mise à jour de la page statut (en millisecondes).", + "appContext.statusUpdateInterval.desc": "La valeur par défaut est de 2000ms. La valeur minimale est de 500ms", + "sceneSelector.statusTitle": "Statut", + "statusScene.noData": "Aucune donnée à afficher", + "statusScene.thmValueCore": "Température du coeur", + "statusScene.pptValueApu": "Consommation package power", + "statusScene.showRawData": "Afficher les données brutes", + "statusScene.tableParameter": "Paramètre", + "statusScene.tableValue": "Valeur actuelle", + "statusScene.tableMaxValue": "Valeur max." } diff --git a/src/locales/ko.json b/src/locales/ko.json index 34ceeb9..46acf25 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -1,119 +1,130 @@ -{ - "topbar.discord": "Discord에서 저희와 참여하세요", - "topbar.beer": "저희에게 맥주를 사주세요 ❤️", - "presetButtons.applyPresetTooltip": "사전 설정이 RyzenAdj의 탭에 불러와서 적용됩니다.", - "presetButtons.loadPresetTooltip": "사전 설정은 RyzenAdj의 탭에 불러올 수 있지만 적용되지 않습니다.", - "presetAutoApply.whenSessionResume": "세션이 재개되었을 때", - "presetAutoApply.whenRCStart": "Ryzen Controller를 시작할 때", - "presetAutoApply.whenLaptopPluggedIn": "랩탑이 플러그에 연결되었을 때", - "presetAutoApply.whenLaptopPluggedOut": "랩탑이 플러그에 연결되지 않았을 때", - "presetButtons.confirmDeletion": "\"{preset}\"을(를) 삭제하겠습니까?", - "presetButtons.loadedPreset": "사전 설정 {preset}을(를) 불러왔습니다.", - "presetButtons.uploadPresetConfirmation": "사전 설정 {preset}을(를) 업로드하겠습니까?", - "presetListEmpty.youDontHaveAny": "아직 아무런 사전 설정이 없습니다", - "presetListEmpty.sentencePart1": "RyzenAdj 설정 탭 (CPU, GPU, ...)에서 사용 가능한 설정을", - "presetListEmpty.createPresetBtn": "사전 설정 생성", - "presetListEmpty.sentencePart2": "버튼을 클릭하여 생성할 수 있습니다.", - "PresetOnline.listNotLoadedYet": "목록을 불러오지 않았거나, 아직 온라인 사전 설정이 없습니다.", - "PresetOnline.loadPresetListBtn": "사전 설정 목록 불러오기", - "PresetOnline.sentencePart1": "자신의 사전 설정을", - "PresetOnline.uploadBtn": "업로드", - "PresetOnline.sentencePart2": "버튼을 클릭하여 공유할 수 있습니다.", - "sceneSelector.cpuTitle": "CPU", - "sceneSelector.gpuTitle": "GPU", - "ryzenAdj.maxGfxclk.label": "최대 Vega iGPU 클럭 주파수 (Mhz)", - "ryzenAdj.stapmTime.desc": "표면 온도 인식 전원 관리 (STAPM). 이것은 사용할 부스트 간격을 정의합니다.", - "ryzenAdj.slowLimit.desc": "부스트 단계가 꺼졌을 때 CPU가 사용할 수 있는 전력입니다.", - "appContext.minimizeOnLaunch.name": "최소화 상태로 시작", - "appContext.ryzenAdjPath.name": "RyzenAdj 경로", - "sceneSelector.settingsTitle": "설정", - "sceneSelector.powerTitle": "전력", - "ryzenAdj.slowTime.desc": "이것은 소켓에 전달될 일정한 전력을 공급하기 위해 부스트 간격에서 사용될 간격을 정의합니다.", - "ryzenAdj.slowTime.label": "패키지 전력 추적 (PPT) - 느린 간격", - "ryzenAdj.minFclkFrequency.desc": "인피니티 패브릭은 프로세서 다이 (GPU/CPU)를 연결하는 버스 연결에 대한 AMD의 마케팅 용어입니다. 이것은 버스의 최소 클럭 제한을 정의합니다.", - "ryzenAdj.maxFclkFrequency.desc": "인피니티 패브릭은 프로세서 다이 (GPU/CPU)를 연결하는 버스 연결에 대한 AMD의 마케팅 용어입니다. 이것은 버스의 최대 클럭 제한을 정의합니다.", - "ryzenAdj.stapmLimit.desc": "표면 온도 인식 전원 관리 (STAPM). 이것은 장치 부스트 간격을 관리하는 데 사용되는 소켓 전원 패키지 제한을 정의합니다.", - "ryzenAdj.stapmTime.label": "CPU 부스트 간격", - "ryzenAdj.vrmmaxCurrent.desc": "마더보드가 CPU로 전달할 수 있는 전류의 한계입니다.", - "ryzenAdj.vrmmaxCurrent.label": "VRM 전류 (A)", - "appContext.ryzenAdjPath.shortDesc": "RyzenAdj 바이너리의 전체 경로입니다.", - "ryzenAdj.maxFclkFrequency.label": "최대 인피니티 패브릭 주파수 (Mhz)", - "ryzenAdj.stapmLimit.label": "CPU TDP (W)", - "appContext.autoStartOnBoot.shortDesc": "컴퓨터를 시작할 때 Ryzen Controller를 실행합니다.", - "sceneSelector.presetsTitle": "사전 설정", - "ryzenAdj.psi0Current.label": "PSI0 전류 제한 (mA)", - "ryzenAdj.maxGfxclk.desc": "통합 (Vega) GPU가 실행될 수 있는 최대 클럭 속도입니다.", - "ryzenAdj.minFclkFrequency.label": "최소 인피니티 패브릭 주파수 (Mhz)", - "ryzenAdj.slowLimit.label": "CPU 최소 TDP (W)", - "appContext.minimizeOnLaunch.shortDesc": "Ryzen Controller를 최소화 상태로 시작합니다.", - "ryzenAdj.minGfxclk.label": "최소 Vega iGPU 클럭 주파수 (Mhz)", - "ryzenAdj.fastLimit.desc": "부스트 단계가 켜졌을 때 CPU가 사용할 수 있는 전력입니다.", - "appContext.minimizeToTray.name": "최소화 상태에서 트레이 상태로 전환", - "ryzenAdj.psi0Current.desc": "마더보드가 PSI0로 전달할 수 있는 전류의 한계입니다.", - "ryzenAdj.minGfxclk.desc": "통합 (Vega) GPU가 실행될 수 있는 최소 클럭 속도입니다.", - "ryzenAdj.fastLimit.label": "CPU 부스트 TDP (W)", - "appContext.autoStartOnBoot.name": "부트 시 자동 시작", - "appContext.minimizeToTray.shortDesc": "Ryzen Controller를 작업 표시줄 대신 트레이로 최소화합니다.", - "appContext.reApplyPeriodically.desc": "일부 랩톱에서는 BIOS가 RyzenAdj가 시도하려는 작업을 다시 설정하기도 합니다. 이를 통해 정기적으로 설정을 적용할 수 있습니다.", - "sceneSelector.releasesTitle": "릴리스", - "ryzenAdj.tctlTemp.desc": "부스트 단계가 꺼지기 전에 CPU가 도달할 수 있는 온도입니다.", - "appContext.reApplyPeriodically.name": "정기적으로 다시 적용", - "ryzenAdj.tctlTemp.label": "온도 제한 (°C)", - "appContext.reApplyPeriodically.shortDesc": "RyzenAdj 설정을 정기적으로 다시 적용할 수 있습니다 (매 X초마다).", - "PresetsScene.onlinePresetTitle": "온라인 사전 설정", - "PresetsScene.localPresetTitle": "로컬 사전 설정", - "PresetsScene.autoApplyTitle": "사전 설정 자동 적용", - "SettingsScene.settingsTitle": "설정", - "settingForm.currentPath": "현재 경로:", - "sysInfoCards.biosVersion": "BIOS 버전:", - "sysInfoCards.gpuPerfDesc": "{ram}Mb (동적 VRAM: {dyn}).", - "SettingsScene.sysInfoTitle": "시스템 정보", - "sysInfoCards.basicInfoTitle": "기본 정보", - "settingForm.browseBtn": "탐색", - "SettingsScene.systemHashDesc": "이것은 다운로드된 사전 설정 호환성을 보장하기 위해 사용됩니다.", - "sysInfoCards.CPUInfoTitle": "CPU 정보", - "sysInfoCards.cpuPerfDesc": "{physicalCores}코어, {cores}스레드에서 {speedmax}Ghz.", - "sysInfoCards.GPUInfoTitle": "GPU #{index} 정보", - "SettingsScene.loadingSysHash": "불러오는 중...", - "ryzenAdjBottomBar.prompt": "새 사전 설정 이름", - "ryzenAdjBottomBar.mustProvideName": "이름을 입력하세요", - "ryzenAdjBottomBar.presetCreated": "사전 설정 \"{newPresetName}\"이(가) 생성되었습니다", - "ryzenAdjBottomBar.presetWithSameNameExist": "사전 설정 이름 \"{newPresetName}\"이(가) 이미 존재합니다", - "presetButtons.apply": "적용", - "presetButtons.delete": "삭제", - "presetButtons.load": "불러오기", - "presetAutoApply.nonePreset": "없음", - "presetButtons.upload": "업로드", - "ryzenAdj.applySuccess": "RyzenAdj가 성공적으로 실행되었습니다.", - "presetButtons.uploadSucceed": "사전 설정 {preset}이(가) 업로드되었습니다", - "presetOnlineBtn.downloadTooltip": "로컬 사전 설정에 사전 설정이 저장됩니다.", - "presetOnlineBtn.loadTooltip": "사전 설정을 저장하지 않으면, RyzenAdj의 탭에 불러올 수 있지만 적용되지 않습니다..", - "presetOnlineBtn.download": "다운로드", - "presetOnlineBtn.load": "불러오기", - "presetButtons.presetWithSameNameAlreadyExistOnline": "사전 설정 이름이 온라인에 이미 존재합니다", - "presetOnlineBtn.presetDownloaded": "사전 설정 \"{presetName}\"을(를) 불러왔습니다", - "presetOnlineBtn.presetSameNameExist": "이미 같은 이름의 사전 설정을 가지고 있습니다", - "PresetsScene.cantVoteTwiceSamePreset": "같은 사전 설정에 2번 투표할 수 없습니다", - "PresetsScene.confirmVote": "이 사전 설정에 {투표}하겠습니까?", - "PresetsScene.updatingVotes": "투표를 갱신하는 중...", - "notification.settingsSaveSuccess": "설정이 성공적으로 저장되었습니다", - "ryzenAdjBottomBar.apply": "적용", - "ryzenAdjBottomBar.createPreset": "사전 설정 생성", - "ryzenAdjBottomBar.reset": "다시 설정", - "app.localeSelectorModalTitle": "언어 변경", - "appContext.newReleaseAvailable": "새로운 릴리스를 사용할 수 있으니, 릴리스 탭을 확인하세요.", - "PresetOnline.errorLoadingPresets": "사전 설정을 불러올 수 없습니다.", - "PresetOnline.retryLoadingPresetListBtn": "다시 시도", - "PresetOnline.pleaseCheckInternetConnection": "인터넷 연결을 확인하세요.", - "presetButtons.uploadError": "사전 설정을 업로드하는 도중에 오류가 발생했습니다", - "presetLine.compatibility": "호환성:", - "appContext.invalidPreset": "유효하지 않은 사전 설정을 적용할 수 없습니다", - "presetOnlineBtn.presetInvalidOrObsolete": "사전 설정 \"{presetName}\"은(는) 유효하지 않습니다", - "PresetsScene.errorWhileSendingVote": "투표를 보내는 도중에 오류가 발생했습니다", - "sysInfoCards.unableToGetSysInfo": "얻지 못한 시스템 정보:", - "settingForm.windowsBinFileType": "Windows 바이너리", - "appContext.ryzenAdjPath.wrongPath": "ryzenadj.exe의 경로가 잘못되었으니, 설정 탭에서 수정하세요.", - "ryzenAdjBottomBar.invalidPreset": "유효하지 않은 사전 설정을 적용할 수 없습니다", - "presetOnlineBtn.presetLoaded": "사전 설정 \"{presetName}\"을(를) 불러왔습니다", - "presetButtons.mustWaitForSignatureGen": "랩탑 서명이 생성될 때까지 기다리세요" -} +{ + "topbar.discord": "Discord에서 저희와 참여하세요", + "topbar.beer": "저희에게 맥주를 사주세요 ❤️", + "presetButtons.applyPresetTooltip": "사전 설정이 RyzenAdj의 탭에 불러와서 적용됩니다.", + "presetButtons.loadPresetTooltip": "사전 설정은 RyzenAdj의 탭에 불러올 수 있지만 적용되지 않습니다.", + "presetAutoApply.whenSessionResume": "세션이 재개되었을 때", + "presetAutoApply.whenRCStart": "Ryzen Controller를 시작할 때", + "presetAutoApply.whenLaptopPluggedIn": "랩탑이 플러그에 연결되었을 때", + "presetAutoApply.whenLaptopPluggedOut": "랩탑이 플러그에 연결되지 않았을 때", + "presetButtons.confirmDeletion": "\"{preset}\"을(를) 삭제하겠습니까?", + "presetButtons.loadedPreset": "사전 설정 {preset}을(를) 불러왔습니다.", + "presetButtons.uploadPresetConfirmation": "사전 설정 {preset}을(를) 업로드하겠습니까?", + "presetListEmpty.youDontHaveAny": "아직 아무런 사전 설정이 없습니다", + "presetListEmpty.sentencePart1": "RyzenAdj 설정 탭 (CPU, GPU, ...)에서 사용 가능한 설정을", + "presetListEmpty.createPresetBtn": "사전 설정 생성", + "presetListEmpty.sentencePart2": "버튼을 클릭하여 생성할 수 있습니다.", + "PresetOnline.listNotLoadedYet": "목록을 불러오지 않았거나, 아직 온라인 사전 설정이 없습니다.", + "PresetOnline.loadPresetListBtn": "사전 설정 목록 불러오기", + "PresetOnline.sentencePart1": "자신의 사전 설정을", + "PresetOnline.uploadBtn": "업로드", + "PresetOnline.sentencePart2": "버튼을 클릭하여 공유할 수 있습니다.", + "sceneSelector.cpuTitle": "CPU", + "sceneSelector.gpuTitle": "GPU", + "ryzenAdj.maxGfxclk.label": "최대 Vega iGPU 클럭 주파수 (Mhz)", + "ryzenAdj.stapmTime.desc": "표면 온도 인식 전원 관리 (STAPM). 이것은 사용할 부스트 간격을 정의합니다.", + "ryzenAdj.slowLimit.desc": "부스트 단계가 꺼졌을 때 CPU가 사용할 수 있는 전력입니다.", + "appContext.minimizeOnLaunch.name": "최소화 상태로 시작", + "appContext.ryzenAdjPath.name": "RyzenAdj 경로", + "sceneSelector.settingsTitle": "설정", + "sceneSelector.powerTitle": "전력", + "ryzenAdj.slowTime.desc": "이것은 소켓에 전달될 일정한 전력을 공급하기 위해 부스트 간격에서 사용될 간격을 정의합니다.", + "ryzenAdj.slowTime.label": "패키지 전력 추적 (PPT) - 느린 간격", + "ryzenAdj.minFclkFrequency.desc": "인피니티 패브릭은 프로세서 다이 (GPU/CPU)를 연결하는 버스 연결에 대한 AMD의 마케팅 용어입니다. 이것은 버스의 최소 클럭 제한을 정의합니다.", + "ryzenAdj.maxFclkFrequency.desc": "인피니티 패브릭은 프로세서 다이 (GPU/CPU)를 연결하는 버스 연결에 대한 AMD의 마케팅 용어입니다. 이것은 버스의 최대 클럭 제한을 정의합니다.", + "ryzenAdj.stapmLimit.desc": "표면 온도 인식 전원 관리 (STAPM). 이것은 장치 부스트 간격을 관리하는 데 사용되는 소켓 전원 패키지 제한을 정의합니다.", + "ryzenAdj.stapmTime.label": "CPU 부스트 간격", + "ryzenAdj.vrmmaxCurrent.desc": "마더보드가 CPU로 전달할 수 있는 전류의 한계입니다.", + "ryzenAdj.vrmmaxCurrent.label": "VRM 전류 (A)", + "appContext.ryzenAdjPath.shortDesc": "RyzenAdj 바이너리의 전체 경로입니다.", + "ryzenAdj.maxFclkFrequency.label": "최대 인피니티 패브릭 주파수 (Mhz)", + "ryzenAdj.stapmLimit.label": "CPU TDP (W)", + "appContext.autoStartOnBoot.shortDesc": "컴퓨터를 시작할 때 Ryzen Controller를 실행합니다.", + "sceneSelector.presetsTitle": "사전 설정", + "ryzenAdj.psi0Current.label": "PSI0 전류 제한 (mA)", + "ryzenAdj.maxGfxclk.desc": "통합 (Vega) GPU가 실행될 수 있는 최대 클럭 속도입니다.", + "ryzenAdj.minFclkFrequency.label": "최소 인피니티 패브릭 주파수 (Mhz)", + "ryzenAdj.slowLimit.label": "CPU 최소 TDP (W)", + "appContext.minimizeOnLaunch.shortDesc": "Ryzen Controller를 최소화 상태로 시작합니다.", + "ryzenAdj.minGfxclk.label": "최소 Vega iGPU 클럭 주파수 (Mhz)", + "ryzenAdj.fastLimit.desc": "부스트 단계가 켜졌을 때 CPU가 사용할 수 있는 전력입니다.", + "appContext.minimizeToTray.name": "최소화 상태에서 트레이 상태로 전환", + "ryzenAdj.psi0Current.desc": "마더보드가 PSI0로 전달할 수 있는 전류의 한계입니다.", + "ryzenAdj.minGfxclk.desc": "통합 (Vega) GPU가 실행될 수 있는 최소 클럭 속도입니다.", + "ryzenAdj.fastLimit.label": "CPU 부스트 TDP (W)", + "appContext.autoStartOnBoot.name": "부트 시 자동 시작", + "appContext.minimizeToTray.shortDesc": "Ryzen Controller를 작업 표시줄 대신 트레이로 최소화합니다.", + "appContext.reApplyPeriodically.desc": "일부 랩톱에서는 BIOS가 RyzenAdj가 시도하려는 작업을 다시 설정하기도 합니다. 이를 통해 정기적으로 설정을 적용할 수 있습니다.", + "sceneSelector.releasesTitle": "릴리스", + "ryzenAdj.tctlTemp.desc": "부스트 단계가 꺼지기 전에 CPU가 도달할 수 있는 온도입니다.", + "appContext.reApplyPeriodically.name": "정기적으로 다시 적용", + "ryzenAdj.tctlTemp.label": "온도 제한 (°C)", + "appContext.reApplyPeriodically.shortDesc": "RyzenAdj 설정을 정기적으로 다시 적용할 수 있습니다 (매 X초마다).", + "PresetsScene.onlinePresetTitle": "온라인 사전 설정", + "PresetsScene.localPresetTitle": "로컬 사전 설정", + "PresetsScene.autoApplyTitle": "사전 설정 자동 적용", + "SettingsScene.settingsTitle": "설정", + "settingForm.currentPath": "현재 경로:", + "sysInfoCards.biosVersion": "BIOS 버전:", + "sysInfoCards.gpuPerfDesc": "{ram}Mb (동적 VRAM: {dyn}).", + "SettingsScene.sysInfoTitle": "시스템 정보", + "sysInfoCards.basicInfoTitle": "기본 정보", + "settingForm.browseBtn": "탐색", + "SettingsScene.systemHashDesc": "이것은 다운로드된 사전 설정 호환성을 보장하기 위해 사용됩니다.", + "sysInfoCards.CPUInfoTitle": "CPU 정보", + "sysInfoCards.cpuPerfDesc": "{physicalCores}코어, {cores}스레드에서 {speedmax}Ghz.", + "sysInfoCards.GPUInfoTitle": "GPU #{index} 정보", + "SettingsScene.loadingSysHash": "불러오는 중...", + "ryzenAdjBottomBar.prompt": "새 사전 설정 이름", + "ryzenAdjBottomBar.mustProvideName": "이름을 입력하세요", + "ryzenAdjBottomBar.presetCreated": "사전 설정 \"{newPresetName}\"이(가) 생성되었습니다", + "ryzenAdjBottomBar.presetWithSameNameExist": "사전 설정 이름 \"{newPresetName}\"이(가) 이미 존재합니다", + "presetButtons.apply": "적용", + "presetButtons.delete": "삭제", + "presetButtons.load": "불러오기", + "presetAutoApply.nonePreset": "없음", + "presetButtons.upload": "업로드", + "ryzenAdj.applySuccess": "RyzenAdj가 성공적으로 실행되었습니다.", + "presetButtons.uploadSucceed": "사전 설정 {preset}이(가) 업로드되었습니다", + "presetOnlineBtn.downloadTooltip": "로컬 사전 설정에 사전 설정이 저장됩니다.", + "presetOnlineBtn.loadTooltip": "사전 설정을 저장하지 않으면, RyzenAdj의 탭에 불러올 수 있지만 적용되지 않습니다..", + "presetOnlineBtn.download": "다운로드", + "presetOnlineBtn.load": "불러오기", + "presetButtons.presetWithSameNameAlreadyExistOnline": "사전 설정 이름이 온라인에 이미 존재합니다", + "presetOnlineBtn.presetDownloaded": "사전 설정 \"{presetName}\"을(를) 불러왔습니다", + "presetOnlineBtn.presetSameNameExist": "이미 같은 이름의 사전 설정을 가지고 있습니다", + "PresetsScene.cantVoteTwiceSamePreset": "같은 사전 설정에 2번 투표할 수 없습니다", + "PresetsScene.confirmVote": "이 사전 설정에 {투표}하겠습니까?", + "PresetsScene.updatingVotes": "투표를 갱신하는 중...", + "notification.settingsSaveSuccess": "설정이 성공적으로 저장되었습니다", + "ryzenAdjBottomBar.apply": "적용", + "ryzenAdjBottomBar.createPreset": "사전 설정 생성", + "ryzenAdjBottomBar.reset": "다시 설정", + "app.localeSelectorModalTitle": "언어 변경", + "appContext.newReleaseAvailable": "새로운 릴리스를 사용할 수 있으니, 릴리스 탭을 확인하세요.", + "PresetOnline.errorLoadingPresets": "사전 설정을 불러올 수 없습니다.", + "PresetOnline.retryLoadingPresetListBtn": "다시 시도", + "PresetOnline.pleaseCheckInternetConnection": "인터넷 연결을 확인하세요.", + "presetButtons.uploadError": "사전 설정을 업로드하는 도중에 오류가 발생했습니다", + "presetLine.compatibility": "호환성:", + "appContext.invalidPreset": "유효하지 않은 사전 설정을 적용할 수 없습니다", + "presetOnlineBtn.presetInvalidOrObsolete": "사전 설정 \"{presetName}\"은(는) 유효하지 않습니다", + "PresetsScene.errorWhileSendingVote": "투표를 보내는 도중에 오류가 발생했습니다", + "sysInfoCards.unableToGetSysInfo": "얻지 못한 시스템 정보:", + "settingForm.windowsBinFileType": "Windows 바이너리", + "appContext.ryzenAdjPath.wrongPath": "ryzenadj.exe의 경로가 잘못되었으니, 설정 탭에서 수정하세요.", + "ryzenAdjBottomBar.invalidPreset": "유효하지 않은 사전 설정을 적용할 수 없습니다", + "presetOnlineBtn.presetLoaded": "사전 설정 \"{presetName}\"을(를) 불러왔습니다", + "presetButtons.mustWaitForSignatureGen": "랩탑 서명이 생성될 때까지 기다리세요", + "appContext.statusUpdateInterval.name": "상태 업데이트 간격", + "appContext.statusUpdateInterval.shortDesc": "상태 페이지가 업데이트되는 빈도를 정의합니다(밀리초).", + "appContext.statusUpdateInterval.desc": "기본값은 2000ms입니다. 최소값은 500ms입니다.", + "sceneSelector.statusTitle": "상태", + "statusScene.noData": "표시 할 데이터 없음", + "statusScene.thmValueCore": "중심 온도", + "statusScene.pptValueApu": "패키지 전력 소비", + "statusScene.showRawData": "원시 데이터 표시", + "statusScene.tableParameter": "매개변수", + "statusScene.tableValue": "현재 가치", + "statusScene.tableMaxValue": "최대 값" +} diff --git a/src/locales/ru.json b/src/locales/ru.json index 2e6d652..9e2a446 100644 --- a/src/locales/ru.json +++ b/src/locales/ru.json @@ -115,5 +115,16 @@ "appContext.ryzenAdjPath.wrongPath": "Путь к ryzenadj.exe некорректен, пожалуйста, измените его в разделе 'Настройки'", "ryzenAdjBottomBar.invalidPreset": "Невозможно применить некорректный пресет", "presetOnlineBtn.presetLoaded": "Пресет \"{presetName}\" загружен", - "presetButtons.mustWaitForSignatureGen": "Вы должны подождать завершения генерации подписи ноутбука" + "presetButtons.mustWaitForSignatureGen": "Вы должны подождать завершения генерации подписи ноутбука", + "appContext.statusUpdateInterval.name": "Интервал обновления состояния", + "appContext.statusUpdateInterval.shortDesc": "Определите, как часто должна обновляться страница состояния (в миллисекундах)", + "appContext.statusUpdateInterval.desc": "Значение по умолчанию - 2000 мс. Минимальное значение - 500 мс", + "sceneSelector.statusTitle": "Статус", + "statusScene.noData": "Нет данных для отображения", + "statusScene.thmValueCore": "Температура процессора", + "statusScene.pptValueApu": "Потребляемая мощность пакета", + "statusScene.showRawData": "Показать исходные данные", + "statusScene.tableParameter": "Параметр", + "statusScene.tableValue": "Текущее значение", + "statusScene.tableMaxValue": "Макс. значение" } diff --git a/src/locales/tr.json b/src/locales/tr.json index 47569e3..1b8dc30 100644 --- a/src/locales/tr.json +++ b/src/locales/tr.json @@ -115,5 +115,16 @@ "appContext.ryzenAdjPath.wrongPath": "Ryzenadj.exe dizin yolu yanlış, lütfen ayarlar sekmesinde düzelt.", "ryzenAdjBottomBar.invalidPreset": "Geçersiz Preset uygulanamıyor", "presetOnlineBtn.presetLoaded": "Preset {PresetName} yüklendi", - "presetButtons.mustWaitForSignatureGen": "Laptop imzasının oluşturulmasını beklemelisiniz" + "presetButtons.mustWaitForSignatureGen": "Laptop imzasının oluşturulmasını beklemelisiniz", + "appContext.statusUpdateInterval.name": "Durum Güncelleme Aralığı", + "appContext.statusUpdateInterval.shortDesc": "Durum sayfasının ne sıklıkla güncelleneceğini tanımlayın (milisaniye cinsinden)", + "appContext.statusUpdateInterval.desc": "Varsayılan değer 2000ms'dir. Minimum değer 500ms", + "sceneSelector.statusTitle": "Durum", + "statusScene.noData": "gösterilecek bilgi yok", + "statusScene.thmValueCore": "Çekirdek sıcaklığı", + "statusScene.pptValueApu": "Paket güç tüketimi", + "statusScene.showRawData": "Ham verileri göster", + "statusScene.tableParameter": "Parametre", + "statusScene.tableValue": "Mevcut değer", + "statusScene.tableMaxValue": "Maks. değer" } diff --git a/src/locales/ua.json b/src/locales/ua.json index 0eda993..f2b132f 100644 --- a/src/locales/ua.json +++ b/src/locales/ua.json @@ -115,5 +115,16 @@ "appContext.ryzenAdjPath.wrongPath": "Шлях до ryzenadj.exe є некоректним, будь ласка, змініть його в розділі 'Налаштування'", "ryzenAdjBottomBar.invalidPreset": "Неможливо застосувати некоректний пресет", "presetOnlineBtn.presetLoaded": "Пресет \"{presetName}\" завантажений", - "presetButtons.mustWaitForSignatureGen": "Ви повинні зачекати завершення генерації подпису ноутбука" + "presetButtons.mustWaitForSignatureGen": "Ви повинні зачекати завершення генерації подпису ноутбука", + "appContext.statusUpdateInterval.name": "Інтервал оновлення стану", + "appContext.statusUpdateInterval.shortDesc": "Визначте, як часто сторінка стану оновлюватиметься (у мілісекундах)", + "appContext.statusUpdateInterval.desc": "Значення за замовчуванням - 2000 мс. Мінімальне значення - 500 мс", + "sceneSelector.statusTitle": "Статус", + "statusScene.noData": "Немає даних для відображення", + "statusScene.thmValueCore": "Основна температура", + "statusScene.pptValueApu": "Споживана потужність пакета", + "statusScene.showRawData": "Показувати необроблені дані", + "statusScene.tableParameter": "Параметр", + "statusScene.tableValue": "Поточне значення", + "statusScene.tableMaxValue": "Макс. значення" } diff --git a/src/react-app-env.d.ts b/src/react-app-env.d.ts index fe8be1e..b843941 100644 --- a/src/react-app-env.d.ts +++ b/src/react-app-env.d.ts @@ -56,6 +56,7 @@ type RyzenControllerSettingsNames = | "minimizeOnLaunch" | "minimizeToTray" | "reApplyPeriodically" + | "statusUpdateInterval" | "ryzenAdjPath" | "onLaptopPluggedIn" | "onLaptopPluggedOut" @@ -67,6 +68,7 @@ type RyzenControllerSettings = { minimizeOnLaunch: boolean; minimizeToTray: boolean; reApplyPeriodically: number | false; + statusUpdateInterval: number; ryzenAdjPath: string; onLaptopPluggedIn: string | false; onLaptopPluggedOut: string | false; diff --git a/src/scenes/Scene.tsx b/src/scenes/Scene.tsx index 6082886..ba4d4c2 100644 --- a/src/scenes/Scene.tsx +++ b/src/scenes/Scene.tsx @@ -13,6 +13,7 @@ import PresetsScene from "../scenes/PresetsScene"; import SettingsScene from "../scenes/SettingsScene"; import NotificationContext from "../contexts/NotificationContext"; import { getTranslation } from "../contexts/LocaleContext"; +import StatusScene from "./StatusScene"; const electronSettings = window.require("electron-settings"); const powerMonitor = window.require("electron").remote.powerMonitor; @@ -174,6 +175,9 @@ class Scene extends React.Component<{}, RyzenControllerAppContextType> { <Route exact path="/cpu" render={() => <RyzenAdjScene filter="cpu" />} /> <Route exact path="/gpu" render={() => <RyzenAdjScene filter="gpu" />} /> <Route exact path="/power" render={() => <RyzenAdjScene filter="power" />} /> + <Route exact path="/status"> + <StatusScene /> + </Route> <Route exact path="/presets"> <PresetsScene /> </Route> diff --git a/src/scenes/StatusScene.tsx b/src/scenes/StatusScene.tsx new file mode 100644 index 0000000..7ca419c --- /dev/null +++ b/src/scenes/StatusScene.tsx @@ -0,0 +1,144 @@ +import * as React from "react"; +import GaugeChart from "react-gauge-chart"; +import { ryzenAdjProcess } from "../contexts/RyzenAdjContext"; +import { getTranslation } from "../contexts/LocaleContext"; +import LightModeContext from "../contexts/LightModeContext"; +import { appContextSettingsKey, RyzenControllerSettingsDefinitions } from "../contexts/RyzenControllerAppContext"; +const electronSettings = window.require("electron-settings"); + +const i18n = { + noData: getTranslation("statusScene.noData", "No data to show"), + thmValueCore: getTranslation("statusScene.thmValueCore", "Core Temperature"), + pptValueApu: getTranslation("statusScene.pptValueApu", "Package Power Consumption"), + showRawData: getTranslation("statusScene.showRawData", "Show raw data"), + tableParameter: getTranslation("statusScene.tableParameter", "Parameter"), + tableValue: getTranslation("statusScene.tableValue", "Current value"), + tableMaxValue: getTranslation("statusScene.tableMaxValue", "Max. value"), +}; + +class PresetsScene extends React.Component { + _isMounted = false; + data: { [key: string]: number } = {}; + allData = false; + __constructor() {} + async componentDidMount() { + this._isMounted = true; + this.parseData(await ryzenAdjProcess(["-i"])); + let intervalDuration = + electronSettings.get(appContextSettingsKey)?.settings.statusUpdateInterval || + RyzenControllerSettingsDefinitions["statusUpdateInterval"].default; + intervalDuration = Math.max(500, intervalDuration); + const interval = setInterval(async () => { + if (!this._isMounted) { + clearInterval(interval); + return; + } + this.parseData(await ryzenAdjProcess(["-i"])); + }, intervalDuration as number); + } + parseData(output: string) { + output + .split("\n") + .slice(2) + .forEach(line => { + const parts = line.split("|"); + if (parts.length === 5) { + const value = parseFloat(parts[2].trim()); + // smooth values on readout to prevent jumping of gauges + if (this.data[parts[1].trim()]) { + this.data[parts[1].trim()] += (value - this.data[parts[1].trim()]) * 0.8; + } else { + this.data[parts[1].trim()] = value; + } + } + }); + this.setState({ data: this.data }); + } + + componentWillUnmount() { + this._isMounted = false; + } + + render() { + if (Object.keys(this.data).length === 0) { + return <h2 className="uk-flex uk-flex-center">{i18n.noData}</h2>; + } + return ( + <LightModeContext.Consumer> + {lightModeContext => { + return ( + <div className="uk-flex uk-flex-column uk-padding-large"> + <div className="uk-flex uk-flex-center uk-flex-around uk-padding-large"> + <div className="uk-flex uk-flex-column uk-flex-middle uk-box-shadow-small uk-padding-small"> + <GaugeChart + id="gauge-temp-current" + textColor={lightModeContext.mode === "light" ? "#000" : "#fff"} + nrOfLevels={10} + percent={(this.data["THM VALUE CORE"] || 0) / this.data["THM LIMIT CORE"] - 0.2} + formatTextValue={v => Math.round(this.data["THM VALUE CORE"]) + " °c"} + /> + <label className="uk-label">{i18n.thmValueCore}</label> + </div> + {this.data["PPT VALUE APU"] ? ( + <div className="uk-flex uk-flex-column uk-flex-middle uk-box-shadow-medium uk-padding-small"> + <GaugeChart + id="gauge-tdp-current" + textColor={lightModeContext.mode === "light" ? "#000" : "#fff"} + nrOfLevels={10} + percent={(this.data["PPT VALUE APU"] || 0) / this.data["PPT LIMIT APU"]} + formatTextValue={v => Math.round(this.data["PPT VALUE APU"] * 10) / 10 + " w"} + /> + <label className="uk-label">{i18n.pptValueApu}</label> + </div> + ) : null} + </div> + <div className="uk-flex uk-flex-center uk-margin-top"> + <button + className="uk-button uk-button-default uk-flex uk-flex-middle" + onClick={() => { + this.allData = !this.allData; + this.setState({ allData: this.allData }); + }} + > + <span>{i18n.showRawData}</span> + <span uk-icon={this.allData ? "chevron-up" : "chevron-down"} className="uk-margin-small-left" /> + </button> + </div> + {this.allData ? this.renderRawData() : null} + </div> + ); + }} + </LightModeContext.Consumer> + ); + } + renderRawData() { + return ( + <div className="uk-container uk-container-xlarge"> + <table className="uk-table"> + <thead> + <tr> + <th>{i18n.tableParameter}</th> + <th>{i18n.tableValue}</th> + <th>{i18n.tableMaxValue}</th> + </tr> + </thead> + <tbody> + {Object.keys(this.data) + .filter(f => f.includes("VALUE")) + .map(element => { + return ( + <tr> + <td>{element}</td> + <td>{Math.round(this.data[element] * 100) / 100}</td> + <td>{Math.round(this.data[element.replace("VALUE", "LIMIT")] * 100) / 100}</td> + </tr> + ); + })} + </tbody> + </table> + </div> + ); + } +} + +export default PresetsScene; diff --git a/yarn.lock b/yarn.lock index 760fd0f..82e7a87 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1514,6 +1514,13 @@ dependencies: "@types/react" "*" +"@types/react-gauge-chart@^0.3.1": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@types/react-gauge-chart/-/react-gauge-chart-0.3.1.tgz#3e9356d321dd4075e1bc2982591090536e4b28e5" + integrity sha512-con5hCPNerlGGAh4VTYwqpgWsITmdcngU+u0+qN77nOB4pXShI9r6dhQ6Ji0hzrHcgM7Xq2g/mNolr7AZ5j+Lg== + dependencies: + "@types/react" "*" + "@types/react-router-dom@^5.1.3": version "5.1.3" resolved "https://registry.yarnpkg.com/@types/react-router-dom/-/react-router-dom-5.1.3.tgz#b5d28e7850bd274d944c0fbbe5d57e6b30d71196" @@ -3229,6 +3236,11 @@ combined-stream@^1.0.6, combined-stream@~1.0.6: dependencies: delayed-stream "~1.0.0" +commander@2, commander@^2.11.0, commander@^2.20.0, commander@~2.20.3: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + commander@2.11.0: version "2.11.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" @@ -3239,11 +3251,6 @@ commander@2.17.x: resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf" integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg== -commander@^2.11.0, commander@^2.20.0, commander@~2.20.3: - version "2.20.3" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" - integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== - commander@~2.19.0: version "2.19.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" @@ -3791,6 +3798,254 @@ cyclist@^1.0.1: resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9" integrity sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk= +d3-array@1, d3-array@^1.1.1, d3-array@^1.2.0: + version "1.2.4" + resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-1.2.4.tgz#635ce4d5eea759f6f605863dbcfc30edc737f71f" + integrity sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw== + +d3-axis@1: + version "1.0.12" + resolved "https://registry.yarnpkg.com/d3-axis/-/d3-axis-1.0.12.tgz#cdf20ba210cfbb43795af33756886fb3638daac9" + integrity sha512-ejINPfPSNdGFKEOAtnBtdkpr24c4d4jsei6Lg98mxf424ivoDP2956/5HDpIAtmHo85lqT4pruy+zEgvRUBqaQ== + +d3-brush@1: + version "1.1.6" + resolved "https://registry.yarnpkg.com/d3-brush/-/d3-brush-1.1.6.tgz#b0a22c7372cabec128bdddf9bddc058592f89e9b" + integrity sha512-7RW+w7HfMCPyZLifTz/UnJmI5kdkXtpCbombUSs8xniAyo0vIbrDzDwUJB6eJOgl9u5DQOt2TQlYumxzD1SvYA== + dependencies: + d3-dispatch "1" + d3-drag "1" + d3-interpolate "1" + d3-selection "1" + d3-transition "1" + +d3-chord@1: + version "1.0.6" + resolved "https://registry.yarnpkg.com/d3-chord/-/d3-chord-1.0.6.tgz#309157e3f2db2c752f0280fedd35f2067ccbb15f" + integrity sha512-JXA2Dro1Fxw9rJe33Uv+Ckr5IrAa74TlfDEhE/jfLOaXegMQFQTAgAw9WnZL8+HxVBRXaRGCkrNU7pJeylRIuA== + dependencies: + d3-array "1" + d3-path "1" + +d3-collection@1: + version "1.0.7" + resolved "https://registry.yarnpkg.com/d3-collection/-/d3-collection-1.0.7.tgz#349bd2aa9977db071091c13144d5e4f16b5b310e" + integrity sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A== + +d3-color@1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-1.4.1.tgz#c52002bf8846ada4424d55d97982fef26eb3bc8a" + integrity sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q== + +d3-contour@1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/d3-contour/-/d3-contour-1.3.2.tgz#652aacd500d2264cb3423cee10db69f6f59bead3" + integrity sha512-hoPp4K/rJCu0ladiH6zmJUEz6+u3lgR+GSm/QdM2BBvDraU39Vr7YdDCicJcxP1z8i9B/2dJLgDC1NcvlF8WCg== + dependencies: + d3-array "^1.1.1" + +d3-dispatch@1: + version "1.0.6" + resolved "https://registry.yarnpkg.com/d3-dispatch/-/d3-dispatch-1.0.6.tgz#00d37bcee4dd8cd97729dd893a0ac29caaba5d58" + integrity sha512-fVjoElzjhCEy+Hbn8KygnmMS7Or0a9sI2UzGwoB7cCtvI1XpVN9GpoYlnb3xt2YV66oXYb1fLJ8GMvP4hdU1RA== + +d3-drag@1: + version "1.2.5" + resolved "https://registry.yarnpkg.com/d3-drag/-/d3-drag-1.2.5.tgz#2537f451acd39d31406677b7dc77c82f7d988f70" + integrity sha512-rD1ohlkKQwMZYkQlYVCrSFxsWPzI97+W+PaEIBNTMxRuxz9RF0Hi5nJWHGVJ3Om9d2fRTe1yOBINJyy/ahV95w== + dependencies: + d3-dispatch "1" + d3-selection "1" + +d3-dsv@1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/d3-dsv/-/d3-dsv-1.2.0.tgz#9d5f75c3a5f8abd611f74d3f5847b0d4338b885c" + integrity sha512-9yVlqvZcSOMhCYzniHE7EVUws7Fa1zgw+/EAV2BxJoG3ME19V6BQFBwI855XQDsxyOuG7NibqRMTtiF/Qup46g== + dependencies: + commander "2" + iconv-lite "0.4" + rw "1" + +d3-ease@1: + version "1.0.7" + resolved "https://registry.yarnpkg.com/d3-ease/-/d3-ease-1.0.7.tgz#9a834890ef8b8ae8c558b2fe55bd57f5993b85e2" + integrity sha512-lx14ZPYkhNx0s/2HX5sLFUI3mbasHjSSpwO/KaaNACweVwxUruKyWVcb293wMv1RqTPZyZ8kSZ2NogUZNcLOFQ== + +d3-fetch@1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/d3-fetch/-/d3-fetch-1.2.0.tgz#15ce2ecfc41b092b1db50abd2c552c2316cf7fc7" + integrity sha512-yC78NBVcd2zFAyR/HnUiBS7Lf6inSCoWcSxFfw8FYL7ydiqe80SazNwoffcqOfs95XaLo7yebsmQqDKSsXUtvA== + dependencies: + d3-dsv "1" + +d3-force@1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/d3-force/-/d3-force-1.2.1.tgz#fd29a5d1ff181c9e7f0669e4bd72bdb0e914ec0b" + integrity sha512-HHvehyaiUlVo5CxBJ0yF/xny4xoaxFxDnBXNvNcfW9adORGZfyNF1dj6DGLKyk4Yh3brP/1h3rnDzdIAwL08zg== + dependencies: + d3-collection "1" + d3-dispatch "1" + d3-quadtree "1" + d3-timer "1" + +d3-format@1: + version "1.4.5" + resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-1.4.5.tgz#374f2ba1320e3717eb74a9356c67daee17a7edb4" + integrity sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ== + +d3-geo@1: + version "1.12.1" + resolved "https://registry.yarnpkg.com/d3-geo/-/d3-geo-1.12.1.tgz#7fc2ab7414b72e59fbcbd603e80d9adc029b035f" + integrity sha512-XG4d1c/UJSEX9NfU02KwBL6BYPj8YKHxgBEw5om2ZnTRSbIcego6dhHwcxuSR3clxh0EpE38os1DVPOmnYtTPg== + dependencies: + d3-array "1" + +d3-hierarchy@1: + version "1.1.9" + resolved "https://registry.yarnpkg.com/d3-hierarchy/-/d3-hierarchy-1.1.9.tgz#2f6bee24caaea43f8dc37545fa01628559647a83" + integrity sha512-j8tPxlqh1srJHAtxfvOUwKNYJkQuBFdM1+JAUfq6xqH5eAqf93L7oG1NVqDa4CpFZNvnNKtCYEUC8KY9yEn9lQ== + +d3-interpolate@1: + version "1.4.0" + resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-1.4.0.tgz#526e79e2d80daa383f9e0c1c1c7dcc0f0583e987" + integrity sha512-V9znK0zc3jOPV4VD2zZn0sDhZU3WAE2bmlxdIwwQPPzPjvyLkd8B3JUVdS1IDUFDkWZ72c9qnv1GK2ZagTZ8EA== + dependencies: + d3-color "1" + +d3-path@1: + version "1.0.9" + resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-1.0.9.tgz#48c050bb1fe8c262493a8caf5524e3e9591701cf" + integrity sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg== + +d3-polygon@1: + version "1.0.6" + resolved "https://registry.yarnpkg.com/d3-polygon/-/d3-polygon-1.0.6.tgz#0bf8cb8180a6dc107f518ddf7975e12abbfbd38e" + integrity sha512-k+RF7WvI08PC8reEoXa/w2nSg5AUMTi+peBD9cmFc+0ixHfbs4QmxxkarVal1IkVkgxVuk9JSHhJURHiyHKAuQ== + +d3-quadtree@1: + version "1.0.7" + resolved "https://registry.yarnpkg.com/d3-quadtree/-/d3-quadtree-1.0.7.tgz#ca8b84df7bb53763fe3c2f24bd435137f4e53135" + integrity sha512-RKPAeXnkC59IDGD0Wu5mANy0Q2V28L+fNe65pOCXVdVuTJS3WPKaJlFHer32Rbh9gIo9qMuJXio8ra4+YmIymA== + +d3-random@1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/d3-random/-/d3-random-1.1.2.tgz#2833be7c124360bf9e2d3fd4f33847cfe6cab291" + integrity sha512-6AK5BNpIFqP+cx/sreKzNjWbwZQCSUatxq+pPRmFIQaWuoD+NrbVWw7YWpHiXpCQ/NanKdtGDuB+VQcZDaEmYQ== + +d3-scale-chromatic@1: + version "1.5.0" + resolved "https://registry.yarnpkg.com/d3-scale-chromatic/-/d3-scale-chromatic-1.5.0.tgz#54e333fc78212f439b14641fb55801dd81135a98" + integrity sha512-ACcL46DYImpRFMBcpk9HhtIyC7bTBR4fNOPxwVSl0LfulDAwyiHyPOTqcDG1+t5d4P9W7t/2NAuWu59aKko/cg== + dependencies: + d3-color "1" + d3-interpolate "1" + +d3-scale@2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-2.2.2.tgz#4e880e0b2745acaaddd3ede26a9e908a9e17b81f" + integrity sha512-LbeEvGgIb8UMcAa0EATLNX0lelKWGYDQiPdHj+gLblGVhGLyNbaCn3EvrJf0A3Y/uOOU5aD6MTh5ZFCdEwGiCw== + dependencies: + d3-array "^1.2.0" + d3-collection "1" + d3-format "1" + d3-interpolate "1" + d3-time "1" + d3-time-format "2" + +d3-selection@1, d3-selection@^1.1.0: + version "1.4.2" + resolved "https://registry.yarnpkg.com/d3-selection/-/d3-selection-1.4.2.tgz#dcaa49522c0dbf32d6c1858afc26b6094555bc5c" + integrity sha512-SJ0BqYihzOjDnnlfyeHT0e30k0K1+5sR3d5fNueCNeuhZTnGw4M4o8mqJchSwgKMXCNFo+e2VTChiSJ0vYtXkg== + +d3-shape@1: + version "1.3.7" + resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-1.3.7.tgz#df63801be07bc986bc54f63789b4fe502992b5d7" + integrity sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw== + dependencies: + d3-path "1" + +d3-time-format@2: + version "2.3.0" + resolved "https://registry.yarnpkg.com/d3-time-format/-/d3-time-format-2.3.0.tgz#107bdc028667788a8924ba040faf1fbccd5a7850" + integrity sha512-guv6b2H37s2Uq/GefleCDtbe0XZAuy7Wa49VGkPVPMfLL9qObgBST3lEHJBMUp8S7NdLQAGIvr2KXk8Hc98iKQ== + dependencies: + d3-time "1" + +d3-time@1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-1.1.0.tgz#b1e19d307dae9c900b7e5b25ffc5dcc249a8a0f1" + integrity sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA== + +d3-timer@1: + version "1.0.10" + resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-1.0.10.tgz#dfe76b8a91748831b13b6d9c793ffbd508dd9de5" + integrity sha512-B1JDm0XDaQC+uvo4DT79H0XmBskgS3l6Ve+1SBCfxgmtIb1AVrPIoqd+nPSv+loMX8szQ0sVUhGngL7D5QPiXw== + +d3-transition@1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/d3-transition/-/d3-transition-1.3.2.tgz#a98ef2151be8d8600543434c1ca80140ae23b398" + integrity sha512-sc0gRU4PFqZ47lPVHloMn9tlPcv8jxgOQg+0zjhfZXMQuvppjG6YuwdMBE0TuqCZjeJkLecku/l9R0JPcRhaDA== + dependencies: + d3-color "1" + d3-dispatch "1" + d3-ease "1" + d3-interpolate "1" + d3-selection "^1.1.0" + d3-timer "1" + +d3-voronoi@1: + version "1.1.4" + resolved "https://registry.yarnpkg.com/d3-voronoi/-/d3-voronoi-1.1.4.tgz#dd3c78d7653d2bb359284ae478645d95944c8297" + integrity sha512-dArJ32hchFsrQ8uMiTBLq256MpnZjeuBtdHpaDlYuQyjU0CVzCJl/BVW+SkszaAeH95D/8gxqAhgx0ouAWAfRg== + +d3-zoom@1: + version "1.8.3" + resolved "https://registry.yarnpkg.com/d3-zoom/-/d3-zoom-1.8.3.tgz#b6a3dbe738c7763121cd05b8a7795ffe17f4fc0a" + integrity sha512-VoLXTK4wvy1a0JpH2Il+F2CiOhVu7VRXWF5M/LroMIh3/zBAC3WAt7QoIvPibOavVo20hN6/37vwAsdBejLyKQ== + dependencies: + d3-dispatch "1" + d3-drag "1" + d3-interpolate "1" + d3-selection "1" + d3-transition "1" + +d3@^5.12.0: + version "5.16.0" + resolved "https://registry.yarnpkg.com/d3/-/d3-5.16.0.tgz#9c5e8d3b56403c79d4ed42fbd62f6113f199c877" + integrity sha512-4PL5hHaHwX4m7Zr1UapXW23apo6pexCgdetdJ5kTmADpG/7T9Gkxw0M0tf/pjoB63ezCCm0u5UaFYy2aMt0Mcw== + dependencies: + d3-array "1" + d3-axis "1" + d3-brush "1" + d3-chord "1" + d3-collection "1" + d3-color "1" + d3-contour "1" + d3-dispatch "1" + d3-drag "1" + d3-dsv "1" + d3-ease "1" + d3-fetch "1" + d3-force "1" + d3-format "1" + d3-geo "1" + d3-hierarchy "1" + d3-interpolate "1" + d3-path "1" + d3-polygon "1" + d3-quadtree "1" + d3-random "1" + d3-scale "2" + d3-scale-chromatic "1" + d3-selection "1" + d3-shape "1" + d3-time "1" + d3-time-format "2" + d3-timer "1" + d3-transition "1" + d3-voronoi "1" + d3-zoom "1" + d@1, d@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a" @@ -5944,7 +6199,7 @@ husky@^3.1.0: run-node "^1.0.0" slash "^3.0.0" -iconv-lite@0.4.24, iconv-lite@^0.4.24: +iconv-lite@0.4, iconv-lite@0.4.24, iconv-lite@^0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== @@ -9937,6 +10192,13 @@ react-error-overlay@^6.0.4: resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.4.tgz#0d165d6d27488e660bc08e57bdabaad741366f7a" integrity sha512-ueZzLmHltszTshDMwyfELDq8zOA803wQ1ZuzCccXa1m57k1PxSHfflPD5W9YIiTXLs0JTLzoj6o1LuM5N6zzNA== +react-gauge-chart@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/react-gauge-chart/-/react-gauge-chart-0.4.0.tgz#4f4d15395e10f9ae29c2953bc92ec92b7de6b178" + integrity sha512-VP3e0YTSPznsFTIuG2gWGLeGMB/E+swEWY8TDFDd7+ti4d5oNHjMUyVCgTHAL0CUU2JIaE1GRmd5a6hhb4u/iA== + dependencies: + d3 "^5.12.0" + react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.4: version "16.12.0" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.12.0.tgz#2cc0fe0fba742d97fd527c42a13bec4eeb06241c" @@ -10576,6 +10838,11 @@ run-queue@^1.0.0, run-queue@^1.0.3: dependencies: aproba "^1.1.1" +rw@1: + version "1.3.3" + resolved "https://registry.yarnpkg.com/rw/-/rw-1.3.3.tgz#3f862dfa91ab766b14885ef4d01124bfda074fb4" + integrity sha1-P4Yt+pGrdmsUiF700BEkv9oHT7Q= + rx@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782"