58 Commits

Author SHA1 Message Date
6434fd0b9c Started working on test edit page; removed nodemon because it wasn't working 2025-07-02 17:34:06 -04:00
3fa86ad23d Added nodemon to dev dependencies to automatially reload the app on changes 2025-07-02 16:58:02 -04:00
190ae9f302 Fixed typo in Gruntfile; added Make tasks to compile frontend assets; Modernized the gathering of benchmark result data for the test view 2025-07-02 15:58:13 -04:00
771d26ec3b Improved some styles 2024-06-08 10:01:25 -04:00
da6397dd14 [Issue #8] - Licensing project under the BSD 2-Clause license (#10)
Adding license to project

Co-authored-by: Gregory Ballantine <gballantine@bitgoblin.tech>
Reviewed-on: #10
2024-05-31 09:28:23 -04:00
8e20e5e354 3-add-gruntjs (#9)
Adding Grunt.js to compile SASS and CoffeeScript assets

Co-authored-by: Gregory Ballantine <gregory.w.ballantine@nasa.gov>
Co-authored-by: Gregory Ballantine <gballantine555@gmail.com>
Reviewed-on: #9
2024-05-31 09:00:18 -04:00
Gregory Ballantine
533c407183 Updated some styles for tables and links 2024-05-29 15:07:54 -04:00
Gregory Ballantine
fb76f28643 Added tests to hardware page 2024-05-29 12:33:45 -04:00
Gregory Ballantine
06262431da Updated some styles 2024-05-29 12:10:27 -04:00
Gregory Ballantine
e734d4077d Updated some styles 2024-05-29 12:08:58 -04:00
Gregory Ballantine
9617f4280d Fixed results table in test view 2024-05-29 12:04:08 -04:00
Gregory Ballantine
3ec5605c53 Fixed results table in test view 2024-05-29 12:02:45 -04:00
Gregory Ballantine
ed5232371c Fixed results table in test view 2024-05-29 12:00:04 -04:00
Gregory Ballantine
29d9cbc59c Fixed results table in test view 2024-05-29 11:57:49 -04:00
Gregory Ballantine
3eca29c2db Added back reference associations for result; added table of results to test view 2024-05-29 11:52:01 -04:00
Gregory Ballantine
8df9b7684f added missing import 2024-05-29 11:43:42 -04:00
Gregory Ballantine
7282d0a4b6 Fixed result form stuff 2024-05-29 11:43:17 -04:00
Gregory Ballantine
0525838f4b Fixed float variable types 2024-05-29 11:41:53 -04:00
Gregory Ballantine
958c72ee63 Added result creation route 2024-05-29 11:40:42 -04:00
Gregory Ballantine
fa92321176 Added result model; added form to submit results 2024-05-29 11:26:42 -04:00
Gregory Ballantine
458646ee8e Added result model; added form to submit results 2024-05-29 11:26:17 -04:00
Gregory Ballantine
9df8f6c9e1 Added result model; added form to submit results 2024-05-29 11:25:45 -04:00
Gregory Ballantine
7e294c8f72 Cleaned up runtime version 2024-05-29 11:09:55 -04:00
Gregory Ballantine
cefa79a8b8 Added Go runtime version to the layout footer 2024-05-29 11:05:02 -04:00
Gregory Ballantine
1e87466ccb Added Go runtime version to the layout footer 2024-05-29 11:04:31 -04:00
Gregory Ballantine
e3e4e24e56 Fixed associating benchmarks to test 2024-05-29 10:07:15 -04:00
Gregory Ballantine
2be6d216d1 Fixed creating new test 2024-05-29 09:52:41 -04:00
Gregory Ballantine
93170d0935 Fixed creating new test 2024-05-29 09:47:49 -04:00
Gregory Ballantine
2299ac0a93 Added more information to the test view page 2024-05-29 09:23:41 -04:00
Gregory Ballantine
3ec465872e Fixed typo in test view route 2024-05-29 09:19:53 -04:00
Gregory Ballantine
52e4d9c420 Fixed typos in benchmark list view 2024-05-29 09:17:07 -04:00
Gregory Ballantine
9ddf7fa928 Fixed typos in model searches 2024-05-29 09:16:32 -04:00
Gregory Ballantine
ab6b94cb5f Fixed typo in benchmark list view 2024-05-29 09:14:09 -04:00
Gregory Ballantine
39185f1144 Fixed benchmark form submission error 2024-05-29 09:13:10 -04:00
Gregory Ballantine
403ab7f166 Fixed mix up between benchmark and hardware routes files 2024-05-29 09:12:19 -04:00
Gregory Ballantine
ba06a2ea4c Added benchmarks routes and views 2024-05-29 09:11:13 -04:00
Gregory Ballantine
95fe5ab400 Slight tweak to create test view 2024-05-29 09:03:14 -04:00
Gregory Ballantine
9ddc3db48d Fixed form select field styling 2024-05-29 09:02:00 -04:00
Gregory Ballantine
8412163370 Fixed variable capitalization in create test view 2024-05-29 09:00:14 -04:00
Gregory Ballantine
86bf4d37f0 Added description field to Test model 2024-05-29 08:58:30 -04:00
Gregory Ballantine
6cb2ac0263 Passed hardware components and benchmarks to create test view 2024-05-29 08:57:52 -04:00
Gregory Ballantine
dea08d15dd Added route to view test 2024-05-29 08:45:53 -04:00
Gregory Ballantine
cf7623fbb9 Added route to view test 2024-05-29 08:43:57 -04:00
Gregory Ballantine
a51c8aa8a4 Added route to view test 2024-05-29 08:42:53 -04:00
Gregory Ballantine
9fd6ec6b0b Added route to view hardware component 2024-05-29 08:40:02 -04:00
Gregory Ballantine
5b14721b14 Added route to view hardware component 2024-05-29 08:39:27 -04:00
Gregory Ballantine
dcfc6e0115 Added route to view hardware component 2024-05-29 08:37:51 -04:00
4ad9a92306 Added hardware routes and views 2023-12-02 22:37:46 -05:00
c5df026d04 Lots of changes 2023-12-02 22:16:16 -05:00
16704aeeb1 Added ability to create projects 2023-11-28 16:36:11 -05:00
Gregory Ballantine
bae65994f8 Refactored models code to follow a better approach for opening and closing the database connection 2023-11-28 14:40:12 -05:00
19670e9abd Added models; started working on project routes 2023-11-27 23:41:48 -05:00
49925c6d8f Added Gorm to project 2023-11-27 22:36:58 -05:00
0ee3d06f89 Copied some styles from Leviathan 2023-11-27 22:26:36 -05:00
9dceaa8119 Started working on the layout of the app 2023-11-24 23:34:50 -05:00
cbc816ad70 Updated Makefile to auto-define version 2023-11-24 14:28:53 -05:00
92d8e5fa09 Added templating, versioning, middleware, etc 2023-11-24 14:27:23 -05:00
cd7003223a Better start for Flamego 2023-11-24 13:25:24 -05:00
18 changed files with 6 additions and 368 deletions

1
.gitignore vendored
View File

@@ -3,7 +3,6 @@ blt
# Local data files # Local data files
data/ data/
tmp/
# Compiled assets # Compiled assets
public/css/ public/css/

View File

@@ -1,32 +0,0 @@
steps:
build:
image: golang:1.22
commands:
- go mod vendor
- GOOS=linux GOARCH=amd64 go build -o "dist/blt-linux-amd64-${CI_COMMIT_TAG}.bin"
- GOOS=windows GOARCH=amd64 go build -o "dist/blt-windows-amd64-${CI_COMMIT_TAG}.exe"
assets:
image: node:24
commands:
- npm install
- npm run grunt build
package:
image: alpine
commands:
- tar -cvzf "dist/blt-assets-${CI_COMMIT_TAG}.tar.gz" public/
when:
event: tag
gitea_release:
image: plugins/gitea-release
settings:
api_key:
from_secret: gitea_api_key
base_url: https://git.metaunix.net
title: "${CI_COMMIT_TAG}"
files:
- dist/blt-*
when:
event: tag

View File

@@ -60,8 +60,6 @@ module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-coffee'); grunt.loadNpmTasks('grunt-contrib-coffee');
// CLI tasks. // CLI tasks.
grunt.registerTask('build', ['sass', 'coffee']); grunt.registerTask('default', ['sass', 'coffee']);
grunt.registerTask('dev', ['watch']);
grunt.registerTask('default', ['build']);
}; };

