Skip to content

Commit

Permalink
Organizations index and show
Browse files Browse the repository at this point in the history
Index is a section of the dashboard.
Show is the organization view page.
  • Loading branch information
martinemde committed Oct 31, 2024
1 parent 15247cc commit ac32613
Show file tree
Hide file tree
Showing 14 changed files with 311 additions and 31 deletions.
1 change: 1 addition & 0 deletions app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ def breadcrumbs
def add_breadcrumb(name, link = nil)
breadcrumbs << [name, link]
end
helper_method :add_breadcrumb

protected

Expand Down
31 changes: 31 additions & 0 deletions app/controllers/organizations_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
class OrganizationsController < ApplicationController
before_action :redirect_to_signin, only: :index, unless: :signed_in?
before_action :redirect_to_new_mfa, only: :index, if: :mfa_required_not_yet_enabled?
before_action :redirect_to_settings_strong_mfa_required, only: :index, if: :mfa_required_weak_level_enabled?

before_action :find_organization, only: %i[show]

layout "subject"

# GET /organizations
def index
@memberships = current_user.memberships.includes(:organization)

Check warning on line 12 in app/controllers/organizations_controller.rb

View check run for this annotation

Codecov / codecov/patch

app/controllers/organizations_controller.rb#L12

Added line #L12 was not covered by tests
end

# GET /organizations/1
def show
add_breadcrumb t("breadcrumbs.org_name", name: @organization.handle)

Check warning on line 17 in app/controllers/organizations_controller.rb

View check run for this annotation

Codecov / codecov/patch

app/controllers/organizations_controller.rb#L17

Added line #L17 was not covered by tests

@latest_events = [] # @organization.latest_events
@gems = [] # @organization.rubygems
@gems_count = @gems.size
@memberships = @organization.memberships
@memberships_count = @organization.memberships.count

Check warning on line 23 in app/controllers/organizations_controller.rb

View check run for this annotation

Codecov / codecov/patch

app/controllers/organizations_controller.rb#L19-L23

Added lines #L19 - L23 were not covered by tests
end

private

def find_organization
@organization = Organization.find_by_handle!(params[:id])

Check warning on line 29 in app/controllers/organizations_controller.rb

View check run for this annotation

Codecov / codecov/patch

app/controllers/organizations_controller.rb#L29

Added line #L29 was not covered by tests
end
end
10 changes: 10 additions & 0 deletions app/helpers/layout_hepler.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module LayoutHelper
# <%= layout_section "Footer Nav", class: "py-8 bg-orange-100 dark:bg-orange-950 text-neutral-800 dark:text-neutral-200 flex-col items-center">
def layout_section(_name, **options, &)
options[:class] = "w-full px-8 #{options[:class]}"

Check warning on line 4 in app/helpers/layout_hepler.rb

View check run for this annotation

Codecov / codecov/patch

app/helpers/layout_hepler.rb#L4

Added line #L4 was not covered by tests

tag.div(**options) do
tag.div(class: "max-w-screen-xl mx-auto flex flex-col", &)

Check warning on line 7 in app/helpers/layout_hepler.rb

View check run for this annotation

Codecov / codecov/patch

app/helpers/layout_hepler.rb#L6-L7

Added lines #L6 - L7 were not covered by tests
end
end
end
2 changes: 2 additions & 0 deletions app/helpers/organizations_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
module OrganizationsHelper
end
19 changes: 19 additions & 0 deletions app/javascript/controllers/auto_refresh_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/* A controller that, when loaded, causes the page to refresh periodically */

import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
static values = {
interval: { type: Number, default: 5000 }
}

connect() {
this.refresh()
}

refresh() {
setTimeout(() => {
window.location.reload()
}, this.intervalValue)
}
}
12 changes: 12 additions & 0 deletions app/models/organization.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,16 @@ def unique_with_user_handle
after_create do
record_event!(Events::OrganizationEvent::CREATED, actor_gid: memberships.first&.to_gid)
end

