diff --git a/Gemfile b/Gemfile index 95fd0462951..db6cb7f4489 100644 --- a/Gemfile +++ b/Gemfile @@ -45,6 +45,7 @@ gem 'rack-timeout-puma' gem 'sidekiq' gem 'ledermann-rails-settings' gem 'pg_search' +gem 'simple-navigation' gem 'react-rails' gem 'browserify-rails' diff --git a/Gemfile.lock b/Gemfile.lock index cc7751ae19b..c3ddf33fcaa 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -353,6 +353,8 @@ GEM connection_pool (~> 2.2, >= 2.2.0) rack-protection (>= 1.5.0) redis (~> 3.2, >= 3.2.1) + simple-navigation (4.0.3) + activesupport (>= 2.3.2) simple_form (3.2.1) actionpack (> 4, < 5.1) activemodel (> 4, < 5.1) @@ -458,6 +460,7 @@ DEPENDENCIES sass-rails (~> 5.0) sdoc (~> 0.4.0) sidekiq + simple-navigation simple_form simplecov uglifier (>= 1.3.0) diff --git a/app/assets/javascripts/components/features/notifications/index.jsx b/app/assets/javascripts/components/features/notifications/index.jsx index 00feeece78f..218196cfd30 100644 --- a/app/assets/javascripts/components/features/notifications/index.jsx +++ b/app/assets/javascripts/components/features/notifications/index.jsx @@ -26,6 +26,12 @@ const Notifications = React.createClass({ trackScroll: React.PropTypes.bool }, + getDefaultProps () { + return { + trackScroll: true + }; + }, + mixins: [PureRenderMixin], componentWillMount () { diff --git a/app/assets/stylesheets/admin.scss b/app/assets/stylesheets/admin.scss new file mode 100644 index 00000000000..6e4234d13dc --- /dev/null +++ b/app/assets/stylesheets/admin.scss @@ -0,0 +1,105 @@ +.admin-wrapper { + width: 100%; + height: 100%; + position: fixed; + background: #1a1c23; + overflow-y: scroll; + + .sidebar { + width: 240px; + position: fixed; + left: 0; + height: 100%; + background: #282c37; + + .logo { + display: block; + margin: 40px auto; + width: 100px; + height: 100px; + } + + ul { + list-style: none; + + a { + display: block; + padding: 15px 25px; + color: rgba(255, 255, 255, 0.7); + text-decoration: none; + transition: all 200ms linear; + + i.fa { + margin-right: 5px; + } + + &:hover { + color: #fff; + background-color: darken(#282c37, 5%); + transition: all 100ms linear; + } + + &.selected { + color: #fff; + background-color: #2b90d9; + + &:hover { + background-color: lighten(#2b90d9, 5%); + } + } + } + } + } + + .content { + margin-left: 240px; + padding: 15px; + } +} + +.filters { + display: flex; + margin-bottom: 20px; + padding-left: 8px; + + .filter-subset { + flex: 0 0 auto; + margin-right: 40px; + + ul { + margin-top: 5px; + list-style: none; + + li { + display: inline-block; + margin-right: 5px; + } + } + + strong { + font-weight: 500; + text-transform: uppercase; + font-size: 12px; + } + + a { + display: inline-block; + color: rgba(255, 255, 255, 0.7); + text-decoration: none; + text-transform: uppercase; + font-size: 12px; + font-weight: 500; + border-bottom: 2px solid #282c37; + + &:hover { + color: #fff; + border-bottom: 2px solid lighten(#282c37, 5%); + } + + &.selected { + color: #2b90d9; + border-bottom: 2px solid #2b90d9; + } + } + } +} diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index bbbeafefe35..609b3072649 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -235,3 +235,4 @@ body { @import 'components'; @import 'about'; @import 'tables'; +@import 'admin'; diff --git a/app/assets/stylesheets/tables.scss b/app/assets/stylesheets/tables.scss index b28b911912f..a3787078672 100644 --- a/app/assets/stylesheets/tables.scss +++ b/app/assets/stylesheets/tables.scss @@ -7,15 +7,15 @@ th, td { padding: 8px; - line-height: 1.42857143; + line-height: 18px; vertical-align: top; - border-top: 1px solid #ddd; + border-top: 1px solid #282c37; text-align: left; } & > thead > tr > th { vertical-align: bottom; - border-bottom: 2px solid #ddd; + border-bottom: 2px solid #282c37; border-top: 0; font-weight: 500; } @@ -24,6 +24,10 @@ font-weight: 500; } + & > tbody > tr:nth-child(odd) > td, & > tbody > tr:nth-child(odd) > th { + background: lighten(#1a1c23, 2%); + } + a { color: #2b90d9; text-decoration: underline; @@ -38,20 +42,20 @@ samp { font-family: 'Roboto Mono', monospace; } -.filters { - list-style: none; - margin-bottom: 20px; +a.table-action-link { + text-decoration: none; + display: inline-block; + margin-right: 5px; + padding: 0 10px; + color: rgba(255, 255, 255, 0.7); + font-weight: 500; - li { - display: inline-block; + &:hover { + color: #fff; } - a { - color: #2b90d9; - text-decoration: underline; - - &:hover { - text-decoration: none; - } + i.fa { + font-weight: 400; + margin-right: 5px; } } diff --git a/app/controllers/admin/accounts_controller.rb b/app/controllers/admin/accounts_controller.rb index 55436d253b7..95107b3dc57 100644 --- a/app/controllers/admin/accounts_controller.rb +++ b/app/controllers/admin/accounts_controller.rb @@ -4,7 +4,7 @@ class Admin::AccountsController < ApplicationController before_action :require_admin! before_action :set_account, except: :index - layout 'public' + layout 'admin' def index @accounts = Account.alphabetic.paginate(page: params[:page], per_page: 40) diff --git a/app/controllers/admin/domain_blocks_controller.rb b/app/controllers/admin/domain_blocks_controller.rb new file mode 100644 index 00000000000..e362957e739 --- /dev/null +++ b/app/controllers/admin/domain_blocks_controller.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +class Admin::DomainBlocksController < ApplicationController + before_action :require_admin! + + layout 'admin' + + def index + @blocks = DomainBlock.paginate(page: params[:page], per_page: 40) + end + + def create + end +end diff --git a/app/controllers/admin/pubsubhubbub_controller.rb b/app/controllers/admin/pubsubhubbub_controller.rb index 7e6bc75ea34..b9e840ffe48 100644 --- a/app/controllers/admin/pubsubhubbub_controller.rb +++ b/app/controllers/admin/pubsubhubbub_controller.rb @@ -3,7 +3,7 @@ class Admin::PubsubhubbubController < ApplicationController before_action :require_admin! - layout 'public' + layout 'admin' def index @subscriptions = Subscription.order('id desc').includes(:account).paginate(page: params[:page], per_page: 40) diff --git a/app/helpers/admin/accounts_helper.rb b/app/helpers/admin/accounts_helper.rb index 5b9cbbacdce..57cd972fa18 100644 --- a/app/helpers/admin/accounts_helper.rb +++ b/app/helpers/admin/accounts_helper.rb @@ -1,2 +1,15 @@ +# frozen_string_literal: true + module Admin::AccountsHelper + def filter_params(more_params) + params.permit(:local, :remote, :by_domain, :silenced, :suspended, :recent).merge(more_params) + end + + def filter_link_to(text, more_params) + link_to text, filter_params(more_params), class: params.merge(more_params).compact == params.compact ? 'selected' : '' + end + + def table_link_to(icon, text, path) + link_to safe_join([fa_icon(icon), text]), path, class: 'table-action-link' + end end diff --git a/app/helpers/admin/domain_blocks_helper.rb b/app/helpers/admin/domain_blocks_helper.rb new file mode 100644 index 00000000000..d66c8d5e145 --- /dev/null +++ b/app/helpers/admin/domain_blocks_helper.rb @@ -0,0 +1,4 @@ +# frozen_string_literal: true + +module Admin::DomainBlocksHelper +end diff --git a/app/helpers/admin/pubsubhubbub_helper.rb b/app/helpers/admin/pubsubhubbub_helper.rb index 41c874a62f8..c2fc2e7da50 100644 --- a/app/helpers/admin/pubsubhubbub_helper.rb +++ b/app/helpers/admin/pubsubhubbub_helper.rb @@ -1,2 +1,4 @@ +# frozen_string_literal: true + module Admin::PubsubhubbubHelper end diff --git a/app/views/admin/accounts/index.html.haml b/app/views/admin/accounts/index.html.haml index a2a3628d67b..99c2af576f6 100644 --- a/app/views/admin/accounts/index.html.haml +++ b/app/views/admin/accounts/index.html.haml @@ -1,9 +1,24 @@ -%ul.filters - %li= link_to 'Local', admin_accounts_path(local: '1') - %li= link_to 'Remote', admin_accounts_path(remote: '1') - %li= link_to 'Silenced', admin_accounts_path(silenced: '1') - %li= link_to 'Suspended', admin_accounts_path(suspended: '1') - %li= link_to 'Most recent', admin_accounts_path(recent: '1') +- content_for :page_title do + Accounts + +.filters + .filter-subset + %strong Location + %ul + %li= filter_link_to 'All', local: nil, remote: nil + %li= filter_link_to 'Local', local: '1', remote: nil + %li= filter_link_to 'Remote', remote: '1', local: nil + .filter-subset + %strong Moderation + %ul + %li= filter_link_to 'All', silenced: nil, suspended: nil + %li= filter_link_to 'Silenced', silenced: '1' + %li= filter_link_to 'Suspended', suspended: '1' + .filter-subset + %strong Order + %ul + %li= filter_link_to 'Alphabetic', recent: nil + %li= filter_link_to 'Most recent', recent: '1' %table.table %thead @@ -38,6 +53,9 @@ %i.fa.fa-check - else %i.fa.fa-times - %td= link_to 'Edit', admin_account_path(account.id) + %td + = table_link_to 'circle', 'Open in web', web_path("accounts/#{account.id}") + = table_link_to 'globe', 'Open public', TagManager.instance.url_for(account) + = table_link_to 'pencil', 'Edit', admin_account_path(account.id) = will_paginate @accounts, pagination_options diff --git a/app/views/admin/domain_blocks/index.html.haml b/app/views/admin/domain_blocks/index.html.haml new file mode 100644 index 00000000000..aedf163f714 --- /dev/null +++ b/app/views/admin/domain_blocks/index.html.haml @@ -0,0 +1,14 @@ +- content_for :page_title do + Domain Blocks + +%table.table + %thead + %tr + %th Domain + %tbody + - @blocks.each do |block| + %tr + %td + %samp= block.domain + += will_paginate @blocks, pagination_options diff --git a/app/views/admin/pubsubhubbub/index.html.haml b/app/views/admin/pubsubhubbub/index.html.haml index ad8cf519831..cb11a502c9e 100644 --- a/app/views/admin/pubsubhubbub/index.html.haml +++ b/app/views/admin/pubsubhubbub/index.html.haml @@ -1,3 +1,6 @@ +- content_for :page_title do + PubSubHubbub + %table.table %thead %tr diff --git a/app/views/layouts/admin.html.haml b/app/views/layouts/admin.html.haml new file mode 100644 index 00000000000..2fc116f45b6 --- /dev/null +++ b/app/views/layouts/admin.html.haml @@ -0,0 +1,11 @@ +- content_for :content do + .admin-wrapper + .sidebar + = link_to root_path do + = image_tag 'logo.png', class: 'logo' + + = render_navigation + .content + = yield + += render template: "layouts/application" diff --git a/config/navigation.rb b/config/navigation.rb new file mode 100644 index 00000000000..1b6615ed028 --- /dev/null +++ b/config/navigation.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +SimpleNavigation::Configuration.run do |navigation| + navigation.items do |primary| + primary.item :accounts, safe_join([fa_icon('users fw'), 'Accounts']), admin_accounts_url + primary.item :pubsubhubbubs, safe_join([fa_icon('paper-plane-o fw'), 'PubSubHubbub']), admin_pubsubhubbub_index_url + primary.item :domain_blocks, safe_join([fa_icon('lock fw'), 'Domain Blocks']), admin_domain_blocks_url + primary.item :sidekiq, safe_join([fa_icon('diamond fw'), 'Sidekiq']), sidekiq_url + primary.item :pghero, safe_join([fa_icon('database fw'), 'PgHero']), pghero_url + end +end diff --git a/config/routes.rb b/config/routes.rb index cde84d3bc84..2d70bdcea6e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -6,8 +6,8 @@ Rails.application.routes.draw do mount ActionCable.server, at: 'cable' authenticate :user, lambda { |u| u.admin? } do - mount Sidekiq::Web, at: 'sidekiq' - mount PgHero::Engine, at: 'pghero' + mount Sidekiq::Web, at: 'sidekiq', as: :sidekiq + mount PgHero::Engine, at: 'pghero', as: :pghero end use_doorkeeper do @@ -46,6 +46,7 @@ Rails.application.routes.draw do namespace :admin do resources :pubsubhubbub, only: [:index] + resources :domain_blocks, only: [:index, :create] resources :accounts, only: [:index, :show, :update] do member do diff --git a/spec/controllers/admin/domain_blocks_controller_spec.rb b/spec/controllers/admin/domain_blocks_controller_spec.rb new file mode 100644 index 00000000000..9d8735ef247 --- /dev/null +++ b/spec/controllers/admin/domain_blocks_controller_spec.rb @@ -0,0 +1,14 @@ +require 'rails_helper' + +RSpec.describe Admin::DomainBlocksController, type: :controller do + before do + sign_in Fabricate(:user, admin: true), scope: :user + end + + describe 'GET #index' do + it 'returns http success' do + get :index + expect(response).to have_http_status(:success) + end + end +end diff --git a/spec/helpers/admin/accounts_helper_spec.rb b/spec/helpers/admin/accounts_helper_spec.rb index 92e29a2229c..b91f258b3a5 100644 --- a/spec/helpers/admin/accounts_helper_spec.rb +++ b/spec/helpers/admin/accounts_helper_spec.rb @@ -1,15 +1,5 @@ require 'rails_helper' -# Specs in this file have access to a helper object that includes -# the Admin::AccountsHelper. For example: -# -# describe Admin::AccountsHelper do -# describe "string concat" do -# it "concats two strings with spaces" do -# expect(helper.concat_strings("this","that")).to eq("this that") -# end -# end -# end RSpec.describe Admin::AccountsHelper, type: :helper do - pending "add some examples to (or delete) #{__FILE__}" + end diff --git a/spec/helpers/admin/domain_blocks_helper_spec.rb b/spec/helpers/admin/domain_blocks_helper_spec.rb new file mode 100644 index 00000000000..cc7ead84e39 --- /dev/null +++ b/spec/helpers/admin/domain_blocks_helper_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe Admin::DomainBlocksHelper, type: :helper do + +end diff --git a/spec/helpers/admin/pubsubhubbub_helper_spec.rb b/spec/helpers/admin/pubsubhubbub_helper_spec.rb index 6603e6dc0ea..673236a7ec2 100644 --- a/spec/helpers/admin/pubsubhubbub_helper_spec.rb +++ b/spec/helpers/admin/pubsubhubbub_helper_spec.rb @@ -1,15 +1,5 @@ require 'rails_helper' -# Specs in this file have access to a helper object that includes -# the Admin::PubsubhubbubHelper. For example: -# -# describe Admin::PubsubhubbubHelper do -# describe "string concat" do -# it "concats two strings with spaces" do -# expect(helper.concat_strings("this","that")).to eq("this that") -# end -# end -# end RSpec.describe Admin::PubsubhubbubHelper, type: :helper do - pending "add some examples to (or delete) #{__FILE__}" + end diff --git a/spec/lib/formatter_spec.rb b/spec/lib/formatter_spec.rb index 927211938a1..7b8259fa62c 100644 --- a/spec/lib/formatter_spec.rb +++ b/spec/lib/formatter_spec.rb @@ -17,7 +17,7 @@ RSpec.describe Formatter do end it 'contains a link' do - expect(subject).to match('google.com') + expect(subject).to match('google.com') end end