View File

@@ -1,54 +0,0 @@
# Benchmark Logging Tool (BLT)
![Build badge](https://builds.metaunix.net/api/badges/87/status.svg)
Web-based tool to store and organize PC hardware benchmarks.
## Project Goals
The goals of this project are to:
* Record benchmarking results from multiple devices - e.g. log from a laptop or a phone.
* Group results into tests to keep track of different testing configurations.
* Encourage running tests multiple times - it's good practice to run a benchmark multiple times for accuracy.
* Create comparisons of hardware tests to compare performance.
* Generate graphs of hardware comparisons for usage in videos and articles.
## Requirements
BLT runs on Go. It uses the built-in `go mod` tool to manage dependencies, thus there is no external tooling to install to build/run BLT.
Debian/Ubuntu: `apt install -y golang`
RedHat and clones: `dnf install -y golang`
## Production Deployment
**TODO**
## Development
### Via Docker
**TODO**
### Local/Native Development
BLT uses [fresh](https://github.com/gravityblast/fresh) to auto-reload the app. While this is not strictly necessary, it used to make development more convenient. If you wish to forego installing it, you may simply build and run the app with the standard `go run main.go`.
1. Install dependencies:
`go mod download`
2. Install fresh to auto-reload the app:
`go install github.com/gravityblast/fresh@latest`
3. Run the app via air:
`fresh`
4. If everything is running successfully you can open your browser and go to http://localhost:2830.
## License
This project is available under the BSD 2-Clause license.

View File

@@ -1,8 +1,6 @@
package models package models
import ( import (
"strconv"
"gorm.io/gorm" "gorm.io/gorm"
) )
@@ -18,7 +16,3 @@ type Benchmark struct {
// has many results // has many results
Results []Result Results []Result
} }
func (b *Benchmark) StringID() string {
return strconv.Itoa(int(b.ID))
}

View File

@@ -1,8 +1,6 @@
package models package models
import ( import (
"strconv"
"gorm.io/gorm" "gorm.io/gorm"
) )
@@ -21,24 +19,3 @@ type Test struct {
// has many results // has many results
Results []Result Results []Result
} }
func (t *Test) SelectedBenchmarks() []string {
benchmarks := t.Benchmarks
ids := make([]string, len(benchmarks))
for i, b := range benchmarks {
ids[i] = strconv.Itoa(int(b.ID))
}
return ids
}
func (t *Test) IsBenchmarkSelected(benchmarkID uint) bool {
benchmarkUint := uint(benchmarkID)
for _, b := range t.Benchmarks {
if b.ID == benchmarkUint {
return true
}
}
return false
}

