Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ gem "bootstrap-sass", "3.4.1"
# Use Puma as the app server
gem "puma", "~> 7.2"
# Use SCSS for stylesheets
gem "sass-rails", "~> 5.0"
gem "sass-rails", "~> 6.0"

gem "bourbon"
gem "matrix"
Expand Down Expand Up @@ -108,4 +108,4 @@ gem "coffee-script"

gem "pundit", "~> 2.2"

gem "madmin", "~> 1.2"
gem "madmin", "~> 2.0"
63 changes: 41 additions & 22 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,10 @@ GEM
logger
i18n (1.15.2)
concurrent-ruby (~> 1.0)
importmap-rails (2.2.3)
actionpack (>= 6.0.0)
activesupport (>= 6.0.0)
railties (>= 6.0.0)
io-console (0.8.2)
irb (1.18.0)
pp (>= 0.6.0)
Expand Down Expand Up @@ -195,9 +199,13 @@ GEM
loofah (2.25.2)
crass (~> 1.0.2)
nokogiri (>= 1.12.0)
madmin (1.2.8)
madmin (2.3.3)
importmap-rails
pagy (>= 3.5)
rails (>= 6.0.3)
propshaft
rails (>= 7.0.0)
stimulus-rails
turbo-rails
mail (2.9.1)
logger
mini_mime (>= 0.1.1)
Expand Down Expand Up @@ -273,7 +281,10 @@ GEM
actionpack (>= 4.2)
omniauth (~> 2.0)
orm_adapter (0.5.0)
pagy (6.1.0)
pagy (43.6.0)
json
uri
yaml
parallel (2.1.0)
parser (3.3.12.0)
ast (~> 2.4.1)
Expand All @@ -283,6 +294,10 @@ GEM
prettyprint
prettyprint (0.2.0)
prism (1.9.0)
propshaft (1.3.2)
actionpack (>= 7.0.0)
activesupport (>= 7.0.0)
rack
public_suffix (7.0.5)
puma (7.2.1)
nio4r (~> 2.0)
Expand Down Expand Up @@ -398,19 +413,16 @@ GEM
rubocop-ast (>= 1.47.1, < 2.0)
ruby-progressbar (1.13.0)
rubyzip (2.3.2)
sass (3.7.4)
sass-listen (~> 4.0.0)
sass-listen (4.0.0)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
sass-rails (5.1.0)
railties (>= 5.2.0)
sass (~> 3.1)
sprockets (>= 2.8, < 4.0)
sprockets-rails (>= 2.0, < 4.0)
tilt (>= 1.1, < 3)
sass-rails (6.0.0)
sassc-rails (~> 2.1, >= 2.1.1)
sassc (2.4.0)
ffi (~> 1.9)
sassc-rails (2.1.2)
railties (>= 4.0.0)
sassc (>= 2.0)
sprockets (> 3.0)
sprockets-rails
tilt
securerandom (0.4.1)
selenium-webdriver (4.10.0)
rexml (~> 3.2, >= 3.2.5)
Expand All @@ -434,12 +446,13 @@ GEM
hashie (>= 0.1.0, < 6)
version_gem (~> 1.1, >= 1.1.14)
spring (3.0.0)
sprockets (3.7.2)
sprockets (4.2.2)
concurrent-ruby (~> 1.0)
rack (> 1, < 3)
sprockets-rails (3.4.2)
actionpack (>= 5.2)
activesupport (>= 5.2)
logger
rack (>= 2.2.4, < 4)
sprockets-rails (3.5.2)
actionpack (>= 6.1)
activesupport (>= 6.1)
sprockets (>= 3.0.0)
stackprof (0.2.26)
standard (1.56.0)
Expand All @@ -456,12 +469,17 @@ GEM
rubocop-performance (~> 1.26.0)
standardrb (1.0.1)
standard
stimulus-rails (1.3.4)
railties (>= 6.0.0)
terser (1.1.18)
execjs (>= 0.3.0, < 3)
thor (1.5.0)
tilt (2.3.0)
tilt (2.8.0)
timeout (0.6.1)
tsort (0.2.0)
turbo-rails (2.0.23)
actionpack (>= 7.1.0)
railties (>= 7.1.0)
turbolinks (5.2.1)
turbolinks-source (~> 5.2)
turbolinks-source (5.2.0)
Expand Down Expand Up @@ -492,6 +510,7 @@ GEM
websocket-extensions (0.1.5)
xpath (3.2.0)
nokogiri (~> 1.8)
yaml (0.4.0)
zeitwerk (2.8.2)

