25 Commits

Author SHA1 Message Date
3a136865b0 Added some more tests; changed URLs for model list pages and added redirects
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/tag/woodpecker Pipeline was successful
2025-08-12 18:22:22 -04:00
Gregory Ballantine
f40d69a98d Using before hook for index route
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2025-08-12 16:26:48 -04:00
Gregory Ballantine
40cfdcc2a3 Changed naming from Routes to Controllers; fixed some Sinatra modular layout stuff; added RSpec for testing and some basic tests
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2025-08-12 16:15:43 -04:00
Gregory Ballantine
260d0d1268 Added rspec testing. It should work, but doesn't for unknown reasons 2025-08-12 15:35:46 -04:00
Gregory Ballantine
e1f5bd3950 Updating to Sinatra 4.1
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2025-08-12 14:27:22 -04:00
Gregory Ballantine
1f0c481105 Refactored app to more explicitly require gems/modules that are used per-file
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2025-08-12 14:12:32 -04:00
Gregory Ballantine
dd8e419e52 Switched over to a modular Sinatra app layout
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2025-08-12 13:54:25 -04:00
Gregory Ballantine
c74ca114d8 Fixed a logic error with removing benchmarks from a test; cleaned up some linter errors
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2025-08-12 12:19:25 -04:00
0a1037e79a Modified the front-end to display averaged results up to two decimals
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2025-08-11 23:39:01 -04:00
Gregory Ballantine
bc5ae4962f Fixed the placeholder for benchmark add/edit pages
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2025-07-31 14:07:58 -04:00
Gregory Ballantine
ec2bf45a6e Fixed the test edit page
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2025-07-31 14:06:08 -04:00
57163b10e4 The report test selection resets when you change the benchmark
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2025-07-30 23:29:53 -04:00
25d394627d Version bump to v0.1.1
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/tag/woodpecker Pipeline was successful
2025-07-28 11:01:35 -04:00
85dfdb163a Fixed rubocop warnings
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2025-07-28 10:57:40 -04:00
b593ef7593 Updating to ruby:3.4 in CI/CD
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2025-07-28 10:54:53 -04:00
26698082f4 Removed backup copy of the reports.coffee script
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
2025-07-28 10:49:09 -04:00
42a0b95015 Fixed the chart generation page with the new ChartJS version and DB schema
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
2025-07-28 10:48:49 -04:00
5cc3b8f824 Added a better way of setting/reading the app version; fixed some of the flexbox sizing
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
2025-07-28 10:23:51 -04:00
d59c75281e Updating puma.rb to allow changing the rack environment dynamically
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
2025-07-28 10:17:45 -04:00
55e4f397f8 Fixed the test edit view
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
2025-07-26 11:37:43 -04:00
49d1276031 Fixed puma config for new Puma versions 2025-07-26 11:32:32 -04:00
bc70fb8dd0 Added config/puma.rb for production deployment
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
2025-07-26 11:16:07 -04:00
0231ebad2d Made some more style changes
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
2025-07-26 01:08:35 -04:00
541b5236f0 Finished transition to Bootstrap 5
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
2025-07-26 00:55:52 -04:00
Gregory Ballantine
6215cecb53 Cleaned up app version output
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
2025-07-25 17:48:21 -04:00
48 changed files with 812 additions and 303 deletions

View File

@@ -1,4 +1,6 @@
require: rubocop-sequel plugins:
- rubocop-rspec
- rubocop-sequel
AllCops: AllCops:
NewCops: enable NewCops: enable

View File

@@ -1,6 +1,6 @@
pipeline: pipeline:
style: style:
image: ruby:3.0 image: ruby:3.4
commands: commands:
- 'gem install rake' - 'gem install rake'
- 'bundle config set --local path "vendor/bundle"' - 'bundle config set --local path "vendor/bundle"'

10
Gemfile
View File

@@ -1,7 +1,7 @@
source 'https://rubygems.org' source 'https://rubygems.org'
gem 'sinatra', '~> 3.2' gem 'sinatra', '~> 4.1'
gem 'sinatra-contrib', '~> 3.2' gem 'sinatra-contrib', '~> 4.1'
gem 'puma', '~> 6.6' gem 'puma', '~> 6.6'
gem 'sequel', '~> 5.92' gem 'sequel', '~> 5.92'
@@ -15,5 +15,11 @@ group :development, :test do
# rubocop and extensions for code style # rubocop and extensions for code style
gem 'rubocop' gem 'rubocop'
gem 'rubocop-rspec'
gem 'rubocop-sequel' gem 'rubocop-sequel'
end end
group :test do
gem 'rspec'
gem 'rack-test'
end

View File