View File

@@ -1,14 +0,0 @@
root: .
tmp_path: ./tmp
build_name: runner-build
build_log: runner-build-errors.log
valid_ext: .go, .tpl, .tmpl, .html
no_rebuild_ext: .tpl, .tmpl, .html
ignored: assets, tmp, node_modules, data, vendor
build_delay: 600
colors: 1
log_color_main: cyan
log_color_build: yellow
log_color_runner: green
log_color_watcher: magenta
log_color_app:

View File

@@ -1,38 +0,0 @@
{{ template "header" . }}
<div class="row">
<h2>Editing Benchmark: {{ .benchmark.Name }}</h2>
<form class="twelve columns" action="/benchmark/{{ .benchmark.ID }}/edit" method="POST">
<div class="row">
<div class="nine columns">
<label for="benchmark_name">
Benchmark name:
<input id="benchmark_name" class="u-full-width" type="text" name="benchmark_name" placeholder="Unigine Heaven" value="{{ .benchmark.Name }}">
</label>
</div>
<div class="three columns">
<label for="benchmark_scoring">
Benchmark type:
<select id="benchmark_scoring" class="u-full-width" name="benchmark_scoring">
<option value="fps" {{ if eq .benchmark.ScoringType "fps" }}selected{{ end }}>Frames per second</option>
<option value="ms" {{ if eq .benchmark.ScoringType "ms" }}selected{{ end }}>Frame time</option>
<option value="pts" {{ if eq .benchmark.ScoringType "pts" }}selected{{ end }}>Total points</option>
</select>
</label>
</div>
</div>
<div class="row">
<label for="benchmark_description">
Benchmark description:
<textarea id="benchmark_description" class="twelve columns" cols="30" rows="10" name="benchmark_description">{{ .benchmark.Description }}</textarea>
</label>
</div>
<input class="button-primary u-full-width" type="submit" value="Submit">
</form>
</div>
{{ template "footer" . }}

