49 Commits

Author SHA1 Message Date
Gregory Ballantine 886f566ae2 Started work to move the CSS framework to Bootstrap 5
ci/woodpecker/push/woodpecker Pipeline failed
ci/woodpecker/tag/woodpecker Pipeline failed
2025-07-25 17:44:25 -04:00
Gregory Ballantine fdd350e16f Updated gulpfile to be a little bit less repetitive
ci/woodpecker/push/woodpecker Pipeline failed
2025-07-25 13:41:51 -04:00
gballan bc4cb181c3 Added some styles
ci/woodpecker/push/woodpecker Pipeline failed
2025-07-23 23:54:12 -04:00
gballan 822f49bcc2 fixed display of tests on the dashboard 2025-07-23 23:26:22 -04:00
gballan aec77628f7 Small updates
ci/woodpecker/push/woodpecker Pipeline failed
2025-07-23 23:25:00 -04:00
gballan ecb696372d Added dockerfile to build assets via Gulp; updated docker scripts 2025-07-23 23:24:49 -04:00
gballan 31b8404be1 Swapping out Grunt for Gulp 2025-06-22 19:30:17 -04:00
gballan 8cd47d7e70 Added API routes to provide some information for JS; added CoffeeScript to grab benchmark results for a test 2025-06-19 00:38:36 -04:00
gballan d17b66920a Fixed typo in watch task for CoffeeScript files 2025-06-18 16:44:10 -04:00
gballan 47cb580393 Started adding test model/routes/views; removed a bit of the old paradigm with tying results directly to hardware 2025-06-10 17:35:52 -04:00
gballan 883019b181 Fixing server:dev Rake command to actuualy reload the app 2025-06-09 23:27:48 -04:00
gballan 2cc80e239b Added TTY flag to docker-run.bat 2025-05-30 09:38:20 -04:00
gballan ed085e4b40 Added abilities to view and edit benchmark info 2025-05-30 01:45:49 -04:00
gballan cf9235cb18 Added ability to edit hardware 2025-05-30 01:30:36 -04:00
gballan 28b6cc66bb Updating dependencies to newer versions; Updating to Ruby 3.4 2025-05-30 01:20:43 -04:00
gballan e3a334546f Transitioned to using SASS and CoffeeScript for assets; using Grunt.js for compiling
ci/woodpecker/push/woodpecker Pipeline was successful
2024-06-12 22:19:46 -04:00
gballan d899ffe58a Adding bundle config to project
ci/woodpecker/push/woodpecker Pipeline was successful
2024-06-12 19:58:08 -04:00
gballan e6853a52d7 Fixed some alignment issues on the benchmark add page
ci/woodpecker/push/woodpecker Pipeline was successful
2024-02-26 15:53:13 -05:00
gballan 6d26eea419 Added shell scripts for managing the docker container
ci/woodpecker/push/woodpecker Pipeline was successful
2024-02-26 00:10:42 -05:00
gballan 778bd25ef2 Fixed awful FirstHashElementIndentation setting
ci/woodpecker/push/woodpecker Pipeline was successful
2024-02-09 15:45:16 -05:00
gballan 6aca95d832 Added rudimentary chart generation for benchmarks
ci/woodpecker/push/woodpecker Pipeline was successful
2024-02-09 15:39:49 -05:00
gballan 357bb69257 Fixed linter errors
ci/woodpecker/push/woodpecker Pipeline was successful
2024-02-09 13:59:44 -05:00
gballan 1e0cd49cf8 Added ability to add benchmark results from hardware page
ci/woodpecker/push/woodpecker Pipeline was successful
2024-02-09 13:57:01 -05:00
gballan 5628c69d66 Fix style linting
ci/woodpecker/push/woodpecker Pipeline was successful
2024-02-09 10:05:10 -05:00
gballan e6333b855f Added form to hardware view page for adding test results
ci/woodpecker/push/woodpecker Pipeline was successful
2024-02-09 10:03:27 -05:00
gballan f7979cd005 Removed more references to test
ci/woodpecker/push/woodpecker Pipeline was successful
2024-02-09 08:42:49 -05:00
gballan ef2e0a12a5 Removed Test object to simplify database schema; updated docker scripts to run database migrations before starting the server if the database doesn't exist
ci/woodpecker/push/woodpecker Pipeline was successful
2024-02-09 08:40:34 -05:00
gballan c83d517437 Updating Gem versions
ci/woodpecker/push/woodpecker Pipeline was successful
2024-02-09 07:19:30 -05:00
gballan 8dee8b1f40 Added docker support for development environment
ci/woodpecker/push/woodpecker Pipeline was successful
2024-02-09 07:17:14 -05:00
gballan 175ce24b27 Started work to redo the UI for database changes
ci/woodpecker/push/woodpecker Pipeline was successful
2023-12-21 01:29:59 -05:00
gballan 516f125ea7 Fixed a lot of linter warnings
ci/woodpecker/push/woodpecker Pipeline was successful
2023-12-11 13:08:46 -05:00
gballan 34741691ed Fixed Rubocop all
ci/woodpecker/push/woodpecker Pipeline was successful
2023-12-08 15:21:11 -05:00
Gregory Ballantine fa9245d7ec Added rubocop for style checking; added woodpecker CI config
ci/woodpecker/manual/woodpecker Pipeline was successful
2023-12-08 12:17:13 -05:00
gballan 1a363a5862 Improved the db:migrate function in the Rakefile to utilize the Sequel API for running migrations, and to allow downgrading to a specific migration easily 2023-12-07 13:04:02 -05:00
gballan b819f4f1cd Reworked database schema from scratch 2023-12-07 12:59:32 -05:00
gballan 394a8ef91f Modified the Rakefile to make the rerun command a lot better 2023-11-29 22:01:44 -05:00
gballan c940a248d7 [Issue #5] - Reworked app to better organize results with their corresponding tests 2023-09-21 20:41:25 -06:00
gballan 269587e6c9 Updated README 2023-09-20 23:04:05 -06:00
gballan 3c9e6eab6b Removed unnecessary score formatting from result add 2023-09-08 07:15:54 -06:00
gballan a1a00d9fe5 Added functionality for better tracking of the minimum and maximum fps 2023-09-08 00:36:40 -06:00
gballan 7e38154bc1 Fixed the table on the dashboard 2023-09-03 09:26:09 -04:00
gballan f0115847b8 Fixed a couple of things missing from result displays 2023-09-03 09:02:31 -04:00
gballan b8bec03357 Removed the setup rake task to run bundler and replaced it with a shell script 2023-07-06 11:49:48 -04:00
gballan 7655b75410 Added functionality to add a benchmark result 2023-07-05 23:39:08 -04:00
gballan 691e2e9b1e Added module for helper functions; added helper for formatting date consistently 2023-07-05 22:27:07 -04:00
gballan 291db231d5 Added functionality to add new hardware and benchmarks to tie to results (this may be moved to an admin panel later) 2023-07-05 22:08:37 -04:00
gballan 6c1c8bca0a Added Sequel ORM for database handling; added navbar 2023-07-05 18:04:31 -04:00
gballan 6f680e72e5 Added some more scaffolding to the project to get going; added Foundation css to start with styles 2023-07-03 23:02:25 -04:00
gballan b376bf3a79 Added started adding some Sinatra app stuff 2023-07-02 23:42:24 -04:00
65 changed files with 4811 additions and 3 deletions
+2
View File
@@ -0,0 +1,2 @@
---
BUNDLE_PATH: "vendor/bundle"
+9
View File
@@ -56,3 +56,12 @@ build-iPhoneSimulator/
# Used by RuboCop. Remote config files pulled in from inherit_from directive. # Used by RuboCop. Remote config files pulled in from inherit_from directive.
# .rubocop-https?--* # .rubocop-https?--*
# Ignore local data
data/
# Node modules
node_modules/
# Compiled assets
public/css/
public/js/
+23
View File
@@ -0,0 +1,23 @@
require: rubocop-sequel
AllCops:
NewCops: enable
Layout/EmptyLinesAroundClassBody:
EnforcedStyle: 'empty_lines_except_namespace'
Layout/EmptyLinesAroundModuleBody:
EnforcedStyle: 'empty_lines_except_namespace'
Layout/FirstHashElementIndentation:
EnforcedStyle: 'consistent'
Metrics/ClassLength:
Max: 150
Style/ClassVars:
Enabled: false
Style/GlobalVars:
Enabled: false
Style/MethodCallWithoutArgsParentheses:
Enabled: false
Style/MethodCallWithArgsParentheses:
Enabled: true
Style/RedundantReturn:
Enabled: false
+19
View File
@@ -0,0 +1,19 @@
pipeline:
style:
image: ruby:3.0
commands:
- 'gem install rake'
- 'bundle config set --local path "vendor/bundle"'
- 'bundle install'
- 'rake test:rubocop'
gitea_release:
image: plugins/gitea-release
settings:
api_key:
from_secret: gitea_api_key
base_url: https://git.metaunix.net
title: "${CI_COMMIT_TAG}"
when:
event: tag
+16
View File
@@ -0,0 +1,16 @@
FROM ruby:3.4
RUN gem install bundler
WORKDIR /usr/src/game-data
COPY Gemfile Gemfile.l*ck ./
RUN bundle check || bundle install
RUN gem install rake
COPY . ./
ENTRYPOINT ["bash", "entrypoints/dev.sh"]
+13
View File
@@ -0,0 +1,13 @@
# Node.js runtime
FROM node:24
WORKDIR /usr/src/game-data/
COPY package.* /usr/src/game-data/
RUN npm install
VOLUME /usr/src/game-data/node_modules/
# Run the app
CMD [ "npm", "run", "gulp" ]
+19
View File
@@ -0,0 +1,19 @@
source 'https://rubygems.org'
gem 'sinatra', '~> 3.2'
gem 'sinatra-contrib', '~> 3.2'
gem 'puma', '~> 6.6'
gem 'sequel', '~> 5.92'
gem 'sqlite3', '~> 2.6'
gem 'logger'
group :development, :test do
gem 'rerun'
gem 'wdm', '>= 0.1.0' if Gem.win_platform?
# rubocop and extensions for code style
gem 'rubocop'
gem 'rubocop-sequel'
end
+118
View File
@@ -0,0 +1,118 @@
GEM
remote: https://rubygems.org/
specs:
ast (2.4.3)
base64 (0.3.0)
bigdecimal (3.2.2)
ffi (1.17.2-aarch64-linux-gnu)
ffi (1.17.2-aarch64-linux-musl)
ffi (1.17.2-arm-linux-gnu)
ffi (1.17.2-arm-linux-musl)
ffi (1.17.2-arm64-darwin)
ffi (1.17.2-x86-linux-gnu)
ffi (1.17.2-x86-linux-musl)
ffi (1.17.2-x86_64-darwin)
ffi (1.17.2-x86_64-linux-gnu)
ffi (1.17.2-x86_64-linux-musl)
json (2.12.2)
language_server-protocol (3.17.0.5)
lint_roller (1.1.0)
listen (3.9.0)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
logger (1.7.0)
multi_json (1.15.0)
mustermann (3.0.3)
ruby2_keywords (~> 0.0.1)
nio4r (2.7.4)
parallel (1.27.0)
parser (3.3.8.0)
ast (~> 2.4.1)
racc
prism (1.4.0)
puma (6.6.0)
nio4r (~> 2.0)
racc (1.8.1)
rack (2.2.17)
rack-protection (3.2.0)
base64 (>= 0.1.0)
rack (~> 2.2, >= 2.2.4)
rainbow (3.1.1)
rb-fsevent (0.11.2)
rb-inotify (0.11.1)
ffi (~> 1.0)
regexp_parser (2.10.0)
rerun (0.14.0)
listen (~> 3.0)
rubocop (1.76.1)
json (~> 2.3)
language_server-protocol (~> 3.17.0.2)
lint_roller (~> 1.1.0)
parallel (~> 1.10)
parser (>= 3.3.0.2)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 2.9.3, < 3.0)
rubocop-ast (>= 1.45.0, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 4.0)
rubocop-ast (1.45.1)
parser (>= 3.3.7.2)
prism (~> 1.4)
rubocop-sequel (0.4.1)
lint_roller (~> 1.1)
rubocop (>= 1.72.1, < 2)
ruby-progressbar (1.13.0)
ruby2_keywords (0.0.5)
sequel (5.93.0)
bigdecimal
sinatra (3.2.0)
mustermann (~> 3.0)
rack (~> 2.2, >= 2.2.4)
rack-protection (= 3.2.0)
tilt (~> 2.0)
sinatra-contrib (3.2.0)
multi_json (>= 0.0.2)
mustermann (~> 3.0)
rack-protection (= 3.2.0)
sinatra (= 3.2.0)
tilt (~> 2.0)
sqlite3 (2.7.0-aarch64-linux-gnu)
sqlite3 (2.7.0-aarch64-linux-musl)
sqlite3 (2.7.0-arm-linux-gnu)
sqlite3 (2.7.0-arm-linux-musl)
sqlite3 (2.7.0-arm64-darwin)
sqlite3 (2.7.0-x86-linux-gnu)
sqlite3 (2.7.0-x86-linux-musl)
sqlite3 (2.7.0-x86_64-darwin)
sqlite3 (2.7.0-x86_64-linux-gnu)
sqlite3 (2.7.0-x86_64-linux-musl)
tilt (2.6.0)
unicode-display_width (3.1.4)
unicode-emoji (~> 4.0, >= 4.0.4)
unicode-emoji (4.0.4)
PLATFORMS
aarch64-linux-gnu
aarch64-linux-musl
arm-linux-gnu
arm-linux-musl
arm64-darwin
x86-linux-gnu
x86-linux-musl
x86_64-darwin
x86_64-linux-gnu
x86_64-linux-musl
DEPENDENCIES
logger
puma (~> 6.6)
rerun
rubocop
rubocop-sequel
sequel (~> 5.92)
sinatra (~> 3.2)
sinatra-contrib (~> 3.2)
sqlite3 (~> 2.6)
BUNDLED WITH
2.6.9
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright (c) <year> <owner> Copyright (c) 2023 Bit Goblin
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+33 -2
View File
@@ -1,3 +1,34 @@
# game-data # Game Data
Web-based tool to store and organize PC hardware gaming benchmarks Web-based tool to store and organize PC hardware gaming 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 - 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
Game Data runs on Ruby, and takes advantage of Bundler to manage code dependencies and Rake to run various tasks for maintaining the app. You can install them globally like so:
Debian/Ubuntu: `apt install -y ruby ruby-bundler rake`
## Development
Install dependencies via bundler:
`bundle install`
Perform database migrations:
`rake db:migrate`
Run the server in development with auto-reloading:
`rake server:dev`
If everything is running successfully you can open your browser and go to https://localhost:9292.
+31
View File
@@ -0,0 +1,31 @@
require 'bundler/setup'
namespace :db do
desc 'Run migrations'
task :migrate, [:version] do |t, args|
require "sequel/core"
Sequel.extension :migration
version = args[:version].to_i if args[:version]
Sequel.connect('sqlite://data/gamedata.db') do |db|
Sequel::Migrator.run(db, "db/migrations", target: version)
end
end
end
namespace :server do
task :start do
ENV['APP_ENV'] = 'production'
system("puma")
end
task :dev do
system('rerun --no-notify --dir="src/" puma')
end
end
namespace :test do
task :rubocop do
system("rubocop src/")
end
end
+3
View File
@@ -0,0 +1,3 @@
$ ->
# run foundation scripts
$(document).foundation()
+55
View File
@@ -0,0 +1,55 @@
$(document).ready ->
$('#generate_button').on 'click', (e) ->
e.preventDefault()
$.ajax(
method: 'POST'
url: '/reports'
data:
type: $('#report_type').val()
choice: $('#report_choice').val()
compare: $('#report_compare').val()
).done (data) ->
benchChart.options.title.text = data.choice
benchChart.data.labels = data.names
benchChart.data.datasets[0].data = data.avg_results
benchChart.data.datasets[1].data = data.min_results
benchChart.update()
return
return
return
benchChart = new Chart(document.getElementById('chart_canvas').getContext('2d'),
type: 'horizontalBar'
data:
labels: []
datasets: [
{
label: 'Average FPS'
data: []
backgroundColor: 'hotpink'
borderColor: '#212121'
borderWidth: 1
}
{
label: 'Minimum FPS'
data: []
backgroundColor: 'cornflowerblue'
borderColor: '#212121'
borderWidth: 1
}
]
options:
title:
display: true
text: 'N/a'
scales: xAxes: [ {
display: true
ticks: beginAtZero: true
} ]
animation: onComplete: ->
dwnbtn = $('#download_button')
dwnbtn.attr 'href', benchChart.toBase64Image()
dwnbtn.attr 'download', 'benchmark_chart.png'
dwnbtn.attr 'disabled', false
return
)
+49
View File
@@ -0,0 +1,49 @@
testId = $('#results-table').data('test-id')
fetchTestBenchmarkResults = (testId, benchmarkId) ->
try
benchmarkSearchParams = new URLSearchParams
benchmark_id: benchmarkId
benchmarkRes = await fetch("/api/v1/benchmark/details?#{benchmarkSearchParams}")
benchmarkData = await benchmarkRes.json()
resultSearchParams = new URLSearchParams
test_id: testId
benchmark_id: benchmarkId
resultRes = await fetch("/api/v1/results?#{resultSearchParams}")
resultData = await resultRes.json()
avg_total = 0
min_total = 0
max_total = 0
for result in resultData
avg_total += result.avg_score
min_total += result.min_score
max_total += result.max_score
tableRow = $("#results-table tr[data-benchmark-id=#{benchmarkId}]")
tableRow.append('<td>' + benchmarkData.name + '</td>')
tableRow.append('<td>' + benchmarkData.scoring + '</td>')
tableRow.append('<td>' + resultData.length + '</td>')
if resultData.length != 0
tableRow.append('<td>' + (avg_total / resultData.length) + '</td>')
else
tableRow.append('<td>N/a</td>')
if min_total != 0
tableRow.append('<td>' + (min_total / resultData.length) + '</td>')
tableRow.append('<td>' + (max_total / resultData.length) + '</td>')
else
tableRow.append('<td>N/a</td>')
tableRow.append('<td>N/a</td>')
catch error
console.error 'An error occurred while fetching benchmark results.', error
$('#results-table tbody tr').each((index, tr) ->
benchmarkId = $(tr).data('benchmark-id')
console.log("Fetching results for benchmark id: " + benchmarkId)
fetchTestBenchmarkResults(testId, benchmarkId)
)
+13
View File
@@ -0,0 +1,13 @@
@use "sass:color"
//$primary-color: #3399ff
$primary-color: cornflowerblue
$primary-color-highlight: color.adjust($primary-color, $lightness: -10%)
body
background: rgb(240, 235, 248)
#wrapper
background: white
padding: 1.5rem 2rem
border-radius: 8px
+2
View File
@@ -0,0 +1,2 @@
docker build -t game-data -f Dockerfile.dev .
docker build -t game-data-gulp -f Dockerfile.gulp .
+5
View File
@@ -0,0 +1,5 @@
#!/bin/sh
docker build -t game-data -f Dockerfile.dev .
docker build -t game-data-gulp -f Dockerfile.gulp .
+1
View File
@@ -0,0 +1 @@
docker exec game-data rake %*
+3
View File
@@ -0,0 +1,3 @@
#!/bin/sh
docker exec game-data rake "$@"
+2
View File
@@ -0,0 +1,2 @@
docker run --rm -d -t -v "%cd%:/usr/src/game-data" -p 9292:9292 --name game-data game-data
docker run --rm -d -t -v "%cd%:/usr/src/game-data" --name game-data-gulp game-data-gulp npm run gulp watch
+5
View File
@@ -0,0 +1,5 @@
#!/bin/sh
docker run --rm -d -t -v "$(pwd):/usr/src/game-data" -p 9292:9292 --name game-data game-data
docker run --rm -d -t -v "$(pwd):/usr/src/game-data" --name game-data-gulp game-data-gulp npm run gulp watch
+6
View File
@@ -0,0 +1,6 @@
#!/bin/sh
# Configure bundler to use local vendor path
bundle config set --local path 'vendor/bundle'
# Install gems
bundle install
+7
View File
@@ -0,0 +1,7 @@
# Load application config
require_relative 'src/config.rb'
$conf = Config.new(File.join(__dir__, 'config/defaults.yaml'))
root = ::File.dirname(__FILE__)
require ::File.join( root, 'src', 'server' )
run GameData.new
+6
View File
@@ -0,0 +1,6 @@
database:
adapter: 'sqlite'
database: 'data/gamedata.db'
testing:
minimum_results_required: 3
View File
+28
View File
@@ -0,0 +1,28 @@
Sequel.migration do
up do
create_table(:hardware) do
primary_key :id
String :name, null: false
String :type, null: false
String :description, text: true
DateTime :created_at, default: Sequel::CURRENT_TIMESTAMP
DateTime :updated_at, default: Sequel::CURRENT_TIMESTAMP
end
create_table(:benchmarks) do
primary_key :id
String :name, null: false
String :description, text: true
String :scoring, null: false
DateTime :created_at, default: Sequel::CURRENT_TIMESTAMP
DateTime :updated_at, default: Sequel::CURRENT_TIMESTAMP
end
end
down do
drop_table(:hardware)
drop_table(:benchmarks)
end
end
+21
View File
@@ -0,0 +1,21 @@
Sequel.migration do
up do
# create tests table
create_table(:results) do
primary_key :id
foreign_key :hardware_id, :hardware
foreign_key :benchmark_id, :benchmarks
Float :avg_score, null: false
Float :min_score
Float :max_score
DateTime :created_at, default: Sequel::CURRENT_TIMESTAMP
DateTime :updated_at, default: Sequel::CURRENT_TIMESTAMP
end
end
down do
drop_table(:results)
end
end
+39
View File
@@ -0,0 +1,39 @@
Sequel.migration do
up do
# create tests table
create_table(:tests) do
primary_key :id
foreign_key :hardware_id, :hardware
String :name, null: false
String :description
DateTime :created_at, default: Sequel::CURRENT_TIMESTAMP
DateTime :updated_at, default: Sequel::CURRENT_TIMESTAMP
end
# create many-to-many table between tests and benchmarks
create_table(:benchmarks_tests) do
primary_key :id
foreign_key :benchmark_id, :benchmarks
foreign_key :test_id, :tests
DateTime :created_at, default: Sequel::CURRENT_TIMESTAMP
DateTime :updated_at, default: Sequel::CURRENT_TIMESTAMP
end
# modify results table to integrate with the new tests table
alter_table(:results) do
drop_foreign_key :hardware_id
add_foreign_key :test_id, :tests
end
end
down do
alter_table(:results) do
drop_foreign_key :test_id
add_foreign_key :hardware_id, :hardware
end
drop_table(:benchmarks_tests)
drop_table(:tests)
end
end
+7
View File
@@ -0,0 +1,7 @@
#!/bin/bash
if [ ! -f ./data/gamedata.db ]; then
rake db:migrate
fi
rake server:dev
+50
View File
@@ -0,0 +1,50 @@
const gulp = require('gulp');
const sass = require('gulp-sass')(require('sass'));
const coffee = require('gulp-coffee');
const sourcemaps = require('gulp-sourcemaps');
const plumber = require('gulp-plumber');
// Compile .sass files to compressed CSS
function compileSass() {
return gulp.src('assets/styles/**/*.sass')
.pipe(plumber())
.pipe(sass({ outputStyle: 'compressed' }).on('error', sass.logError))
.pipe(gulp.dest('public/css'));
}
// Compile .coffee files to JavaScript with source maps
function compileCoffee() {
return gulp.src('assets/scripts/**/*.coffee', { sourcemaps: true })
.pipe(plumber())
.pipe(coffee({ bare: true }))
.pipe(gulp.dest('public/js', { sourcemaps: '.' }));
}
// Watch files for changes
function watchFiles(cb) {
gulp.watch('assets/styles/**/*.sass', compileSass);
gulp.watch('assets/scripts/**/*.coffee', compileCoffee);
cb();
}
// Chain all asset builds together
function buildAssets() {
return gulp.parallel(compileSass, compileCoffee);
}
// Perform initial build then watch
function buildAndWatch() {
return gulp.series(
buildAssets(),
watchFiles
);
}
// one-time build
exports.build = buildAssets();
// start builds with file watching
exports.watch = buildAndWatch();
// Define default task (defaults to watch)
exports.default = exports.watch;
+3159
View File
File diff suppressed because it is too large Load Diff
+28
View File
@@ -0,0 +1,28 @@
{
"name": "game-data",
"description": "PC hardware benchmarking data logger",
"version": "0.1.0",
"main": "src/server.rb",
"scripts": {
"gulp": "gulp"
},
"repository": {
"type": "git",
"url": "https://git.metaunix.net/BitGoblin/game-data"
},
"keywords": [
"pc",
"hardware",
"benchmarking"
],
"author": "Gregory Ballantine <gballantine@bitgoblin.tech>",
"license": "BSD-2-Clause",
"devDependencies": {
"gulp": "^5.0.1",
"gulp-coffee": "^3.0.3",
"gulp-plumber": "^1.2.1",
"gulp-sass": "^6.0.1",
"gulp-sourcemaps": "^3.0.0",
"sass": "^1.89.2"
}
}
+28
View File
@@ -0,0 +1,28 @@
# frozen_string_literal: true
require 'yaml'
# Config - loads and manages the app's configuration
class Config
DEFAULT_CONFIG = 'config/defaults.yaml'
def initialize(config_path)
@data = YAML.load_file(DEFAULT_CONFIG)
# merge in user-defined configuration if it exists
@data.merge!(YAML.load_file(config_path)) if File.exist?(config_path)
end
def get(key)
bits = key.split('.')
value = @data
bits.each do |bit|
value = value[bit]
end
return value
end
end
+29
View File
@@ -0,0 +1,29 @@
# frozen_string_literal: true
# Helpers - view helper functions
module Helpers
def ruby_version()
return RUBY_VERSION
end
def app_version()
return `git describe --tags`
end
def date_format(date)
dt = date.to_datetime
return dt.strftime('%B %d, %Y @ %I:%M:%S %p %Z')
end
def average_array(arr, decimals = 1)
sum = 0
arr.each do |i|
sum += i
end
return (sum / arr.length).round(decimals)
end
end
+8
View File
@@ -0,0 +1,8 @@
# frozen_string_literal: true
# Benchmark - database model for PC benchmarks
class Benchmark < Sequel::Model
one_to_many :results
end
+20
View File
@@ -0,0 +1,20 @@
# frozen_string_literal: true
# Hardware - database model for PC hardware
class Hardware < Sequel::Model(:hardware)
one_to_many :tests
def bench_results
br = {}
results.each do |r|
br[r.benchmark.name.to_s] = [] unless br.key?(r.benchmark.name)
br[r.benchmark.name.to_s].push(r.avg_score)
end
return br
end
end
+6
View File
@@ -0,0 +1,6 @@
# frozen_string_literal: true
require_relative 'hardware'
require_relative 'benchmark'
require_relative 'result'
require_relative 'test'
+13
View File
@@ -0,0 +1,13 @@
# frozen_string_literal: true
# Result - database model for benchmark results
class Result < Sequel::Model
many_to_one :test
many_to_one :benchmark
def formatted_score
return @avg_score
end
end
+10
View File
@@ -0,0 +1,10 @@
# frozen_string_literal: true
# Test - database model for hardware tests
class Test < Sequel::Model
one_to_many :result
many_to_one :hardware
many_to_many :benchmark
end
+23
View File
@@ -0,0 +1,23 @@
# frozen_string_literal: true
# /api/v1 routes
class GameData < Sinatra::Base
get '/api/v1/benchmark/details' do
benchmark_id = params[:benchmark_id]
benchmark = Benchmark.where(id: benchmark_id).first()
json benchmark.values()
end
get '/api/v1/results' do
test_id = params[:test_id]
benchmark_id = params[:benchmark_id]
results = Result.where(test_id: test_id, benchmark_id: benchmark_id).all()
json results.map(&:values)
end
end
+58
View File
@@ -0,0 +1,58 @@
# frozen_string_literal: true
# /benchmark routes
class GameData < Sinatra::Base
get '/benchmark' do
benchmarks = Benchmark.reverse(:updated_at).limit(10).all()
erb :'benchmark/index', locals: {
title: 'List of Benchmarks',
benchmarks: benchmarks
}
end
get '/benchmark/add' do
erb :'benchmark/add', locals: {
title: 'Add Benchmark'
}
end
post '/benchmark/add' do
benchmark = Benchmark.create(
name: params[:benchmark_name],
scoring: params[:benchmark_scoring],
description: params[:benchmark_description]
)
redirect "/benchmark/#{benchmark.id}"
end
get '/benchmark/:benchmark_id' do
benchmark = Benchmark.where(id: params[:benchmark_id]).first()
erb :'benchmark/view', locals: {
title: benchmark.name,
benchmark: benchmark
}
end
get '/benchmark/:benchmark_id/edit' do
benchmark = Benchmark.where(id: params[:benchmark_id]).first()
erb :'benchmark/edit', locals: {
title: "Editing: #{benchmark.name}",
benchmark: benchmark
}
end
post '/benchmark/:benchmark_id/edit' do
benchmark = Benchmark.where(id: params[:benchmark_id]).first()
benchmark.update(
name: params[:benchmark_name],
scoring: params[:benchmark_scoring],
description: params[:benchmark_description]
)
redirect "/benchmark/#{benchmark.id}"
end
end
+58
View File
@@ -0,0 +1,58 @@
# frozen_string_literal: true
# /hardware routes
class GameData < Sinatra::Base
get '/hardware' do
hardware = Hardware.reverse(:updated_at).limit(10).all()
erb :'hardware/index', locals: {
title: 'List of Hardware',
hardware: hardware
}
end
get '/hardware/add' do
erb :'hardware/add', locals: {
title: 'Add Hardware'
}
end
post '/hardware/add' do
hardware = Hardware.create(
name: params[:hardware_name],
type: params[:hardware_type]
)
redirect "/hardware/#{hardware.id}"
end
get '/hardware/:hardware_id' do
benchmarks = Benchmark.order(:name).all()
hardware = Hardware.where(id: params[:hardware_id]).first()
erb :'hardware/view', locals: {
title: hardware.name,
hardware: hardware,
benchmarks: benchmarks
}
end
get '/hardware/:hardware_id/edit' do
hardware = Hardware.where(id: params[:hardware_id]).first()
erb :'hardware/edit', locals: {
title: "Editing: #{hardware.name}",
hardware: hardware
}
end
post '/hardware/:hardware_id/edit' do
hardware = Hardware.where(id: params[:hardware_id]).first()
hardware.update(
name: params[:hardware_name],
type: params[:hardware_type]
)
redirect "/hardware/#{hardware.id}"
end
end
+15
View File
@@ -0,0 +1,15 @@
# frozen_string_literal: true
# / (top-level) routes
class GameData < Sinatra::Base
get '/' do
tests = Test.reverse(:updated_at).limit(10).all()
erb :'index/index', locals: {
title: 'Dashboard',
tests: tests
}
end
end
+10
View File
@@ -0,0 +1,10 @@
# frozen_string_literal: true
require_relative 'index'
require_relative 'hardware'
require_relative 'benchmark'
require_relative 'reports'
require_relative 'result'
require_relative 'test'
require_relative 'api1'
+46
View File
@@ -0,0 +1,46 @@
# frozen_string_literal: true
# /reports routes
class GameData < Sinatra::Base
get '/report' do
benchmarks = Benchmark.order(:name).all()
tests = Test.order(:name).all()
erb :'reports/index', locals: {
title: 'Generate Reports',
tests: tests,
benchmarks: benchmarks
}
end
post '/report' do
report_type = params[:type]
report_choice = params[:choice]
report_compare = params[:compare]
if report_type == 'benchmark'
choice = Benchmark.where(id: report_choice).first().name
names = []
avg_results = []
min_results = []
report_compare.each do |c|
tst = Test.where(id: c).first()
names.push(tst.name)
res = Result.where(benchmark_id: report_choice, test_id: c).first()
avg_results.push(res.avg_score)
min_results.push(res.min_score)
end
json({
choice: choice,
names: names,
avg_results: avg_results,
min_results: min_results
})
end
end
end
+29
View File
@@ -0,0 +1,29 @@
# frozen_string_literal: true
# /result routes
class GameData < Sinatra::Base
post '/result/add' do
result_minimum = params[:result_minimum] if params.key?(:result_minimum)
result_maximum = params[:result_maximum] if params.key?(:result_maximum)
Result.create(
test_id: params[:result_test],
benchmark_id: params[:result_benchmark],
avg_score: params[:result_average],
min_score: result_minimum,
max_score: result_maximum
)
if params.key?(:result_referrer)
if params[:result_referrer] == 'test'
redirect "/test/#{params[:result_test]}"
elsif params[:result_referrer] == 'benchmark'
redirect "/benchmark/#{params[:result_benchmark]}"
end
else
redirect '/result'
end
end
end
+68
View File
@@ -0,0 +1,68 @@
# frozen_string_literal: true
# /test routes
class GameData < Sinatra::Base
get '/test' do
tests = Test.reverse(:updated_at).limit(10).all()
erb :'test/index', locals: {
title: 'List of Tests',
tests: tests
}
end
get '/test/add' do
hardware = Hardware.order(:name).all()
benchmarks = Benchmark.order(:name).all()
erb :'test/add', locals: {
title: 'Add Test',
hardware: hardware,
benchmarks: benchmarks
}
end
post '/test/add' do
tst = Test.create(
name: params[:test_name],
hardware_id: params[:test_hardware],
description: params[:test_description]
)
# create an array of the selected benchmarks
benchmarks = Array(params[:test_benchmarks])
# associate the benchmarks to the test
benchmarks.each do |b|
tst.add_benchmark(b)
end
redirect "/test/#{tst.id}"
end
get '/test/:test_id' do
tst = Test.where(id: params[:test_id]).first()
erb :'test/view', locals: {
title: tst.name,
test: tst
}
end
get '/test/:hardware_id/edit' do
hardware = Hardware.where(id: params[:hardware_id]).first()
erb :'test/edit', locals: {
title: "Editing: #{hardware.name}",
hardware: hardware
}
end
post '/test/:hardware_id/edit' do
hardware = Hardware.where(id: params[:hardware_id]).first()
hardware.update(
name: params[:hardware_name],
type: params[:hardware_type]
)
redirect "/hardware/#{hardware.id}"
end
end
Executable
+34
View File
@@ -0,0 +1,34 @@
# frozen_string_literal: true
require 'sinatra/base'
require 'sinatra/json'
require 'sequel'
require 'sqlite3'
# Load the Sequel timestamps plugin
Sequel::Model.plugin(:timestamps)
# Initialize Sequel gem for database actions
DB = Sequel.connect(adapter: $conf.get('database.adapter'), database: $conf.get('database.database'))
# Base app
class GameData < Sinatra::Base
enable :sessions
# Set up static file serving
enable :static
set :public_folder, File.join(__dir__, '/../public')
# Register view helpers
require_relative 'helpers'
helpers Helpers
# Set up our view engine
set :views, File.join(settings.root, '/../views')
end
# Load routes
require_relative 'routes/init'
# Load models
require_relative 'models/init'
+36
View File
@@ -0,0 +1,36 @@
<div class="row mb-4">
<div class="col-12">
<h1>Add new benchmark</h1>
</div>
</div>
<div class="row">
<form class="col-12" action="/benchmark/add" method="post">
<div class="row mb-3">
<div class="col-9">
<label for="benchmark_name">Benchmark name</label>
<input id="benchmark_name" class="form-control" type="text" name="benchmark_name" placeholder="Example benchmark">
</div>
<div class="col-3">
<label for="benchmark_scoring">Scoring type</label>
<select id="benchmark_scoring" class="form-select" name="benchmark_scoring">
<option value="fps">Frames per Second (fps)</option>
<option value="ms">Frame Time (ms)</option>
<option value="pts">Total Points</option>
</select>
</div>
</div>
<div class="row mb-3">
<div class="col-12">
<label for="benchmark_description">Benchmark description</label>
<textarea id="benchmark_description" class="form-control" name="benchmark_description">Enter a description/notes here.</textarea>
</div>
</div>
<input class="btn btn-primary" type="submit" value="Create Benchmark">
</form>
</div>
+36
View File
@@ -0,0 +1,36 @@
<div class="row mb-4">
<div class="col-12">
<h1>Editing: <%= benchmark.name %></h1>
</div>
</div>
<div class="row">
<form class="cell small-12" action="/benchmark/<%= benchmark.id %>/edit" method="post">
<div class="row mb-3">
<div class="col-9">
<label for="benchmark_name">Benchmark name</label>
<input id="benchmark_name" class="form-control" type="text" name="benchmark_name" placeholder="Example benchmark" value="<%= benchmark.name %>">
</div>
<div class="col-3">
<label for="benchmark_scoring">Scoring type</label>
<select id="benchmark_scoring" class="form-select" name="benchmark_scoring">
<option value="fps" <% if benchmark.scoring == 'fps' %>selected<% end %>>Frames per Second (fps)</option>
<option value="ms" <% if benchmark.scoring == 'ms' %>selected<% end %>>Frame Time (ms)</option>
<option value="pts" <% if benchmark.scoring == 'pts' %>selected<% end %>>Total Points</option>
</select>
</div>
</div>
<div class="row mb-3">
<div class="col-12">
<label for="benchmark_description">Benchmark description</label>
<textarea id="benchmark_description" class="form-control" name="benchmark_description"><%= benchmark.description %></textarea>
</div>
</div>
<input class="btn btn-primary" type="submit" value="Submit Changes">
</form>
</div>
+40
View File
@@ -0,0 +1,40 @@
<div class="row mb-3">
<div class="col-12">
<h1>List of benchmarks</h1>
</div>
<div class="col-12">
<p>
<a href="/benchmark/add">Add new benchmark</a>
</p>
</div>
</div>
<div class="row">
<% if benchmarks.length > 0 %>
<div class="col-12">
<table class="table table-hover table-responsive">
<thead class="table-light">
<tr>
<th>Benchmark name</th>
<th>Scoring type</th>
<th>Notes</th>
</tr>
</thead>
<tbody>
<% benchmarks.each do |b| %>
<tr>
<td><a href="/benchmark/<%= b.id %>"><%= b.name %></a></td>
<td><%= b.scoring %></td>
<td><%= b.description %></td>
</tr>
<% end %>
</tbody>
</table>
</div>
<% else %>
<div class="col-12">
<p>I'm sorry, there doesn't appear to be any benchmarks added yet. Check again later!</p>
</div>
<% end %>
</div>
+18
View File
@@ -0,0 +1,18 @@
<div class="row">
<div class="col-12">
<h1><%= benchmark.name %></h1>
</div>
<div class="col-12">
<p><a href="/benchmark/<%= benchmark.id %>/edit">Edit</a></p>
</div>
<div class="col-12">
Benchmark scoring type: <%= benchmark.scoring %>
</div>
<div class="col-12">
Description:
<p><%= benchmark.description %></p>
</div>
</div>
+28
View File
@@ -0,0 +1,28 @@
<div class="row mb-3">
<div class="col-12">
<h1>Add new hardware</h1>
</div>
</div>
<div class="row mb-3">
<form class="col-12" action="/hardware/add" method="post">
<div class="row mb-3">
<div class="col-12 col-md-9">
<label for="hardware_name">Hardware name</label>
<input id="hardware_name" class="form-control" type="text" name="hardware_name" placeholder="Example hardware">
</div>
<div class="col-12 col-md-3">
<label for="hardware_type">Type</label>
<select id="hardware_type" class="form-select" name="hardware_type">
<option value="gpu">Graphics card</option>
<option value="cpu">Processor</option>
</select>
</div>
</div>
<input class="btn btn-primary" type="submit" value="Create Hardware">
</form>
</div>
+28
View File
@@ -0,0 +1,28 @@
<div class="row mb-3">
<div class="col-12">
<h1>Add new hardware</h1>
</div>
</div>
<div class="row mb-3">
<form class="col-12" action="/hardware/<%= hardware.id %>/edit" method="post">
<div class="row mb-3">
<div class="col-12 col-md-9">
<label for="hardware_name">Hardware name</label>
<input id="hardware_name" class="form-control" type="text" name="hardware_name" placeholder="Example hardware" value="<%= hardware.name %>">
</div>
<div class="col-12 col-md-3">
<label for="hardware_type">Type</label>
<select id="hardware_type" class="form-select" name="hardware_type">
<option value="gpu" <% if hardware.type == 'gpu' %>selected<% end %>>Graphics card</option>
<option value="cpu" <% if hardware.type == 'cpu' %>selected<% end %>>Processor</option>
</select>
</div>
</div>
<input class="btn btn-primary" type="submit" value="Create Hardware">
</form>
</div>
+42
View File
@@ -0,0 +1,42 @@
<div class="row mb-3">
<div class="col-12">
<h1>List of hardware</h1>
</div>
<div class="col-12">
<p>
<a href="/hardware/add">Add new hardware</a>
</p>
</div>
</div>
<div class="row mb-3">
<% if hardware.length > 0 %>
<div class="col-12">
<table class="table table-hover table-responsive">
<thead class="table-light">
<tr>
<th>Hardware name</th>
<th>Type</th>
<th>Date added</th>
<th>Date modified</th>
</tr>
</thead>
<tbody>
<% hardware.each do |h| %>
<tr>
<td><a href="/hardware/<%= h.id %>"><%= h.name %></a></td>
<td><%= h.type %></td>
<td><%= date_format(h.created_at) %></td>
<td><%= date_format(h.updated_at) %></td>
</tr>
<% end %>
</tbody>
</table>
</div>
<% else %>
<div class="col-12">
<p>I'm sorry, there doesn't appear to be any hardware added yet. Check again later!</p>
</div>
<% end %>
</div>
+13
View File
@@ -0,0 +1,13 @@
<div class="row">
<div class="col-12">
<h1><%= hardware.name %></h1>
</div>
<div class="col-12">
<p><a href="/hardware/<%= hardware.id %>/edit">Edit</a></p>
</div>
<div class="col-12">
Hardware type: <%= hardware.type %>
</div>
</div>
+32
View File
@@ -0,0 +1,32 @@
<div class="row">
<% if tests.length > 0 %>
<div class="twelve columns">
<h2>Latest benchmark results:</h2>
</div>
<div class="twelve columns">
<table>
<thead>
<tr>
<th>Test name</th>
<th># Benchmarks</th>
<th>Last Updated</th>
</tr>
</thead>
<tbody>
<% tests.each do |t| %>
<tr>
<td><a href="/test/<%= t.id %>"><%= t.name %></a></td>
<td><%= t.benchmark.length %></td>
<td><%= t.updated_at %></td>
</tr>
<% end %>
</tbody>
</table>
</div>
<% else %>
<div class="twelve columns">
<p>I'm sorry, there don't appear to be any benchmark results logged yet. Check again later!</p>
</div>
<% end %>
</div>
+27
View File
@@ -0,0 +1,27 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title><%= title %> | Game Data</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.7/css/bootstrap.min.css">
<link rel="stylesheet" href="/css/rimmington.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js" charset="utf-8"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.7/js/bootstrap.min.js" charset="utf-8"></script>
<script src="/js/edgeville.js" charset="utf-8"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.min.js" charset="utf-8"></script>
</head>
<body>
<!-- main navigation -->
<%= erb :'partials/navbar', :locals => locals %>
<!-- main content -->
<div id="wrapper" class="container mb-4">
<%= yield %>
</div>
<!-- site footer -->
<%= erb :'partials/footer', :locals => locals %>
</body>
</html>
+8
View File
@@ -0,0 +1,8 @@
<nav id="main-footer" class="container">
<div class="row">
<div class="col-12">
<p>Game Data version v<%= app_version() %></p>
<p>Running Ruby version v<%= ruby_version() %></p>
</div>
</div>
</nav>
+29
View File
@@ -0,0 +1,29 @@
<div id="main-nav" class="navbar navbar-expand-md bg-body-secondary mb-3">
<div class="container-fluid">
<a class="navbar-brand mb-0 h1" href="#">Game Data</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-md-0">
<li class="nav-item">
<a class="nav-link" href="/">Dashboard</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/benchmark">Benchmarks</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/hardware">Hardware</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/test">Test</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/report">Reports</a>
</li>
</ul>
</div>
</div>
</div>
+35
View File
@@ -0,0 +1,35 @@
<div class="row">
<form class="col-12" action="/reports" method="post">
<div class="grid-x grid-margin-x">
<select class="col-12 col-md-6 form-select" id="report_type" name="report_type" disabled>
<option value="benchmark">Benchmark</option>
<option value="test">Test</option>
</select>
<select class="col-12 col-md-6 form-select" id="report_choice" name="report_choice">
<% benchmarks.each do |b| %>
<option value="<%= b.id %>"><%= b.name %></option>
<% end %>
</select>
</div>
<div class="grid-x grid-margin-x">
<select class="col-12 form-select" id="report_compare" name="report_compare[]" multiple>
<% tests.each do |t| %>
<option value="<%= t.id %>"><%= t.name %></option>
<% end %>
</select>
</div>
<input type="submit" class="btn btn-primary" id="generate_button" value="Generate">
<a href="#" class="button" id="download_button" disabled>Download</a>
<div class="grid-x grid-margin-x">
<canvas id="chart_canvas" width="100%" height="25"></canvas>
</div>
</form>
</div>
<!-- load the chart.js library -->
<!-- load chart functionality -->
<script src="/js/reports.js" charset="utf-8"></script>
+46
View File
@@ -0,0 +1,46 @@
<div class="row mb-3">
<div class="col-12">
<h1>Add new test</h1>
</div>
</div>
<div class="row">
<form class="col-12" action="/test/add" method="post">
<div class="row mb-3">
<div class="col-12 col-md-6 mb-3">
<label for="test_name">Test name</label>
<input id="test_name" class="form-control" type="text" name="test_name" placeholder="My hardware test (01/99)">
</div>
<div class="col-12 col-md-6 mb-3">
<label for="test_hardware">Hardware to test</label>
<select id="test_hardware" class="form-select" name="test_hardware">
<% for h in hardware %>
<option value="<%= h.id %>"><%= h.name %></option>
<% end %>
</select>
</div>
<div class="col-12 col-md-4 mb-3">
<label for="test_benchmarks">Benchmarks</label>
<select id="test_benchmarks" class="form-select" name="test_benchmarks[]" multiple>
<% for b in benchmarks %>
<option value="<%= b.id %>"><%= b.name %></option>
<% end %>
</select>
</div>
<div class="col-12 col-md-8 mb-3">
<label for="test_description">Test description</label>
<textarea id="test_description" class="form-control" name="test_description" placeholder="This is my test for a hardware..."></textarea>
</div>
<div class="row">
<div class="col-12">
<input class="btn btn-primary" type="submit" value="Create Test">
</div>
</div>
</form>
</div>
+32
View File
@@ -0,0 +1,32 @@
<div class="grid-x grid-margin-x">
<div class="cell small-12">
<h1>Editing: <%= hardware.name %></h1>
</div>
</div>
<div class="grid-x grid-margin-x">
<form class="cell small-12" action="/hardware/<%= hardware.id %>/edit" method="post">
<div class="grid-x grid-padding-x">
<div class="cell medium-9">
<label>
Hardware name
<input type="text" name="hardware_name" placeholder="Example hardware" value="<%= hardware.name %>">
</label>
</div>
<div class="cell medium-3">
<label>
Type
<select name="hardware_type">
<option value="gpu" <% if hardware.type == 'gpu' %>selected<% end %>>Graphics card</option>
<option value="cpu" <% if hardware.type == 'cpu' %>selected<% end %>>Processor</option>
</select>
</label>
</div>
</div>
<input type="submit" class="button" value="Submit">
</form>
</div>
+42
View File
@@ -0,0 +1,42 @@
<div class="row mb-3">
<div class="col-12">
<h1>List of tests</h1>
</div>
<div class="col-12">
<p>
<a href="/test/add">Add new test</a>
</p>
</div>
</div>
<div class="row mb-3">
<% if tests.length > 0 %>
<div class="col-12">
<table class="table table-hover table-responsive">
<thead class="table-light">
<tr>
<th>Test name</th>
<th># of benchmarks</th>
<th>Date added</th>
<th>Date modified</th>
</tr>
</thead>
<tbody>
<% tests.each do |t| %>
<tr>
<td><a href="/test/<%= t.id %>"><%= t.name %></a></td>
<td><%= t.benchmark.length %></td>
<td><%= date_format(t.created_at) %></td>
<td><%= date_format(t.updated_at) %></td>
</tr>
<% end %>
</tbody>
</table>
</div>
<% else %>
<div class="col-12">
<p>I'm sorry, there doesn't appear to be any tests added yet. Check again later!</p>
</div>
<% end %>
</div>
+91
View File
@@ -0,0 +1,91 @@
<div class="grid-x grid-margin-x">
<div class="cell small-12">
<h1><%= test.name %></h1>
</div>
<div class="cell small-12">
<p><a href="/test/<%= test.id %>/edit">Edit</a></p>
</div>
<div class="cell small-12">
Hardware tested: <%= test.hardware.name %>
</div>
<div class="cell small-12">
<p><%= test.description %></p>
</div>
</div>
<hr>
<div class="grix-x grix-margin-x">
<div class="cell small-12">
<form class="u-full-width" action="/result/add" method="post">
<input type="hidden" name="result_test" value="<%= test.id %>">
<input type="hidden" name="result_referrer" value="test">
<div class="grid-x grid-margin-x">
<div class="cell medium-5">
<label for="result_benchmark">
Add benchmark result:
<select class="u-full-width" id="result_benchmark" name="result_benchmark">
<% test.benchmark.each do |b| %>
<option value="<%= b.id %>"><%= b.name %></option>
<% end %>
</select>
</label>
</div>
<div class="cell medium-2">
<label for="result_average">
Average score:
<input type="text" id="result_average" name="result_average" value="">
</label>
</div>
<div class="cell medium-2">
<label for="result_minimum">
Minimum score:
<input type="text" id="result_minimum" name="result_minimum" value="">
</label>
</div>
<div class="cell medium-2">
<label for="result_maximum">
Maximum score:
<input type="text" id="result_maximum" name="result_maximum" value="">
</label>
</div>
<div class="cell medium-1">
<input type="submit" class="u-full-width button" value="Submit">
</div>
</div>
</form>
<hr>
<h4>Benchmark results for this test:</h4>
<table id="results-table" data-test-id="<%= test.id %>">
<thead>
<tr>
<th>Benchmark name</th>
<th>Scoring type</th>
<th># results</th>
<th>Average</th>
<th>Minimum</th>
<th>Maximum</th>
</tr>
</thead>
<tbody>
<% test.benchmark.each do |benchmark| %>
<tr data-benchmark-id="<%= benchmark.id %>"></tr>
<% end %>
</tbody>
</table>
</div>
</div>
<!-- load test data fetching functionality -->
<script src="/js/test.js" charset="utf-8"></script>