def self.find_by_handle(handle)
not_deleted.find_by("lower(handle) = lower(?)", handle)
end

Check warning on line 28 in app/models/organization.rb

View check run for this annotation

Codecov / codecov/patch

app/models/organization.rb#L26-L28

Added lines #L26 - L28 were not covered by tests

def self.find_by_handle!(handle)
find_by_handle(handle) || raise(ActiveRecord::RecordNotFound)
end

Check warning on line 32 in app/models/organization.rb

View check run for this annotation

Codecov / codecov/patch

app/models/organization.rb#L30-L32

Added lines #L30 - L32 were not covered by tests

def to_param
handle
end

Check warning on line 36 in app/models/organization.rb

View check run for this annotation

Codecov / codecov/patch

app/models/organization.rb#L34-L36

Added lines #L34 - L36 were not covered by tests
end
61 changes: 34 additions & 27 deletions app/views/dashboards/_subject.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -3,40 +3,47 @@
current ||= :dashboard
%>

<div class="flex flex-wrap lg:flex-col items-start mb-6 lg:mb-10">
<%= avatar 328, "user_gravatar", theme: :dark, class: "h-24 w-24 lg:h-40 lg:w-40 rounded-lg object-cover mr-4" %>
<div class="mb-8 space-y-4">
<div class="flex flex-wrap lg:flex-col items-start mb-6 lg:mb-10">
<%= avatar 328, "user_gravatar", theme: :dark, class: "h-24 w-24 lg:h-40 lg:w-40 rounded-lg object-cover mr-4" %>

<div class="lg:w-full lg:mt-2">
<h2 class="font-bold text-h4"><%= user.display_handle %></h2>
<% if user.full_name.present? %>
<p class="text-neutral-500 text-b3"><%= user.full_name %></p>
<% end %>
<div class="lg:w-full lg:mt-2">
<h2 class="font-bold text-h4"><%= user.display_handle %></h2>
<% if user.full_name.present? %>
<p class="text-neutral-500 text-b3"><%= user.full_name %></p>
<% end %>
</div>
</div>
</div>

<% if user.public_email? || user == current_user %>
<div class="flex items-center mb-4 text-b3 lg:text-b2">
<%= icon_tag("mail", color: :primary, class: "h-6 w-6 text-orange mr-3") %>
<p class="text-neutral-800 dark:text-white"><%=
mail_to(user.email, encode: "hex")
%></p>
</div>
<% end %>
<% if user.public_email? || user == current_user %>
<div class="flex items-center mb-4 text-b3 lg:text-b2">
<%= icon_tag("mail", color: :primary, class: "h-6 w-6 text-orange mr-3") %>
<p class="text-neutral-800 dark:text-white"><%=
mail_to(user.email, encode: "hex")
%></p>
</div>
<% end %>
<% if user.twitter_username.present? %>
<div class="flex items-center mb-4 text-b3 lg:text-b2">
<%= icon_tag("x-twitter", color: :primary, class: "w-6 text-orange mr-3") %>
<p class="text-neutral-800 dark:text-white"><%=
link_to(
twitter_username(user),
twitter_url(user)
)
%></p>
</div>
<% end %>
<% if user.twitter_username.present? %>
<div class="flex items-center mb-4 text-b3 lg:text-b2">
<%= icon_tag("x-twitter", color: :primary, class: "w-6 text-orange mr-3") %>
<p class="text-neutral-800 dark:text-white"><%=
link_to(
twitter_username(user),
twitter_url(user)
)
%></p>
</div>
<% end %>
</div>

<hr class="hidden lg:block lg:mb-6 border-neutral-400 dark:border-neutral-600" />