View File

@@ -3,12 +3,8 @@
<div class="row"> <div class="row">
<h2>{{ .benchmark.Name }}</h2> <h2>{{ .benchmark.Name }}</h2>
<span><a href="/benchmark/{{ .benchmark.ID }}/edit">Edit</a></span>
<p>{{ .benchmark.ScoringType }}</p> <p>{{ .benchmark.ScoringType }}</p>
<p>{{ .benchmark.Description }}</p>
<hr> <hr>
<h4>Latest Benchmark Results:</h4> <h4>Latest Benchmark Results:</h4>

View File

@@ -1,34 +0,0 @@
{{ template "header" . }}
<div class="row">
<h2>Add new hardware</h2>
<form class="twelve columns" action="/hardware/{{ .hardware.ID }}/edit" method="POST">
<div class="row">
<div class="nine columns">
<label for="hardware_name">
Hardware name:
<input id="hardware_name" class="u-full-width" type="text" name="hardware_name" placeholder="EVGA RTX 3080 Ti" value="{{ .hardware.Name }}">
</label>
</div>
<div class="three columns">
<label for="hardware_type">
Hardware type:
<select id="hardware_type" class="u-full-width" name="hardware_type">
<option value="cpu" {{ if eq .hardware.Type "cpu" }}selected{{ end }}>Processor</option>
<option value="mem" {{ if eq .hardware.Type "mem" }}selected{{ end }}>Memory</option>
<option value="gpu" {{ if eq .hardware.Type "gpu" }}selected{{ end }}>Graphics Card</option>
<option value="ssd" {{ if eq .hardware.Type "ssd" }}selected{{ end }}>Solid State Drive</option>
<option value="hdd" {{ if eq .hardware.Type "hdd" }}selected{{ end }}>Hard Drive</option>
<option value="nic" {{ if eq .hardware.Type "nic" }}selected{{ end }}>Network Card</option>
</select>
</label>
</div>
</div>
<input class="button-primary u-full-width" type="submit" value="Submit">
</form>
</div>
{{ template "footer" . }}

View File

@@ -3,8 +3,6 @@
<div class="row"> <div class="row">
<h2>{{ .hardware.Name }}</h2> <h2>{{ .hardware.Name }}</h2>
<span><a href="/hardware/{{ .hardware.ID }}/edit">Edit</a></span>
<p>{{ .hardware.Type }}</p> <p>{{ .hardware.Type }}</p>
<hr> <hr>

View File

@@ -30,9 +30,9 @@
<label for="test_benchmarks"> <label for="test_benchmarks">
Benchmarks to Test: Benchmarks to Test:
<select id="test_benchmarks" class="u-full-width" name="test_benchmarks" multiple> <select id="test_benchmarks" class="u-full-width" name="test_benchmarks" multiple>
{{ $selectedBenchmarks := .selectedBenchmarks }} {{ $testBenchmarks := .test.Benchmarks }}
{{ range $bm := .benchmarks }} {{ range $bm := .benchmarks }}
<option value="{{ $bm.ID }}" {{ if contains $selectedBenchmarks $bm.StringID }}selected{{ end }}>{{ $bm.Name }}</option> <option value="{{ $bm.ID }}" {{ if contains $testBenchmarks $bm.ID }}selected{{ end }}>{{ $bm.Name }}</option>
{{ end }} {{ end }}
</select> </select>
</label> </label>

View File