PLATFORMS
Expand Down Expand Up @@ -520,7 +539,7 @@ DEPENDENCIES
jquery-rails
jquery-ui-rails (~> 8.0)
listen (~> 3.7)
madmin (~> 1.2)
madmin (~> 2.0)
matrix
mimemagic (~> 0.3.8)
newrelic_rpm
Expand All @@ -536,7 +555,7 @@ DEPENDENCIES
recursive-open-struct
redcarpet (~> 3.5.1)
rspec-rails (~> 6.1)
sass-rails (~> 5.0)
sass-rails (~> 6.0)
sentry-rails
sentry-ruby
shoulda-matchers (~> 3.1)
Expand Down
2 changes: 1 addition & 1 deletion app/assets/stylesheets/1-utilities/_basic.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
box-sizing: border-box;
}
main {
min-height: calc(100vh - 160px);
min-height: unquote("calc(100vh - 160px)");
padding-bottom: 60px;
}
::selection {
Expand Down
2 changes: 1 addition & 1 deletion app/assets/stylesheets/4-molecules/_floors.scss
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
justify-content: center;
width: 100%;
overflow: hidden;
height: calc(100vh - 160px);
height: unquote("calc(100vh - 160px)");
margin: -100px 0;
}
}
2 changes: 2 additions & 0 deletions app/assets/stylesheets/project.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

@import "1-utilities/variables";