<%= render Subject::NavComponent.new(current:) do |nav| %>
<%= nav.link t("layouts.application.header.dashboard"), dashboard_path, name: :dashboard, icon: "space-dashboard" %>
<%= nav.link t("dashboards.show.my_subscriptions"), subscriptions_path, name: :subscriptions, icon: "notifications" %>
<% if current_user.memberships.any? %>
<%= nav.link t("dashboards.show.organizations"), organizations_path, name: :organizations, icon: "organizations" %>
<% end %>
<%= nav.link t("layouts.application.header.settings"), edit_settings_path, name: :settings, icon: "settings" %>
<% end %>
11 changes: 7 additions & 4 deletions app/views/dashboards/show.html.erb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<% @title = t('.title') %>
<% content_for :subject do %>
<% render "dashboards/subject", user: current_user %>
<%= render "dashboards/subject", user: current_user, current: :dashboard %>
<% end %>

<!-- Main Content -->
Expand Down Expand Up @@ -92,9 +92,12 @@
<% end %>
<%= c.divided_list do %>
<% current_user.memberships.preload(:organization).each do |membership| %>
<%= c.list_item_to("#") do %>
<div class="flex justify-between">
<p class="text-neutral-800 dark:text-white"><%= membership.organization.name %></p>
<%= c.list_item_to(organization_path(membership.organization)) do %>
<div class="flex flex-row w-full justify-between items-center">
<div class="flex flex-col">
<p class="text-neutral-800 dark:text-white"><%= membership.organization.name %></p>
<p class="text-b3 text-neutral-600"><%= membership.organization.handle %></p>
</div>
<p class="text-neutral-500 capitalize"><%= membership.role %></p>
</div>
<% end %>
Expand Down
23 changes: 23 additions & 0 deletions app/views/organizations/_subject.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<% current ||= :dashboard %>

<div class="flex flex-wrap lg:flex-col items-start mb-6 lg:mb-10">
<div class="lg:w-full lg:mt-2">
<h2 class="font-bold text-h4"><%= organization.name %></h2>
<p class="text-neutral-500 text-b3"><%= organization.handle %></p>
<p class="my-1">
<span class="shrink px-3 py-1 rounded-full border border-orange text-orange items-center text-b3 uppercase font-semibold">
<%= icon_tag("organizations", size: 6, class: "-mt-1 -ml-1 mr-1 inline-block") -%><%= t("organizations.show.organization") %>
</span>
</p>
</div>
</div>

<hr class="hidden lg:block lg:mb-6 border-neutral-400 dark:border-neutral-600" />

<%= render Subject::NavComponent.new(current:) do |nav| %>
<%= nav.link t("layouts.application.header.dashboard"), dashboard_path, name: :dashboard, icon: "space-dashboard" %>
<%= nav.link t("organizations.show.history"), subscriptions_path, name: :subscriptions, icon: "notifications" %>
<%= nav.link t("organizations.show.gems"), organizations_path, name: :gems, icon: "gems" %>
<%= nav.link t("organizations.show.members"), organizations_path, name: :organizations, icon: "organizations" %>
<%= nav.link t("layouts.application.header.settings"), edit_settings_path, name: :settings, icon: "settings" %>
<% end %>
34 changes: 34 additions & 0 deletions app/views/organizations/index.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<%
@title = t('.title')
add_breadcrumb "Dashboard", dashboard_path
add_breadcrumb "Organizations"
%>
<% content_for :subject do %>
<%= render "dashboards/subject", user: current_user, current: :organizations %>
<% end %>

<!-- Main Content -->
<h1 class="text-h2 mb-10 space-x-2">
<span><%= t("dashboards.show.organizations") %></span>
<% unless @memberships.size.zero? %>
<span class="font-light text-neutral-600"><%= @memberships.size %></span>
<% end %>
</h1>

<!-- Organizations -->
<%= render CardComponent.new do |c| %>
<%= c.divided_list do %>
<% @memberships.each do |membership| %>
<%= c.list_item_to(organization_path(membership.organization.handle)) do %>
<div class="flex flex-row w-full justify-between items-center">
<div class="flex flex-col">
<p class="text-neutral-800 dark:text-white"><%= membership.organization.name %></p>
<p class="text-b3 text-neutral-600"><%= membership.organization.handle %></p>
</div>
<p class="text-neutral-500 capitalize"><%= membership.role %></p>
</div>
<% end %>
<% end %>
<% end %>
<% end %>
88 changes: 88 additions & 0 deletions app/views/organizations/show.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<% content_for :subject do %>
<%= render "organizations/subject", organization: @organization, current: :dashboard %>
<% end %>