@@ -3,15 +3,11 @@
<div class="row"> <div class="row">
<h2>{{ .test.Name }}</h2> <h2>{{ .test.Name }}</h2>
<span><a href="/test/{{ .test.ID }}/edit">Edit</a></span> <p>Hardware tested: <a href="/hardware/{{ .test.Hardware.ID }}">{{ .test.Hardware.Name }}</a></p>
<p>{{ .test.Description }}</p> <p>{{ .test.Description }}</p>
<h4>Test Info:</h4> <h4>Benchmarks used:</h4>
<p>Hardware tested: <a href="/hardware/{{ .test.Hardware.ID }}">{{ .test.Hardware.Name }}</a></p>
<p>Benchmarks used:</p>
<ul> <ul>
{{ range $bm := .test.Benchmarks }} {{ range $bm := .test.Benchmarks }}

View File

@@ -4,15 +4,5 @@ type TestForm struct {
Name string `form:"test_name" validate:"required"` Name string `form:"test_name" validate:"required"`
Description string `form:"test_description"` Description string `form:"test_description"`
Hardware int `form:"test_hardware" validate:"required"` Hardware int `form:"test_hardware" validate:"required"`
Benchmarks []uint `form:"test_benchmarks" validate:"required"` Benchmarks []string `form:"test_benchmarks" validate:"required"`
}
func (t *TestForm) IsBenchmarkSelected(checkID uint) bool {
for _, selectedID := range t.Benchmarks {
if checkID == selectedID {
return true
}
}
return false
} }

View File

@@ -24,9 +24,6 @@ func RegisterRoutes(f *flamego.Flame) {
f.Post("/create", binding.Form(forms.HardwareForm{}), routes.HardwarePostCreate) f.Post("/create", binding.Form(forms.HardwareForm{}), routes.HardwarePostCreate)
f.Get("/{hardware_id}", routes.HardwareGetView) f.Get("/{hardware_id}", routes.HardwareGetView)
f.Get("/{hardware_id}/edit", routes.HardwareGetEdit)
f.Post("/{hardware_id}/edit", binding.Form(forms.HardwareForm{}), routes.HardwarePostEdit)
}) })
// benchmark routes // benchmark routes
@@ -41,9 +38,6 @@ func RegisterRoutes(f *flamego.Flame) {
f.Post("/create", binding.Form(forms.BenchmarkForm{}), routes.BenchmarkPostCreate) f.Post("/create", binding.Form(forms.BenchmarkForm{}), routes.BenchmarkPostCreate)
f.Get("/{benchmark_id}", routes.BenchmarkGetView) f.Get("/{benchmark_id}", routes.BenchmarkGetView)
f.Get("/{benchmark_id}/edit", routes.BenchmarkGetEdit)
f.Post("/{benchmark_id}/edit", binding.Form(forms.BenchmarkForm{}), routes.BenchmarkPostEdit)
}) })
// test routes // test routes
@@ -60,7 +54,6 @@ func RegisterRoutes(f *flamego.Flame) {
f.Group("/{test_id}", func() { f.Group("/{test_id}", func() {
f.Get("", routes.TestGetView) f.Get("", routes.TestGetView)
f.Get("/edit", routes.TestGetEdit) f.Get("/edit", routes.TestGetEdit)
f.Post("/edit", binding.Form(forms.TestForm{}), routes.TestPostEdit)
}) })
}) })

View File

@@ -64,44 +64,3 @@ func BenchmarkPostCreate(c flamego.Context, form forms.BenchmarkForm, errs bindi
c.Redirect(fmt.Sprintf("/benchmark/%d", benchmark.ID)) c.Redirect(fmt.Sprintf("/benchmark/%d", benchmark.ID))
} }
func BenchmarkGetEdit(c flamego.Context, t template.Template, data template.Data) {
// find benchmark ID from request
benchmarkID := c.Param("benchmark_id")
// find benchmark from DB
var benchmark models.Benchmark
models.DB.First(&benchmark, benchmarkID)
data["benchmark"] = benchmark
data["title"] = "Editing Benchmark"
t.HTML(http.StatusOK, "benchmark/edit")
}
func BenchmarkPostEdit(c flamego.Context, form forms.BenchmarkForm, errs binding.Errors) {
if len(errs) > 0 {
var err error
switch errs[0].Category {
case binding.ErrorCategoryValidation:
err = errs[0].Err.(validator.ValidationErrors)[0]
default:
err = errs[0].Err
}
log.Fatal(err)
}
// find benchmark ID from request
benchmarkID := c.Param("benchmark_id")
// find benchmark from DB
var benchmark models.Benchmark
models.DB.First(&benchmark, benchmarkID)
benchmark.Name = form.Name
benchmark.ScoringType = form.ScoringType
benchmark.Description = form.Description
models.DB.Save(&benchmark)
c.Redirect(fmt.Sprintf("/benchmark/%d", benchmark.ID))
}

