Compare commits
62 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 25d394627d | |||
| 85dfdb163a | |||
| b593ef7593 | |||
| 26698082f4 | |||
| 42a0b95015 | |||
| 5cc3b8f824 | |||
| d59c75281e | |||
| 55e4f397f8 | |||
| 49d1276031 | |||
| bc70fb8dd0 | |||
| 0231ebad2d | |||
| 541b5236f0 | |||
| 6215cecb53 | |||
| 886f566ae2 | |||
| fdd350e16f | |||
| bc4cb181c3 | |||
| 822f49bcc2 | |||
| aec77628f7 | |||
| ecb696372d | |||
| 31b8404be1 | |||
| 8cd47d7e70 | |||
| d17b66920a | |||
| 47cb580393 | |||
| 883019b181 | |||
| 2cc80e239b | |||
| ed085e4b40 | |||
| cf9235cb18 | |||
| 28b6cc66bb | |||
| e3a334546f | |||
| d899ffe58a | |||
| e6853a52d7 | |||
| 6d26eea419 | |||
| 778bd25ef2 | |||
| 6aca95d832 | |||
| 357bb69257 | |||
| 1e0cd49cf8 | |||
| 5628c69d66 | |||
| e6333b855f | |||
| f7979cd005 | |||
| ef2e0a12a5 | |||
| c83d517437 | |||
| 8dee8b1f40 | |||
| 175ce24b27 | |||
| 516f125ea7 | |||
| 34741691ed | |||
| fa9245d7ec | |||
| 1a363a5862 | |||
| b819f4f1cd | |||
| 394a8ef91f | |||
| c940a248d7 | |||
| 269587e6c9 | |||
| 3c9e6eab6b | |||
| a1a00d9fe5 | |||
| 7e38154bc1 | |||
| f0115847b8 | |||
| b8bec03357 | |||
| 7655b75410 | |||
| 691e2e9b1e | |||
| 291db231d5 | |||
| 6c1c8bca0a | |||
| 6f680e72e5 | |||
| b376bf3a79 |
@@ -0,0 +1,2 @@
|
||||
---
|
||||
BUNDLE_PATH: "vendor/bundle"
|
||||
@@ -56,3 +56,12 @@ build-iPhoneSimulator/
|
||||
# Used by RuboCop. Remote config files pulled in from inherit_from directive.
|
||||
# .rubocop-https?--*
|
||||
|
||||
# Ignore local data
|
||||
data/
|
||||
|
||||
# Node modules
|
||||
node_modules/
|
||||
|
||||
# Compiled assets
|
||||
public/css/
|
||||
public/js/
|
||||
|
||||
@@ -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
|
||||
@@ -0,0 +1,19 @@
|
||||
pipeline:
|
||||
style:
|
||||
image: ruby:3.4
|
||||
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
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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" ]
|
||||
@@ -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
@@ -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,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:
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
$ ->
|
||||
# run foundation scripts
|
||||
console.log('Ready.')
|
||||
@@ -0,0 +1,113 @@
|
||||
$ ->
|
||||
chartInstance = null
|
||||
|
||||
$('#reports-download').on 'click', (e) ->
|
||||
e.preventDefault()
|
||||
canvas = $('#benchmark-chart')[0]
|
||||
a = document.createElement 'a'
|
||||
a.href = canvas.toDataURL 'image/png'
|
||||
a.download = 'chart.png'
|
||||
a.click()
|
||||
|
||||
$('#reports-button').on 'click', (e) ->
|
||||
e.preventDefault()
|
||||
$('#reports-download').attr('disabled', true)
|
||||
chartInstance.destroy() if chartInstance
|
||||
|
||||
benchmarkId = $('#report-benchmarks').val()
|
||||
testIds = $('#report-tests').val()
|
||||
|
||||
benchmarkSearchParams = new URLSearchParams
|
||||
benchmark_id: benchmarkId
|
||||
benchmarkRes = await fetch("/api/v1/benchmark/details?#{benchmarkSearchParams}")
|
||||
benchmarkData = await benchmarkRes.json()
|
||||
|
||||
data =
|
||||
labels: []
|
||||
datasets: []
|
||||
|
||||
switch benchmarkData.scoring
|
||||
when 'pts'
|
||||
data.datasets.push({
|
||||
label: 'Average Score'
|
||||
data: []
|
||||
})
|
||||
when 'fps'
|
||||
data.datasets.push({
|
||||
label: 'Average FPS'
|
||||
data: []
|
||||
})
|
||||
data.datasets.push({
|
||||
label: 'Minimum FPS'
|
||||
data: []
|
||||
})
|
||||
when 'ms'
|
||||
data.datasets.push({
|
||||
label: 'Average Frame Time'
|
||||
data: []
|
||||
})
|
||||
data.datasets.push({
|
||||
label: 'Minimum Frame Time'
|
||||
data: []
|
||||
})
|
||||
|
||||
for testId in testIds
|
||||
try
|
||||
testSearchParams = new URLSearchParams
|
||||
test_id: testId
|
||||
testRes = await fetch("/api/v1/test/details?#{testSearchParams}")
|
||||
testData = await testRes.json()
|
||||
|
||||
resultSearchParams = new URLSearchParams
|
||||
test_id: testId
|
||||
benchmark_id: benchmarkId
|
||||
resultRes = await fetch("/api/v1/result/list?#{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 if result.min_score
|
||||
max_total += result.max_score if result.max_score
|
||||
|
||||
data.labels.push(testData.name)
|
||||
data.datasets[0].data.push(avg_total / resultData.length)
|
||||
console.log(data.datasets[0].data)
|
||||
switch benchmarkData.scoring
|
||||
when 'fps', 'ms'
|
||||
data.datasets[1].data.push(min_total / resultData.length)
|
||||
catch error
|
||||
console.error 'An error occurred while fetching benchmark results.', error
|
||||
|
||||
ctx = $('#benchmark-chart')[0].getContext('2d')
|
||||
|
||||
options =
|
||||
indexAxis: 'y'
|
||||
plugins:
|
||||
title:
|
||||
display: true
|
||||
text: benchmarkData.name
|
||||
font:
|
||||
size: '24'
|
||||
datalabels:
|
||||
anchor: 'end'
|
||||
align: 'left'
|
||||
color: 'black'
|
||||
font:
|
||||
weight: 'bold'
|
||||
formatter: (value) -> value
|
||||
scales:
|
||||
y:
|
||||
beginAtZero: true
|
||||
|
||||
chartInstance = new Chart ctx,
|
||||
type: 'bar'
|
||||
data: data
|
||||
options: options
|
||||
plugins: [ChartDataLabels]
|
||||
|
||||
$('#reports-download').attr('disabled', false)
|
||||
$('#benchmark-chart').removeClass('disabled')
|
||||
@@ -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/result/list?#{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><a href="/benchmark/' + benchmarkData.id + '">' + benchmarkData.name + '</a></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)
|
||||
)
|
||||
@@ -0,0 +1,21 @@
|
||||
@use "sass:color"
|
||||
|
||||
//$primary-color: #3399ff
|
||||
$primary-color: cornflowerblue
|
||||
$primary-color-highlight: color.adjust($primary-color, $lightness: -10%)
|
||||
|
||||
html
|
||||
width: 100%
|
||||
height: 100%
|
||||
|
||||
body
|
||||
background: rgb(240, 235, 248)
|
||||
|
||||
table
|
||||
border: 1px solid #666
|
||||
|
||||
#wrapper
|
||||
background: white
|
||||
padding: 1.5rem 2rem
|
||||
border: 1px solid #bbb
|
||||
border-radius: 8px
|
||||
@@ -0,0 +1,2 @@
|
||||
docker build -t game-data -f Dockerfile.dev .
|
||||
docker build -t game-data-gulp -f Dockerfile.gulp .
|
||||
Executable
+5
@@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
|
||||
docker build -t game-data -f Dockerfile.dev .
|
||||
docker build -t game-data-gulp -f Dockerfile.gulp .
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
docker exec game-data rake %*
|
||||
Executable
+3
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
docker exec game-data rake "$@"
|
||||
@@ -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
|
||||
Executable
+5
@@ -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
|
||||
|
||||
Executable
+6
@@ -0,0 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Configure bundler to use local vendor path
|
||||
bundle config set --local path 'vendor/bundle'
|
||||
# Install gems
|
||||
bundle install
|
||||
@@ -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
|
||||
@@ -0,0 +1,6 @@
|
||||
database:
|
||||
adapter: 'sqlite'
|
||||
database: 'data/gamedata.db'
|
||||
|
||||
testing:
|
||||
minimum_results_required: 3
|
||||
@@ -0,0 +1,9 @@
|
||||
app_dir = File.expand_path('..', __dir__)
|
||||
directory app_dir
|
||||
|
||||
environment ENV.fetch('RACK_ENV', 'development')
|
||||
|
||||
bind 'tcp://0.0.0.0:9292'
|
||||
workers 2
|
||||
threads 1, 5
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ ! -f ./data/gamedata.db ]; then
|
||||
rake db:migrate
|
||||
fi
|
||||
|
||||
rake server:dev
|
||||
+50
@@ -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;
|
||||
Generated
+3159
File diff suppressed because it is too large
Load Diff
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module AppInfo
|
||||
|
||||
VERSION = '0.1.1'
|
||||
|
||||
end
|
||||
@@ -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
|
||||
@@ -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 AppInfo::VERSION
|
||||
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
|
||||
@@ -0,0 +1,9 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Benchmark - database model for PC benchmarks
|
||||
class Benchmark < Sequel::Model
|
||||
|
||||
many_to_many :tests
|
||||
one_to_many :results
|
||||
|
||||
end
|
||||
@@ -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
|
||||
@@ -0,0 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'hardware'
|
||||
require_relative 'benchmark'
|
||||
require_relative 'result'
|
||||
require_relative 'test'
|
||||
@@ -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
|
||||
@@ -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 :benchmarks
|
||||
|
||||
end
|
||||
@@ -0,0 +1,31 @@
|
||||
# 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/result/list' 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
|
||||
|
||||
get '/api/v1/test/details' do
|
||||
test_id = params[:test_id]
|
||||
|
||||
tst = Test.where(id: test_id).first()
|
||||
|
||||
json tst.values()
|
||||
end
|
||||
|
||||
end
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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'
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -0,0 +1,74 @@
|
||||
# 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/:test_id/edit' do
|
||||
tst = Test.where(id: params[:test_id]).first()
|
||||
hardware = Hardware.order(:name).all()
|
||||
benchmarks = Benchmark.order(:name).all()
|
||||
|
||||
erb :'test/edit', locals: {
|
||||
title: "Editing: #{tst.name}",
|
||||
test: tst,
|
||||
hardware: hardware,
|
||||
benchmarks: benchmarks
|
||||
}
|
||||
end
|
||||
|
||||
post '/test/:test_id/edit' do
|
||||
tst = Test.where(id: params[:test_id]).first()
|
||||
|
||||
tst.update(
|
||||
name: params[:test_name],
|
||||
type: params[:test_type]
|
||||
)
|
||||
|
||||
redirect "/test/#{tst.id}"
|
||||
end
|
||||
|
||||
end
|
||||
Executable
+36
@@ -0,0 +1,36 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'sinatra/base'
|
||||
require 'sinatra/json'
|
||||
require 'sequel'
|
||||
require 'sqlite3'
|
||||
|
||||
require_relative 'appinfo'
|
||||
|
||||
# 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'
|
||||
@@ -0,0 +1,40 @@
|
||||
<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>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<input class="btn btn-primary w-100" type="submit" value="Create Benchmark">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,40 @@
|
||||
<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>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<input class="btn btn-primary w-100" type="submit" value="Submit Changes">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
@@ -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>
|
||||
@@ -0,0 +1,49 @@
|
||||
<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>
|
||||
|
||||
<hr>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h3 class="mb-3">Tests using this benchmark:</h3>
|
||||
|
||||
<% if benchmark.tests.length > 0 %>
|
||||
<table class="table table-hover table-responsive">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Test title</th>
|
||||
<th>Benchmarks</th>
|
||||
<th>Last updated</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% benchmark.tests.each do |t| %>
|
||||
<tr>
|
||||
<td><a href="/test/<%= t.id %>"><%= t.name %></a></td>
|
||||
<td><%= t.benchmarks.length %></td>
|
||||
<td><%= t.updated_at %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
<% else %>
|
||||
<p>There are no tests associated with this benchmark.</p>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,32 @@
|
||||
<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>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<input class="btn btn-primary w-100" type="submit" value="Create Hardware">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,32 @@
|
||||
<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>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<input class="btn btn-primary w-100" type="submit" value="Submit Changes">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
@@ -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>
|
||||
@@ -0,0 +1,44 @@
|
||||
<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>
|
||||
|
||||
<hr>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h3 class="mb-3">Tests using this benchmark:</h3>
|
||||
|
||||
<% if hardware.tests.length > 0 %>
|
||||
<table class="table table-hover table-responsive">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Test title</th>
|
||||
<th>Benchmarks</th>
|
||||
<th>Last updated</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% hardware.tests.each do |t| %>
|
||||
<tr>
|
||||
<td><a href="/test/<%= t.id %>"><%= t.name %></a></td>
|
||||
<td><%= t.benchmarks.length %></td>
|
||||
<td><%= t.updated_at %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
<% else %>
|
||||
<p>There are no tests associated with this benchmark.</p>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,32 @@
|
||||
<div class="row">
|
||||
<% if tests.length > 0 %>
|
||||
<div class="12-col mb-3">
|
||||
<h2>Latest benchmark results:</h2>
|
||||
</div>
|
||||
|
||||
<div class="12-col">
|
||||
<table class="table table-hover table-responsive">
|
||||
<thead class="table-light">
|
||||
<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.benchmarks.length %></td>
|
||||
<td><%= t.updated_at %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<% else %>
|
||||
<div class="12-col">
|
||||
<p>I'm sorry, there don't appear to be any benchmark results logged yet. Check again later!</p>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
@@ -0,0 +1,28 @@
|
||||
<!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>
|
||||
</head>
|
||||
<body class="d-flex flex-column min-vh-100">
|
||||
<!-- main navigation -->
|
||||
<%= erb :'partials/navbar', :locals => locals %>
|
||||
|
||||
<!-- main content -->
|
||||
<main class="flex-grow-1 py-4">
|
||||
<div id="wrapper" class="container mb-4">
|
||||
<%= yield %>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- site footer -->
|
||||
<%= erb :'partials/footer', :locals => locals %>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,10 @@
|
||||
<footer id="main-footer" class="bg-light border-top py-3 text-center">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<p>Game Data version v<%= app_version() %></p>
|
||||
<p class="mb-0">Running Ruby version v<%= ruby_version() %></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
@@ -0,0 +1,29 @@
|
||||
<div id="main-nav" class="navbar navbar-expand-md bg-dark border-bottom border-body mb-3" data-bs-theme="dark">
|
||||
<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>
|
||||
@@ -0,0 +1,43 @@
|
||||
<div class="row">
|
||||
<form class="col-12" action="/reports" method="post">
|
||||
<div class="row mb-3">
|
||||
<div class="col-12 col-md-6">
|
||||
<select id="report-type" class="form-select" name="report_type" disabled>
|
||||
<option value="benchmark">Benchmark</option>
|
||||
<option value="test">Test</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-md-6">
|
||||
<select id="report-benchmarks" class="form-select" name="report_choice">
|
||||
<% benchmarks.each do |b| %>
|
||||
<option value="<%= b.id %>"><%= b.name %></option>
|
||||
<% end %>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 mb-3">
|
||||
<select id="report-tests" class="col-12 form-select" name="report_compare[]" multiple>
|
||||
<% tests.each do |t| %>
|
||||
<option value="<%= t.id %>"><%= t.name %></option>
|
||||
<% end %>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="col-12 mb-3">
|
||||
<button id="reports-button" class="btn btn-primary">Generate</button>
|
||||
<button id="reports-download" class="btn btn-primary" disabled>Download</button>
|
||||
</div>
|
||||
|
||||
<div class="col-12">
|
||||
<canvas id="benchmark-chart" width="100%" height="25"></canvas>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- load the chart.js library -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.1/chart.umd.min.js" charset="utf-8"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-datalabels/2.2.0/chartjs-plugin-datalabels.min.js" charset="utf-8"></script>
|
||||
<!-- load chart functionality -->
|
||||
<script src="/js/reports.js" charset="utf-8"></script>
|
||||
@@ -0,0 +1,49 @@
|
||||
<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-0 mb-md-3">
|
||||
<div class="col-12 col-md-6 mb-3 mb-md-0">
|
||||
<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 mb-md-0">
|
||||
<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>
|
||||
|
||||
<div class="row mb-0 mb-md-3">
|
||||
<div class="col-12 col-md-4 mb-3 mb-md-0">
|
||||
<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 mb-md-0">
|
||||
<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>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<input class="btn btn-primary w-100" type="submit" value="Create Test">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,49 @@
|
||||
<div class="row mb-3">
|
||||
<div class="col-12">
|
||||
<h1>Editing: <%= test.name %></h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
|
||||
<form class="col-12" action="/test/<%= test.id %>/edit" method="post">
|
||||
<div class="row mb-0 mb-md-3">
|
||||
<div class="col-12 col-md-6 mb-3 mb-md-0">
|
||||
<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)" value="<%= test.name %>">
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-md-6 mb-3 mb-md-0">
|
||||
<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 %>" <% if h.id == test.hardware.id %>selected<% end %>><%= h.name %></option>
|
||||
<% end %>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-0 mb-md-3">
|
||||
<div class="col-12 col-md-4 mb-3 mb-md-0">
|
||||
<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 mb-md-0">
|
||||
<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..."><%= test.description %></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<input class="btn btn-primary w-100" type="submit" value="Create Test">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
@@ -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.benchmarks.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>
|
||||
@@ -0,0 +1,83 @@
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h1><%= test.name %></h1>
|
||||
</div>
|
||||
|
||||
<div class="col-12">
|
||||
<p><a href="/test/<%= test.id %>/edit">Edit</a></p>
|
||||
</div>
|
||||
|
||||
<div class="col-12">
|
||||
<p>Hardware tested: <a href="/hardware/<%= test.hardware.id %>"><%= test.hardware.name %></a></p>
|
||||
</div>
|
||||
|
||||
<div class="col-12">
|
||||
<p><%= test.description %></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<form action="/result/add" method="post">
|
||||
<input type="hidden" name="result_test" value="<%= test.id %>">
|
||||
<input type="hidden" name="result_referrer" value="test">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-5 mb-3 mb-md-0">
|
||||
<label for="result_benchmark">Add benchmark result:</label>
|
||||
<select class="form-select" id="result_benchmark" name="result_benchmark">
|
||||
<% test.benchmarks.each do |b| %>
|
||||
<option value="<%= b.id %>"><%= b.name %></option>
|
||||
<% end %>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="col-4 col-md-2">
|
||||
<label for="result_average">Average score:</label>
|
||||
<input id="result_average" class="form-control" type="text" name="result_average" value="">
|
||||
</div>
|
||||
|
||||
<div class="col-4 col-md-2">
|
||||
<label for="result_minimum">Minimum score:</label>
|
||||
<input id="result_minimum" class="form-control" type="text" name="result_minimum" value="">
|
||||
</div>
|
||||
|
||||
<div class="col-4 col-md-2 mb-3 mb-md-0">
|
||||
<label for="result_maximum">Maximum score:</label>
|
||||
<input id="result_maximum" class="form-control" type="text" name="result_maximum" value="">
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-md-1 d-flex align-items-stretch mb-3 mb-md-0">
|
||||
<input class="btn btn-primary w-100" type="submit" value="Submit">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<hr>
|
||||
|
||||
<h4>Benchmark results for this test:</h4>
|
||||
|
||||
<table id="results-table" class="table table-hover table-responsive" data-test-id="<%= test.id %>">
|
||||
<thead class="table-light">
|
||||
<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.benchmarks.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>
|
||||
Reference in New Issue
Block a user