<h1 class="text-h2 mb-10"><%= t("dashboards.show.title") %></h1>

<%= render CardComponent.new do |c| %>
<%= c.head(divide: true) do %>
<%= c.title t(".history"), icon: :history %>
<% end %>
<% if @latest_events.empty? %>
<%= prose do %>
<i><%= t('.no_history') %></i>
<% end %>
<% else %>
<%= c.scrollable do %>
<%= render Card::TimelineComponent.new do |t| %>
<% @latest_events.each do |version| %>
<%
pusher_link = if version.pusher.present?
link_to_user(version.pusher)
elsif version.pusher_api_key&.owner.present?
link_to_pusher(version.pusher_api_key.owner)
end
%>
<%= t.timeline_item(version.authored_at, pusher_link) do %>
<div class="flex text-b1 text-neutral-800 dark:text-white"><%= link_to version.rubygem.name, rubygem_path(version.rubygem.slug) %></div>
<%= version_number(version) %>
<% end %>
<% end %>
<% end %>
<% end %>
<% end %>
<% end %>
<%= render CardComponent.new do |c| %>
<%= c.head do %>
<%= c.title t(".gems"), icon: "gems", count: @gems_count %>
<% end %>
<% if @gems.empty? %>
<%= prose do %>
<i><%= t('.no_gems', :creating_link => link_to(t('.creating_link_text'), "https://guides.rubygems.org/make-your-own-gem/")) %></i>
<% end %>
<% else %>
<%= c.divided_list do %>
<% @gems.each do |rubygem| %>
<%= c.list_item_to(
rubygem_path(rubygem.slug),
title: short_info(rubygem.most_recent_version),
) do %>
<div class="flex flex-col w-full justify-between">
<div class="flex flex-row w-full items-center justify-between">
<h4 class="text-b1 flex"><%= rubygem.name %></h4>
<%= version_number(rubygem.most_recent_version) %>
</div>
<div class="flex flex-row w-full items-center justify-between">
<%= download_count_component(rubygem, class: "flex") %>
<div class="flex text-neutral-600"><%= version_date_component(rubygem.most_recent_version) %></div>
</div>
</div>
<% end %>
<% end %>
<% end %>
<% end %>
<% end %>
<%= render CardComponent.new do |c| %>
<%= c.head do %>
<%= c.title t(".members"), icon: "organizations", count: @memberships_count %>
<% end %>
<% if @memberships.empty? %>
<%= prose do %>
<i><%= t('.no_members') %></i>
<% end %>
<% else %>
<%= c.divided_list do %>
<% @memberships.each do |membership| %>
<%= c.list_item_to(profile_path(membership.user.handle)) do %>
<div class="flex justify-between">
<p class="text-neutral-800 dark:text-white"><%= membership.user.name %></p>
<p class="text-neutral-500 capitalize"><%= membership.role %></p>
</div>
<% end %>
<% end %>
<% end %>
<% end %>
<% end %>
9 changes: 9 additions & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,15 @@ en:
popular_gems: Popular Gems
popular:
title: New Releases — Popular Gems
organizations:
index:
title: Organizations
show:
gems: Gems
history: History
members: Members
no_history: No events yet
no_gems: No gems yet
pages:
about:
contributors_amount: "%{count} Rubyists"
Expand Down
1 change: 1 addition & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@
end
resource :dashboard, only: :show, constraints: { format: /html|atom/ }
resources :subscriptions, only: :index
resources :organizations, only: %i[index show]
resources :profiles, only: :show
get "profile/me", to: "profiles#me", as: :my_profile
resource :multifactor_auth, only: %i[update] do
Expand Down
Loading

0 comments on commit ac32613

Please sign in to comment.