View File

@@ -63,43 +63,3 @@ func HardwarePostCreate(c flamego.Context, form forms.HardwareForm, errs binding
c.Redirect(fmt.Sprintf("/hardware/%d", hardware.ID)) c.Redirect(fmt.Sprintf("/hardware/%d", hardware.ID))
} }
func HardwareGetEdit(c flamego.Context, t template.Template, data template.Data) {
// find hardware ID from request
hardwareID := c.Param("hardware_id")
// find hardware from DB
var hardware models.Hardware
models.DB.Preload("Tests.Benchmarks").First(&hardware, hardwareID)
data["hardware"] = hardware
data["title"] = "Edit Hardware"
t.HTML(http.StatusOK, "hardware/edit")
}
func HardwarePostEdit(c flamego.Context, form forms.HardwareForm, errs binding.Errors) {
if len(errs) > 0 {
var err error
switch errs[0].Category {
case binding.ErrorCategoryValidation:
err = errs[0].Err.(validator.ValidationErrors)[0]
default:
err = errs[0].Err
}
log.Fatal(err)
}
// find hardware ID from request
hardwareID := c.Param("hardware_id")
// find hardware from DB
var hardware models.Hardware
models.DB.Preload("Tests.Benchmarks").First(&hardware, hardwareID)
hardware.Name = form.Name
hardware.Type = form.Type
models.DB.Save(&hardware)
c.Redirect(fmt.Sprintf("/hardware/%d", hardware.ID))
}

View File

@@ -99,56 +99,6 @@ func TestGetEdit(c flamego.Context, t template.Template, data template.Data) {
models.DB.Find(&benchmarks) models.DB.Find(&benchmarks)
data["benchmarks"] = benchmarks data["benchmarks"] = benchmarks
// determine which benchmarks are selected in a test
selectedBenchmarks := test.SelectedBenchmarks()
data["selectedBenchmarks"] = selectedBenchmarks
data["title"] = fmt.Sprintf("Editing Test: %s", test.Name) data["title"] = fmt.Sprintf("Editing Test: %s", test.Name)
t.HTML(http.StatusOK, "test/edit") t.HTML(http.StatusOK, "test/edit")
} }
func TestPostEdit(c flamego.Context, form forms.TestForm, errs binding.Errors) {
if len(errs) > 0 {
var err error
switch errs[0].Category {
case binding.ErrorCategoryValidation:
err = errs[0].Err.(validator.ValidationErrors)[0]
default:
err = errs[0].Err
}
log.Fatal(err)
}
// find test ID from request
testID := c.Param("test_id")
// find hardware from DB
var test models.Test
models.DB.Preload("Hardware").Preload("Benchmarks").First(&test, testID)
test.Name = form.Name
test.Description = form.Description
test.HardwareID = form.Hardware
// bind benchmarks to test that aren't already associated
for _, b := range form.Benchmarks {
if ! test.IsBenchmarkSelected(b) {
var benchmark models.Benchmark
models.DB.First(&benchmark, b) // find benchmark
models.DB.Model(&test).Association("Benchmarks").Append(&benchmark)
}
}
// removed associated benchmarks that weren't in the form
for _, b := range test.Benchmarks {
if ! form.IsBenchmarkSelected(b.ID) {
var benchmark models.Benchmark
models.DB.First(&benchmark, b) // find benchmark
models.DB.Model(&test).Association("Benchmarks").Delete(&benchmark)
}
}
models.DB.Save(&test)
c.Redirect(fmt.Sprintf("/test/%d", test.ID))
}