.projects-controller {
&.index-action {
.btn-group {
Expand Down
2 changes: 1 addition & 1 deletion app/assets/stylesheets/stories.scss
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@
.extra_info_preview .content,
.story_preview .content {
overflow: auto;
max-height: min(50vh, 700px);
max-height: unquote("min(50vh, 700px)");
// prevent long links from overflowing
a {
word-break: break-all;
Expand Down
3 changes: 3 additions & 0 deletions app/views/madmin/application/_javascript.html.erb
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
<%# madmin's npm_rails_version helper was removed in 2.x; reproduce it here.
Pins @rails/* unpkg packages to the matching Rails version (or "main" for prereleases). %>
<% npm_rails_version = Rails.version.match?(/\A\d+\.\d+\.\d+\z/) ? Rails.version : "main" %>
<script src="https://cdn.tailwindcss.com?plugins=forms,typography,aspect-ratio,line-clamp"></script>
<%= stylesheet_link_tag "https://unpkg.com/flatpickr/dist/flatpickr.min.css", "data-turbo-track": "reload" %>
<%= stylesheet_link_tag "https://unpkg.com/trix/dist/trix.css", "data-turbo-track": "reload" %>
Expand Down
13 changes: 12 additions & 1 deletion app/views/madmin/application/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,15 @@
</tbody>
</table>
</div>
<%== render(partial: 'madmin/pagy/nav', locals: { pagy: @pagy }) if @pagy.pages > 1 %>
<%# madmin 2.x dropped the madmin/pagy/_nav partial in favor of pagy's own
helpers. series_nav/info_tag are the pagy 43+ API; pagy_nav/pagy_info the
older one. %>
<div class="pagination">
<% if @pagy.respond_to?(:series_nav) %>
<%== @pagy.series_nav if @pagy.last > 1 %>
<%== @pagy.info_tag %>
<% else %>
<%== pagy_nav @pagy if @pagy.last > 1 %>
<%== pagy_info @pagy %>
<% end %>
</div>
6 changes: 5 additions & 1 deletion config/environments/production.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@
# Apache or NGINX already handles this.
config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present?

config.assets.css_compressor = :sass
# Do not use the SassC/libsass CSS compressor: it re-parses already-compiled
# CSS and evaluates arithmetic inside calc()/min() (e.g. `100vh - 160px`),
# raising "Incompatible units" on valid CSS. Set to nil explicitly since
# sprockets-rails otherwise defaults to :sass when sassc is available.
config.assets.css_compressor = nil
config.assets.js_compressor = :terser

# Do not fallback to assets pipeline if a precompiled asset is missed.
Expand Down
56 changes: 56 additions & 0 deletions spec/requests/madmin/authorization_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
require "rails_helper"

# The madmin interface is gated by Madmin::ApplicationController#ensure_admin,
# which redirects anyone who is not a signed-in admin back to the root path.
# These specs lock that behavior down across a representative set of routes.
RSpec.describe "Madmin authorization", type: :request do
after { Warden.test_reset! }

# One route per controller under /madmin, enough to prove the shared
# before_action guards every resource and the dashboard.
let(:guarded_paths) do
[
"/madmin",
"/madmin/projects",
"/madmin/stories",
"/madmin/estimates",
"/madmin/users",
"/madmin/version_jumps"
]
end

context "when not signed in" do
it "redirects every madmin path to the root path" do
guarded_paths.each do |path|
get path
expect(response).to redirect_to("/"), "expected #{path} to redirect to /"
end
end
end

context "when signed in as a non-admin user" do
let(:user) { FactoryBot.create(:user, admin: false) }

before { login_as(user, scope: :user) }

it "redirects every madmin path to the root path" do
guarded_paths.each do |path|
get path
expect(response).to redirect_to("/"), "expected #{path} to redirect to /"
end
end
end

context "when signed in as an admin user" do
let(:admin) { FactoryBot.create(:user, :admin) }

before { login_as(admin, scope: :user) }

it "grants access to every madmin path" do
guarded_paths.each do |path|
get path
expect(response).to have_http_status(:ok), "expected #{path} to return 200"
end
end
end
end
20 changes: 20 additions & 0 deletions spec/requests/madmin/dashboard_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
require "rails_helper"

# The dashboard renders the madmin layout (including _javascript.html.erb),
# so this request spec also guards against layout/partial regressions such as
# the removed `npm_rails_version` helper.
RSpec.describe "Madmin dashboard", type: :request do
let(:admin) { FactoryBot.create(:user, :admin) }

before { login_as(admin, scope: :user) }
after { Warden.test_reset! }

describe "GET /madmin" do
it "renders the dashboard successfully" do
get "/madmin"

expect(response).to have_http_status(:ok)
expect(response.body).to include("madmin")
end
end
end
44 changes: 44 additions & 0 deletions spec/requests/madmin/estimates_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
require "rails_helper"

# Estimates are registered as: resources :estimates, except: [:update, :edit, :create]
RSpec.describe "Madmin estimates", type: :request do
let(:admin) { FactoryBot.create(:user, :admin) }
let!(:estimate) { FactoryBot.create(:estimate) }

before { login_as(admin, scope: :user) }
after { Warden.test_reset! }

describe "GET /madmin/estimates" do
it "lists estimates" do
get "/madmin/estimates"

expect(response).to have_http_status(:ok)
end
end

describe "GET /madmin/estimates/new" do
it "renders the new form" do
get "/madmin/estimates/new"

expect(response).to have_http_status(:ok)
end
end

describe "GET /madmin/estimates/:id" do
it "shows the estimate" do
get "/madmin/estimates/#{estimate.id}"

expect(response).to have_http_status(:ok)
end
end

describe "DELETE /madmin/estimates/:id" do
it "destroys the estimate" do
expect {
delete "/madmin/estimates/#{estimate.id}"
}.to change(Estimate, :count).by(-1)

expect(response).to have_http_status(:redirect)
end
end
end
28 changes: 28 additions & 0 deletions spec/requests/madmin/pagination_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
require "rails_helper"

# Guards the shared madmin/application/index.html.erb pagination path.
#
# The index partial only renders the pagination nav when there is more than
# one page of results (pagy's default limit is 20). An older madmin override
# rendered a `madmin/pagy/_nav` partial that no longer ships with madmin 2.x,
# raising ActionView::MissingTemplate once a list grew past one page. The
# single-record index specs never hit this branch, so this spec creates enough
# records to paginate and exercise the nav rendering.
RSpec.describe "Madmin pagination", type: :request do
let(:admin) { FactoryBot.create(:user, :admin) }

before { login_as(admin, scope: :user) }
after { Warden.test_reset! }

describe "GET /madmin/version_jumps with more than one page of records" do
before { FactoryBot.create_list(:version_jump, 21) }

it "renders the index with pagination navigation" do
get "/madmin/version_jumps"

expect(response).to have_http_status(:ok)
# pagy builds links to subsequent pages using the `page` query param
expect(response.body).to include("page=2")
end
end
end
Loading
Loading