@@ -4,6 +4,7 @@ GEM
ast (2.4.3) ast (2.4.3)
base64 (0.3.0) base64 (0.3.0)
bigdecimal (3.2.2) bigdecimal (3.2.2)
diff-lcs (1.6.2)
ffi (1.17.2-aarch64-linux-gnu) ffi (1.17.2-aarch64-linux-gnu)
ffi (1.17.2-aarch64-linux-musl) ffi (1.17.2-aarch64-linux-musl)
ffi (1.17.2-arm-linux-gnu) ffi (1.17.2-arm-linux-gnu)
@@ -33,10 +34,16 @@ GEM
puma (6.6.0) puma (6.6.0)
nio4r (~> 2.0) nio4r (~> 2.0)
racc (1.8.1) racc (1.8.1)
rack (2.2.17) rack (3.2.0)
rack-protection (3.2.0) rack-protection (4.1.1)
base64 (>= 0.1.0) base64 (>= 0.1.0)
rack (~> 2.2, >= 2.2.4) logger (>= 1.6.0)
rack (>= 3.0.0, < 4)
rack-session (2.1.1)
base64 (>= 0.1.0)
rack (>= 3.0.0)
rack-test (2.2.0)
rack (>= 1.3)
rainbow (3.1.1) rainbow (3.1.1)
rb-fsevent (0.11.2) rb-fsevent (0.11.2)
rb-inotify (0.11.1) rb-inotify (0.11.1)
@@ -44,6 +51,19 @@ GEM
regexp_parser (2.10.0) regexp_parser (2.10.0)
rerun (0.14.0) rerun (0.14.0)
listen (~> 3.0) listen (~> 3.0)
rspec (3.13.1)
rspec-core (~> 3.13.0)
rspec-expectations (~> 3.13.0)
rspec-mocks (~> 3.13.0)
rspec-core (3.13.5)
rspec-support (~> 3.13.0)
rspec-expectations (3.13.5)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
rspec-mocks (3.13.5)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
rspec-support (3.13.4)
rubocop (1.76.1) rubocop (1.76.1)
json (~> 2.3) json (~> 2.3)
language_server-protocol (~> 3.17.0.2) language_server-protocol (~> 3.17.0.2)
@@ -58,6 +78,9 @@ GEM
rubocop-ast (1.45.1) rubocop-ast (1.45.1)
parser (>= 3.3.7.2) parser (>= 3.3.7.2)
prism (~> 1.4) prism (~> 1.4)
rubocop-rspec (3.6.0)
lint_roller (~> 1.1)
rubocop (~> 1.72, >= 1.72.1)
rubocop-sequel (0.4.1) rubocop-sequel (0.4.1)
lint_roller (~> 1.1) lint_roller (~> 1.1)
rubocop (>= 1.72.1, < 2) rubocop (>= 1.72.1, < 2)
@@ -65,16 +88,18 @@ GEM
ruby2_keywords (0.0.5) ruby2_keywords (0.0.5)
sequel (5.93.0) sequel (5.93.0)
bigdecimal bigdecimal
sinatra (3.2.0) sinatra (4.1.1)
logger (>= 1.6.0)
mustermann (~> 3.0) mustermann (~> 3.0)
rack (~> 2.2, >= 2.2.4) rack (>= 3.0.0, < 4)
rack-protection (= 3.2.0) rack-protection (= 4.1.1)
rack-session (>= 2.0.0, < 3)
tilt (~> 2.0) tilt (~> 2.0)
sinatra-contrib (3.2.0) sinatra-contrib (4.1.1)
multi_json (>= 0.0.2) multi_json (>= 0.0.2)
mustermann (~> 3.0) mustermann (~> 3.0)
rack-protection (= 3.2.0) rack-protection (= 4.1.1)
sinatra (= 3.2.0) sinatra (= 4.1.1)
tilt (~> 2.0) tilt (~> 2.0)
sqlite3 (2.7.0-aarch64-linux-gnu) sqlite3 (2.7.0-aarch64-linux-gnu)
sqlite3 (2.7.0-aarch64-linux-musl) sqlite3 (2.7.0-aarch64-linux-musl)
@@ -106,12 +131,15 @@ PLATFORMS
DEPENDENCIES DEPENDENCIES
logger logger
puma (~> 6.6) puma (~> 6.6)
rack-test
rerun rerun
rspec
rubocop rubocop
rubocop-rspec
rubocop-sequel rubocop-sequel
sequel (~> 5.92) sequel (~> 5.92)
sinatra (~> 3.2) sinatra (~> 4.1)
sinatra-contrib (~> 3.2) sinatra-contrib (~> 4.1)
sqlite3 (~> 2.6) sqlite3 (~> 2.6)
BUNDLED WITH BUNDLED WITH

View File

@@ -24,8 +24,12 @@ namespace :server do
end end
namespace :test do namespace :test do
task :unit do
system("rspec")
end
task :rubocop do task :rubocop do
system("rubocop src/") system("rubocop src/ spec/")
end end
end end

View File

@@ -1,3 +1,21 @@
$ -> $ ->
# run foundation scripts # run foundation scripts
$(document).foundation() console.log('Ready.')
averageResults = (results, decimals = 2) ->
avgScore = 0
minScore = Infinity
maxScore = -Infinity
factor = (10 ^ decimals)
for result in results
avgScore += result.avg_score
minScore = Math.min(minScore, result.min_score)
maxScore = Math.max(maxScore, result.max_score)
return {
avgScore: Math.round((avgScore / results.length) * factor) / factor,
minScore: minScore,
maxScore: maxScore,
}

View File

@@ -1,55 +1,109 @@
$(document).ready -> $ ->
$('#generate_button').on 'click', (e) -> chartInstance = null
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'), $('#report-benchmarks').on 'change', (e) ->
type: 'horizontalBar' $('#report-tests option').prop('selected', false)
data:
$('#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: [] labels: []
datasets: [ datasets: []
{
switch benchmarkData.scoring
when 'pts'
data.datasets.push({
label: 'Average Score'
data: []
})
when 'fps'
data.datasets.push({
label: 'Average FPS' label: 'Average FPS'
data: [] data: []
backgroundColor: 'hotpink' })
borderColor: '#212121' data.datasets.push({
borderWidth: 1
}
{
label: 'Minimum FPS' label: 'Minimum FPS'
data: [] data: []
backgroundColor: 'cornflowerblue' })
borderColor: '#212121' when 'ms'
borderWidth: 1 data.datasets.push({
} label: 'Average Frame Time'
] data: []
options: })
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()
resultAverage = averageResults(resultData)
data.labels.push(testData.name)
data.datasets[0].data.push(resultAverage.avgScore)
console.log(data.datasets[0].data)
switch benchmarkData.scoring
when 'fps', 'ms'
data.datasets[1].data.push(resultAverage.minScore)
catch error
console.error 'An error occurred while fetching benchmark results.', error
ctx = $('#benchmark-chart')[0].getContext('2d')
options =
indexAxis: 'y'
plugins:
title: title:
display: true display: true
text: 'N/a' text: benchmarkData.name
scales: xAxes: [ { font:
display: true size: '24'
ticks: beginAtZero: true datalabels:
} ] anchor: 'end'
animation: onComplete: -> align: 'left'
dwnbtn = $('#download_button') color: 'black'
dwnbtn.attr 'href', benchChart.toBase64Image() font:
dwnbtn.attr 'download', 'benchmark_chart.png' weight: 'bold'
dwnbtn.attr 'disabled', false formatter: (value) -> value
return 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')

View File

@@ -10,35 +10,30 @@ fetchTestBenchmarkResults = (testId, benchmarkId) ->
resultSearchParams = new URLSearchParams resultSearchParams = new URLSearchParams
test_id: testId test_id: testId
benchmark_id: benchmarkId benchmark_id: benchmarkId
resultRes = await fetch("/api/v1/results?#{resultSearchParams}") resultRes = await fetch("/api/v1/result/list?#{resultSearchParams}")
resultData = await resultRes.json() resultData = await resultRes.json()
avg_total = 0 resultAverage = averageResults(resultData)
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 = $("#results-table tr[data-benchmark-id=#{benchmarkId}]")
tableRow.append('<td>' + benchmarkData.name + '</td>') tableRow.append('<td><a href="/benchmark/' + benchmarkData.id + '">' + benchmarkData.name + '</a></td>')
tableRow.append('<td>' + benchmarkData.scoring + '</td>') tableRow.append('<td>' + benchmarkData.scoring + '</td>')
tableRow.append('<td>' + resultData.length + '</td>') tableRow.append('<td>' + resultData.length + '</td>')
if resultData.length != 0 if resultData.length != 0
tableRow.append('<td>' + (avg_total / resultData.length) + '</td>') tableRow.append('<td>' + resultAverage.avgScore + '</td>')
if benchmarkData.scoring == 'fps'
tableRow.append('<td>' + resultAverage.minScore + '</td>')
tableRow.append('<td>' + resultAverage.maxScore + '</td>')
else else
tableRow.append('<td>N/a</td>') tableRow.append('<td>N/a</td>')
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 else
tableRow.append('<td>N/a</td>') tableRow.append('<td>N/a</td>')
tableRow.append('<td>N/a</td>') tableRow.append('<td>N/a</td>')
tableRow.append('<td>N/a</td>')
catch error catch error
console.error 'An error occurred while fetching benchmark results.', error console.error 'An error occurred while fetching benchmark results.', error

View File

@@ -4,10 +4,18 @@
$primary-color: cornflowerblue $primary-color: cornflowerblue
$primary-color-highlight: color.adjust($primary-color, $lightness: -10%) $primary-color-highlight: color.adjust($primary-color, $lightness: -10%)
html
width: 100%
height: 100%
body body
background: rgb(240, 235, 248) background: rgb(240, 235, 248)
table
border: 1px solid #666
#wrapper #wrapper
background: white background: white
padding: 1.5rem 2rem padding: 1.5rem 2rem
border: 1px solid #bbb
border-radius: 8px border-radius: 8px

View File

@@ -1,6 +1,4 @@
# Load application config # Load application config
require_relative 'src/config.rb'
$conf = Config.new(File.join(__dir__, 'config/defaults.yaml'))
root = ::File.dirname(__FILE__) root = ::File.dirname(__FILE__)
require ::File.join( root, 'src', 'server' ) require ::File.join( root, 'src', 'server' )

9
config/puma.rb Normal file
View File

@@ -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

View File

@@ -0,0 +1,41 @@
# frozen_string_literal: true
require_relative '../spec_helper'
RSpec.describe(BenchmarkController) do
# /benchmark - redirects to /benchmark/list
describe 'GET /benchmark' do
before { get '/benchmark' }
it 'Benchmark base route redirects to /benchmark/list' do
expect(last_response).to(be_redirect)
expect(last_response['Location']).to(eq("#{BASE_URL}/benchmark/list"))
end
end
# /benchmark/list - displays a table of benchmarks
describe 'GET /benchmark/list' do
before { get '/benchmark/list' }
it 'Benchmark list page returns 200.' do
expect(last_response).to(be_ok)
end
it "Benchmark list page contains 'List of benchmarks' on page." do
expect(last_response.body).to(include('List of benchmarks'))
end
end
# /benchmark/add - form for adding benchmark
describe 'GET /benchmark/add' do
before { get '/benchmark/add' }
it 'Benchmark add page returns 200.' do
expect(last_response).to(be_ok)
end
it "Benchmark add page contains 'Add new benchmark' on page." do
expect(last_response.body).to(include('Add new benchmark'))
end
end
end

View File

@@ -0,0 +1,41 @@
# frozen_string_literal: true
require_relative '../spec_helper'
RSpec.describe(HardwareController) do
# /hardware - redirects to /hardware/list
describe 'GET /hardware' do
before { get '/hardware' }
it 'Hardware base route redirects to /hardware/list' do
expect(last_response).to(be_redirect)
expect(last_response['Location']).to(eq("#{BASE_URL}/hardware/list"))
end
end
# /hardware/list - displays a table of hardwares
describe 'GET /hardware/list' do
before { get '/hardware/list' }
it 'Hardware list page returns 200.' do
expect(last_response).to(be_ok)
end
it "Hardware list page contains 'List of hardware' on page." do
expect(last_response.body).to(include('List of hardware'))
end
end
# /hardware/add - form for adding hardware
describe 'GET /hardware/add' do
before { get '/hardware/add' }
it 'Hardware add page returns 200.' do
expect(last_response).to(be_ok)
end
it "Hardware add page contains 'Add new hardware' on page." do
expect(last_response.body).to(include('Add new hardware'))
end
end
end

View File

@@ -0,0 +1,21 @@
# frozen_string_literal: true
require_relative '../spec_helper'
RSpec.describe(IndexController) do
describe 'GET /' do
before { get '/' }
it 'Dashboard returns 200.' do
expect(last_response).to(be_ok)
end
it "Dashboard contains 'Game Data' on page (nav bar should be loaded)." do
expect(last_response.body).to(include('Game Data'))
end
it "Dashboard contains 'Ruby version' on page (footer should be loaded)." do
expect(last_response.body).to(include('Ruby version'))
end
end
end

View File

@@ -0,0 +1,17 @@
# frozen_string_literal: true
require_relative '../spec_helper'
RSpec.describe(ReportsController) do
describe 'GET /report' do
before { get '/report' }
it 'Reports page returns 200.' do
expect(last_response).to(be_ok)
end
it "Reports page contains 'Generate report' on page." do
expect(last_response.body).to(include('Generate report'))
end
end
end

View File

@@ -0,0 +1,41 @@
# frozen_string_literal: true
require_relative '../spec_helper'
RSpec.describe(TestController) do
# /test - redirects to /test/list
describe 'GET /test' do
before { get '/test' }
it 'Test base route redirects to /test/list' do
expect(last_response).to(be_redirect)
expect(last_response['Location']).to(eq("#{BASE_URL}/test/list"))
end
end
# /test/list - displays a table of tests
describe 'GET /test/list' do
before { get '/test/list' }
it 'Test list page returns 200.' do
expect(last_response).to(be_ok)
end
it "Test list page contains 'List of tests' on page." do
expect(last_response.body).to(include('List of tests'))
end
end
# /test/add - form for adding test
describe 'GET /test/add' do
before { get '/test/add' }
it 'Test add page returns 200.' do
expect(last_response).to(be_ok)
end
it "Test add page contains 'Add new test' on page." do
expect(last_response.body).to(include('Add new test'))
end
end
end

24
spec/spec_helper.rb Normal file
View File

@@ -0,0 +1,24 @@
# frozen_string_literal: true
ENV['APP_ENV'] = 'test'
require_relative '../src/server'
require 'rspec'
require 'rack/test'
# setting this here so all redirect tests can reference the same base URL
BASE_URL = 'http://example.org'
module RSpecMixin
include Rack::Test::Methods
def app
GameData
end
end
RSpec.configure do |config|
config.include(RSpecMixin)
end

7
src/appinfo.rb Normal file
View File

@@ -0,0 +1,7 @@
# frozen_string_literal: true
module AppInfo
VERSION = '0.1.1'
end

View File

@@ -1,7 +1,14 @@
# frozen_string_literal: true # frozen_string_literal: true
require 'sinatra/json'
require_relative 'base_controller'
require_relative '../models/benchmark'
require_relative '../models/test'
require_relative '../models/result'
# /api/v1 routes # /api/v1 routes
class GameData < Sinatra::Base class APIv1Controller < BaseController
get '/api/v1/benchmark/details' do get '/api/v1/benchmark/details' do
benchmark_id = params[:benchmark_id] benchmark_id = params[:benchmark_id]
@@ -11,7 +18,7 @@ class GameData < Sinatra::Base
json benchmark.values() json benchmark.values()
end end
get '/api/v1/results' do get '/api/v1/result/list' do
test_id = params[:test_id] test_id = params[:test_id]
benchmark_id = params[:benchmark_id] benchmark_id = params[:benchmark_id]
@@ -20,4 +27,12 @@ class GameData < Sinatra::Base
json results.map(&:values) json results.map(&:values)
end end
get '/api/v1/test/details' do
test_id = params[:test_id]
tst = Test.where(id: test_id).first()
json tst.values()
end
end end

View File

@@ -0,0 +1,15 @@
# frozen_string_literal: true
require 'sinatra/base'
# BaseController - base modular Sinatra app class
class BaseController < Sinatra::Base
# Register view helpers
require_relative '../helpers'
helpers Helpers
# Set up our view engine
set :views, File.join(settings.root, '/../../views')
end

View File

@@ -1,9 +1,16 @@
# frozen_string_literal: true # frozen_string_literal: true
require_relative 'base_controller'
require_relative '../models/benchmark'
# /benchmark routes # /benchmark routes
class GameData < Sinatra::Base class BenchmarkController < BaseController
get '/benchmark' do get '/benchmark' do
redirect('/benchmark/list')
end
get '/benchmark/list' do
benchmarks = Benchmark.reverse(:updated_at).limit(10).all() benchmarks = Benchmark.reverse(:updated_at).limit(10).all()
erb :'benchmark/index', locals: { erb :'benchmark/index', locals: {

View File

@@ -1,9 +1,17 @@
# frozen_string_literal: true # frozen_string_literal: true
require_relative 'base_controller'
require_relative '../models/hardware'
require_relative '../models/benchmark'
# /hardware routes # /hardware routes
class GameData < Sinatra::Base class HardwareController < BaseController
get '/hardware' do get '/hardware' do
redirect('/hardware/list')
end
get '/hardware/list' do
hardware = Hardware.reverse(:updated_at).limit(10).all() hardware = Hardware.reverse(:updated_at).limit(10).all()
erb :'hardware/index', locals: { erb :'hardware/index', locals: {

View File

@@ -1,7 +1,10 @@
# frozen_string_literal: true # frozen_string_literal: true
require_relative 'base_controller'
require_relative '../models/test'
# / (top-level) routes # / (top-level) routes
class GameData < Sinatra::Base class IndexController < BaseController
get '/' do get '/' do
tests = Test.reverse(:updated_at).limit(10).all() tests = Test.reverse(:updated_at).limit(10).all()

View File

@@ -1,7 +1,14 @@
# frozen_string_literal: true # frozen_string_literal: true
require 'sinatra/json'
require_relative 'base_controller'
require_relative '../models/benchmark'
require_relative '../models/result'
require_relative '../models/test'
# /reports routes # /reports routes
class GameData < Sinatra::Base class ReportsController < BaseController
get '/report' do get '/report' do
benchmarks = Benchmark.order(:name).all() benchmarks = Benchmark.order(:name).all()

View File

@@ -1,7 +1,10 @@
# frozen_string_literal: true # frozen_string_literal: true
require_relative 'base_controller'
require_relative '../models/result'
# /result routes # /result routes
class GameData < Sinatra::Base class ResultController < BaseController
post '/result/add' do post '/result/add' do
result_minimum = params[:result_minimum] if params.key?(:result_minimum) result_minimum = params[:result_minimum] if params.key?(:result_minimum)

96
src/controllers/test.rb Normal file
View File

@@ -0,0 +1,96 @@
# frozen_string_literal: true
require_relative 'base_controller'
require_relative '../models/benchmark'
require_relative '../models/hardware'
require_relative '../models/test'
# /test routes
class TestController < BaseController
get '/test' do
redirect('/test/list')
end
get '/test/list' 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],
hardware_id: params[:test_hardware],
description: params[:test_description]
)
selected_benchmarks = Array(params[:test_benchmarks])
# remove benchmarks no longer associated with the test
tst.benchmarks.dup.each do |b|
tst.remove_benchmark(b.id) unless selected_benchmarks.include?(b.id)
end
# associate the benchmarks to the test
selected_benchmarks.each do |b|
tst.add_benchmark(b) unless tst.benchmark?(b)
end
redirect "/test/#{tst.id}"
end
end

View File

@@ -1,14 +1,16 @@
# frozen_string_literal: true # frozen_string_literal: true
require_relative 'appinfo'
# Helpers - view helper functions # Helpers - view helper functions
module Helpers module Helpers
def ruby_version() def ruby_version
return RUBY_VERSION return RUBY_VERSION
end end
def app_version() def app_version
return `git describe --tags` return AppInfo::VERSION
end end
def date_format(date) def date_format(date)

View File

@@ -3,6 +3,7 @@
# Benchmark - database model for PC benchmarks # Benchmark - database model for PC benchmarks
class Benchmark < Sequel::Model class Benchmark < Sequel::Model
many_to_many :tests
one_to_many :results one_to_many :results
end end

View File

@@ -1,6 +0,0 @@
# frozen_string_literal: true
require_relative 'hardware'
require_relative 'benchmark'
require_relative 'result'
require_relative 'test'

View File

@@ -5,6 +5,10 @@ class Test < Sequel::Model
one_to_many :result one_to_many :result
many_to_one :hardware many_to_one :hardware
many_to_many :benchmark many_to_many :benchmarks
def benchmark?(benchmark_id)
return benchmarks_dataset.where(Sequel[:benchmarks][:id] => benchmark_id).any?
end
end end

View File

@@ -1,10 +0,0 @@
# 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'

View File

@@ -1,68 +0,0 @@
# 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

37
src/server.rb Executable file → Normal file
View File

@@ -1,16 +1,31 @@
# frozen_string_literal: true # frozen_string_literal: true
require 'sinatra/base' require 'sinatra/base'
require 'sinatra/json'
require 'sequel' require 'sequel'
require 'sqlite3' require 'sqlite3'
require_relative 'config'
$conf = Config.new(File.join(__dir__, 'config/defaults.yaml'))
# Load the Sequel timestamps plugin # Load the Sequel timestamps plugin
Sequel::Model.plugin(:timestamps) Sequel::Model.plugin(:timestamps)
# Initialize Sequel gem for database actions # Initialize Sequel gem for database actions
DB = Sequel.connect(adapter: $conf.get('database.adapter'), database: $conf.get('database.database')) DB = Sequel.connect(adapter: $conf.get('database.adapter'), database: $conf.get('database.database'))
# Base app # Load in routes (must happen after Sequel is loaded!)
require_relative 'controllers/api1'
require_relative 'controllers/benchmark'
require_relative 'controllers/hardware'
require_relative 'controllers/index'
require_relative 'controllers/reports'
require_relative 'controllers/result'
require_relative 'controllers/test'
# GameData - main app that gets launched
# - inherits from Sinatra::Base to instantiate the server
# - sets up some base app configuration
# - registers route classes with the base app
class GameData < Sinatra::Base class GameData < Sinatra::Base
enable :sessions enable :sessions
@@ -19,16 +34,12 @@ class GameData < Sinatra::Base
enable :static enable :static
set :public_folder, File.join(__dir__, '/../public') set :public_folder, File.join(__dir__, '/../public')
# Register view helpers use IndexController
require_relative 'helpers' use HardwareController
helpers Helpers use BenchmarkController
use TestController
# Set up our view engine use ResultController
set :views, File.join(settings.root, '/../views') use ReportsController
use APIv1Controller
end end
# Load routes
require_relative 'routes/init'
# Load models
require_relative 'models/init'

View File

@@ -26,11 +26,15 @@
<div class="row mb-3"> <div class="row mb-3">
<div class="col-12"> <div class="col-12">
<label for="benchmark_description">Benchmark description</label> <label for="benchmark_description">Benchmark description</label>
<textarea id="benchmark_description" class="form-control" name="benchmark_description">Enter a description/notes here.</textarea> <textarea id="benchmark_description" class="form-control" name="benchmark_description" placeholder="Enter a description/notes here."></textarea>
</div> </div>
</div> </div>
<input class="btn btn-primary" type="submit" value="Create Benchmark"> <div class="row">
<div class="col-12">
<input class="btn btn-primary w-100" type="submit" value="Create Benchmark">
</div>
</div>
</form> </form>
</div> </div>

View File

@@ -26,11 +26,15 @@
<div class="row mb-3"> <div class="row mb-3">
<div class="col-12"> <div class="col-12">
<label for="benchmark_description">Benchmark description</label> <label for="benchmark_description">Benchmark description</label>
<textarea id="benchmark_description" class="form-control" name="benchmark_description"><%= benchmark.description %></textarea> <textarea id="benchmark_description" class="form-control" name="benchmark_description" placeholder="Enter a description/notes here."><%= benchmark.description %></textarea>
</div> </div>
</div> </div>
<input class="btn btn-primary" type="submit" value="Submit Changes"> <div class="row">
<div class="col-12">
<input class="btn btn-primary w-100" type="submit" value="Submit Changes">
</div>
</div>
</form> </form>
</div> </div>

View File

@@ -16,3 +16,34 @@
<p><%= benchmark.description %></p> <p><%= benchmark.description %></p>
</div> </div>
</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>

View File

@@ -22,7 +22,11 @@
</div> </div>
</div> </div>
<input class="btn btn-primary" type="submit" value="Create Hardware"> <div class="row">
<div class="col-12">
<input class="btn btn-primary w-100" type="submit" value="Create Hardware">
</div>
</div>
</form> </form>
</div> </div>

View File

@@ -22,7 +22,11 @@
</div> </div>
</div> </div>
<input class="btn btn-primary" type="submit" value="Create Hardware"> <div class="row">
<div class="col-12">
<input class="btn btn-primary w-100" type="submit" value="Submit Changes">
</div>
</div>
</form> </form>
</div> </div>

View File

@@ -11,3 +11,34 @@
Hardware type: <%= hardware.type %> Hardware type: <%= hardware.type %>
</div> </div>
</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>

View File

@@ -1,12 +1,12 @@
<div class="row"> <div class="row">
<% if tests.length > 0 %> <% if tests.length > 0 %>
<div class="twelve columns"> <div class="12-col mb-3">
<h2>Latest benchmark results:</h2> <h2>Latest benchmark results:</h2>
</div> </div>
<div class="twelve columns"> <div class="12-col">
<table> <table class="table table-hover table-responsive">
<thead> <thead class="table-light">
<tr> <tr>
<th>Test name</th> <th>Test name</th>
<th># Benchmarks</th> <th># Benchmarks</th>
@@ -17,7 +17,7 @@
<% tests.each do |t| %> <% tests.each do |t| %>
<tr> <tr>
<td><a href="/test/<%= t.id %>"><%= t.name %></a></td> <td><a href="/test/<%= t.id %>"><%= t.name %></a></td>
<td><%= t.benchmark.length %></td> <td><%= t.benchmarks.length %></td>
<td><%= t.updated_at %></td> <td><%= t.updated_at %></td>
</tr> </tr>
<% end %> <% end %>
@@ -25,7 +25,7 @@
</table> </table>
</div> </div>
<% else %> <% else %>
<div class="twelve columns"> <div class="12-col">
<p>I'm sorry, there don't appear to be any benchmark results logged yet. Check again later!</p> <p>I'm sorry, there don't appear to be any benchmark results logged yet. Check again later!</p>
</div> </div>
<% end %> <% end %>

View File

@@ -10,16 +10,17 @@
<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/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="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="/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> </head>
<body> <body class="d-flex flex-column min-vh-100">
<!-- main navigation --> <!-- main navigation -->
<%= erb :'partials/navbar', :locals => locals %> <%= erb :'partials/navbar', :locals => locals %>
<!-- main content --> <!-- main content -->
<main class="flex-grow-1 py-4">
<div id="wrapper" class="container mb-4"> <div id="wrapper" class="container mb-4">
<%= yield %> <%= yield %>
</div> </div>
</main>
<!-- site footer --> <!-- site footer -->
<%= erb :'partials/footer', :locals => locals %> <%= erb :'partials/footer', :locals => locals %>

View File

@@ -1,8 +1,10 @@
<nav id="main-footer" class="container"> <footer id="main-footer" class="bg-light border-top py-3 text-center">
<div class="container">
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
<p>Game Data version v<%= app_version() %></p> <p>Game Data version v<%= app_version() %></p>
<p>Running Ruby version v<%= ruby_version() %></p> <p class="mb-0">Running Ruby version v<%= ruby_version() %></p>
</div> </div>
</div> </div>
</nav> </div>
</footer>

View File

@@ -1,4 +1,4 @@
<div id="main-nav" class="navbar navbar-expand-md bg-body-secondary mb-3"> <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"> <div class="container-fluid">
<a class="navbar-brand mb-0 h1" href="#">Game Data</a> <a class="navbar-brand mb-0 h1" href="#">Game Data</a>

View File

@@ -1,35 +1,49 @@
<div class="row">
<div class="col-12">
<h1>Generate report</h1>
</div>
</div>
<div class="row"> <div class="row">
<form class="col-12" action="/reports" method="post"> <form class="col-12" action="/reports" method="post">
<div class="grid-x grid-margin-x"> <div class="row mb-3">
<select class="col-12 col-md-6 form-select" id="report_type" name="report_type" disabled> <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="benchmark">Benchmark</option>
<option value="test">Test</option> <option value="test">Test</option>
</select> </select>
</div>
<select class="col-12 col-md-6 form-select" id="report_choice" name="report_choice"> <div class="col-12 col-md-6">
<select id="report-benchmarks" class="form-select" name="report_choice">
<% benchmarks.each do |b| %> <% benchmarks.each do |b| %>
<option value="<%= b.id %>"><%= b.name %></option> <option value="<%= b.id %>"><%= b.name %></option>
<% end %> <% end %>
</select> </select>
</div> </div>
</div>
<div class="grid-x grid-margin-x"> <div class="col-12 mb-3">
<select class="col-12 form-select" id="report_compare" name="report_compare[]" multiple> <select id="report-tests" class="col-12 form-select" name="report_compare[]" multiple>
<% tests.each do |t| %> <% tests.each do |t| %>
<option value="<%= t.id %>"><%= t.name %></option> <option value="<%= t.id %>"><%= t.name %></option>
<% end %> <% end %>
</select> </select>
</div> </div>
<input type="submit" class="btn btn-primary" id="generate_button" value="Generate"> <div class="col-12 mb-3">
<a href="#" class="button" id="download_button" disabled>Download</a> <button id="reports-button" class="btn btn-primary">Generate</button>
<button id="reports-download" class="btn btn-primary" disabled>Download</button>
</div>
<div class="grid-x grid-margin-x"> <div class="col-12">
<canvas id="chart_canvas" width="100%" height="25"></canvas> <canvas id="benchmark-chart" width="100%" height="25"></canvas>
</div> </div>
</form> </form>
</div> </div>
<!-- load the chart.js library --> <!-- 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 --> <!-- load chart functionality -->
<script src="/js/reports.js" charset="utf-8"></script> <script src="/js/reports.js" charset="utf-8"></script>

View File

@@ -7,13 +7,13 @@
<div class="row"> <div class="row">
<form class="col-12" action="/test/add" method="post"> <form class="col-12" action="/test/add" method="post">
<div class="row mb-3"> <div class="row mb-0 mb-md-3">
<div class="col-12 col-md-6 mb-3"> <div class="col-12 col-md-6 mb-3 mb-md-0">
<label for="test_name">Test name</label> <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)"> <input id="test_name" class="form-control" type="text" name="test_name" placeholder="My hardware test (01/99)">
</div> </div>
<div class="col-12 col-md-6 mb-3"> <div class="col-12 col-md-6 mb-3 mb-md-0">
<label for="test_hardware">Hardware to test</label> <label for="test_hardware">Hardware to test</label>
<select id="test_hardware" class="form-select" name="test_hardware"> <select id="test_hardware" class="form-select" name="test_hardware">
<% for h in hardware %> <% for h in hardware %>
@@ -21,8 +21,10 @@
<% end %> <% end %>
</select> </select>
</div> </div>
</div>
<div class="col-12 col-md-4 mb-3"> <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> <label for="test_benchmarks">Benchmarks</label>
<select id="test_benchmarks" class="form-select" name="test_benchmarks[]" multiple> <select id="test_benchmarks" class="form-select" name="test_benchmarks[]" multiple>
<% for b in benchmarks %> <% for b in benchmarks %>
@@ -31,14 +33,15 @@
</select> </select>
</div> </div>
<div class="col-12 col-md-8 mb-3"> <div class="col-12 col-md-8 mb-3 mb-md-0">
<label for="test_description">Test description</label> <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> <textarea id="test_description" class="form-control" name="test_description" placeholder="This is my test for a hardware..."></textarea>
</div> </div>
</div>
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
<input class="btn btn-primary" type="submit" value="Create Test"> <input class="btn btn-primary w-100" type="submit" value="Create Test">
</div> </div>
</div> </div>
</form> </form>

View File

@@ -1,32 +1,49 @@
<div class="grid-x grid-margin-x"> <div class="row mb-3">
<div class="cell small-12"> <div class="col-12">
<h1>Editing: <%= hardware.name %></h1> <h1>Editing: <%= test.name %></h1>
</div> </div>
</div> </div>
<div class="grid-x grid-margin-x"> <div class="row">
<form class="cell small-12" action="/hardware/<%= hardware.id %>/edit" method="post"> <form class="col-12" action="/test/<%= test.id %>/edit" method="post">
<div class="grid-x grid-padding-x"> <div class="row mb-0 mb-md-3">
<div class="cell medium-9"> <div class="col-12 col-md-6 mb-3 mb-md-0">
<label> <label for="test_name">Test name</label>
Hardware name <input id="test_name" class="form-control" type="text" name="test_name" placeholder="My hardware test (01/99)" value="<%= test.name %>">
<input type="text" name="hardware_name" placeholder="Example hardware" value="<%= hardware.name %>">
</label>
</div> </div>
<div class="cell medium-3"> <div class="col-12 col-md-6 mb-3 mb-md-0">
<label> <label for="test_hardware">Hardware to test</label>
Type <select id="test_hardware" class="form-select" name="test_hardware">
<select name="hardware_type"> <% for h in hardware %>
<option value="gpu" <% if hardware.type == 'gpu' %>selected<% end %>>Graphics card</option> <option value="<%= h.id %>" <% if h.id == test.hardware.id %>selected<% end %>><%= h.name %></option>
<option value="cpu" <% if hardware.type == 'cpu' %>selected<% end %>>Processor</option> <% end %>
</select> </select>
</label>
</div> </div>
</div> </div>
<input type="submit" class="button" value="Submit"> <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 %>" <% if test.benchmark?(b.id) %>selected<% end %>><%= 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="Submit Changes">
</div>
</div>
</form> </form>
</div> </div>

View File

@@ -26,7 +26,7 @@
<% tests.each do |t| %> <% tests.each do |t| %>
<tr> <tr>
<td><a href="/test/<%= t.id %>"><%= t.name %></a></td> <td><a href="/test/<%= t.id %>"><%= t.name %></a></td>
<td><%= t.benchmark.length %></td> <td><%= t.benchmarks.length %></td>
<td><%= date_format(t.created_at) %></td> <td><%= date_format(t.created_at) %></td>
<td><%= date_format(t.updated_at) %></td> <td><%= date_format(t.updated_at) %></td>
</tr> </tr>

View File

@@ -1,64 +1,56 @@
<div class="grid-x grid-margin-x"> <div class="row">
<div class="cell small-12"> <div class="col-12">
<h1><%= test.name %></h1> <h1><%= test.name %></h1>
</div> </div>
<div class="cell small-12"> <div class="col-12">
<p><a href="/test/<%= test.id %>/edit">Edit</a></p> <p><a href="/test/<%= test.id %>/edit">Edit</a></p>
</div> </div>
<div class="cell small-12"> <div class="col-12">
Hardware tested: <%= test.hardware.name %> <p>Hardware tested: <a href="/hardware/<%= test.hardware.id %>"><%= test.hardware.name %></a></p>
</div> </div>
<div class="cell small-12"> <div class="col-12">
<p><%= test.description %></p> <p><%= test.description %></p>
</div> </div>
</div> </div>
<hr> <hr>
<div class="grix-x grix-margin-x"> <div class="row">
<div class="cell small-12"> <div class="col-12">
<form class="u-full-width" action="/result/add" method="post"> <form action="/result/add" method="post">
<input type="hidden" name="result_test" value="<%= test.id %>"> <input type="hidden" name="result_test" value="<%= test.id %>">
<input type="hidden" name="result_referrer" value="test"> <input type="hidden" name="result_referrer" value="test">
<div class="grid-x grid-margin-x"> <div class="row">
<div class="cell medium-5"> <div class="col-12 col-md-5 mb-3 mb-md-0">
<label for="result_benchmark"> <label for="result_benchmark">Add benchmark result:</label>
Add benchmark result: <select class="form-select" id="result_benchmark" name="result_benchmark">
<select class="u-full-width" id="result_benchmark" name="result_benchmark"> <% test.benchmarks.each do |b| %>
<% test.benchmark.each do |b| %>
<option value="<%= b.id %>"><%= b.name %></option> <option value="<%= b.id %>"><%= b.name %></option>
<% end %> <% end %>
</select> </select>
</label>
</div> </div>
<div class="cell medium-2"> <div class="col-4 col-md-2">
<label for="result_average"> <label for="result_average">Average score:</label>
Average score: <input id="result_average" class="form-control" type="text" name="result_average" value="">
<input type="text" id="result_average" name="result_average" value="">
</label>
</div> </div>
<div class="cell medium-2"> <div class="col-4 col-md-2">
<label for="result_minimum"> <label for="result_minimum">Minimum score:</label>
Minimum score: <input id="result_minimum" class="form-control" type="text" name="result_minimum" value="">
<input type="text" id="result_minimum" name="result_minimum" value="">
</label>
</div> </div>
<div class="cell medium-2"> <div class="col-4 col-md-2 mb-3 mb-md-0">
<label for="result_maximum"> <label for="result_maximum">Maximum score:</label>
Maximum score: <input id="result_maximum" class="form-control" type="text" name="result_maximum" value="">
<input type="text" id="result_maximum" name="result_maximum" value="">
</label>
</div> </div>
<div class="cell medium-1"> <div class="col-12 col-md-1 d-flex align-items-stretch mb-3 mb-md-0">
<input type="submit" class="u-full-width button" value="Submit"> <input class="btn btn-primary w-100" type="submit" value="Submit">
</div> </div>
</div> </div>
</form> </form>
@@ -67,8 +59,8 @@
<h4>Benchmark results for this test:</h4> <h4>Benchmark results for this test:</h4>
<table id="results-table" data-test-id="<%= test.id %>"> <table id="results-table" class="table table-hover table-responsive" data-test-id="<%= test.id %>">
<thead> <thead class="table-light">
<tr> <tr>
<th>Benchmark name</th> <th>Benchmark name</th>
<th>Scoring type</th> <th>Scoring type</th>
@@ -79,7 +71,7 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<% test.benchmark.each do |benchmark| %> <% test.benchmarks.each do |benchmark| %>
<tr data-benchmark-id="<%= benchmark.id %>"></tr> <tr data-benchmark-id="<%= benchmark.id %>"></tr>
<% end %> <% end %>
</tbody> </tbody>