Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Project aliases #2644

Merged
merged 71 commits into from
Feb 18, 2025
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
c94f5e2
Generate model ProjectAlias
mo-nathan Dec 26, 2024
b8f3756
Rubocop
mo-nathan Dec 26, 2024
3ac26fb
Hookup ProjectAlias class
mo-nathan Dec 26, 2024
2229d1c
Fix migration to use integers for references
mo-nathan Dec 26, 2024
12c738d
Rubocop
mo-nathan Dec 26, 2024
5aac91a
Merge branch 'main' into njw-project-aliases
mo-nathan Dec 29, 2024
fd9e403
Some simple tests
mo-nathan Dec 29, 2024
744d015
Merge branch 'main' into njw-project-aliases
mo-nathan Dec 31, 2024
f5e79bb
Merge branch 'main' into njw-project-aliases
mo-nathan Jan 5, 2025
2ebaf43
Merge branch 'main' into njw-project-aliases
mo-nathan Jan 7, 2025
ec1e816
First pass at CRUD
mo-nathan Jan 10, 2025
829ea96
Rejigger ProjectAliases
mo-nathan Jan 11, 2025
6fe4e88
Merge branch 'main' into njw-project-aliases
mo-nathan Jan 11, 2025
a1ce799
Rubocop
mo-nathan Jan 11, 2025
8482da1
Merge branch 'main' into njw-project-aliases
mo-nathan Jan 12, 2025
33946f2
Project Alias improvements
mo-nathan Jan 13, 2025
bd5baf9
Merge branch 'main' into njw-project-aliases
mo-nathan Jan 14, 2025
24233b7
Merge branch 'main' into njw-project-aliases
mo-nathan Jan 14, 2025
fb4e4b7
Merge branch 'main' into njw-project-aliases
mo-nathan Jan 15, 2025
2ad9e33
Merge branch 'main' into njw-project-aliases
mo-nathan Jan 16, 2025
ab0ccf8
Get autocompleter to switch from location to user
mo-nathan Jan 17, 2025
16236da
Autocomplete fixes
mo-nathan Jan 17, 2025
441c144
Fix new action for ProjectAliases
mo-nathan Jan 18, 2025
9493462
Merge branch 'main' into njw-project-aliases
mo-nathan Jan 18, 2025
35a2c25
Project Alias form fixes
mo-nathan Jan 18, 2025
339eb57
Add more parens
mo-nathan Jan 18, 2025
ea2d105
Fixes for Project Alias delete routes
mo-nathan Jan 18, 2025
12a46ed
Add tests for Project Alias controller
mo-nathan Jan 18, 2025
edecd37
Rubocop
mo-nathan Jan 18, 2025
bdb6a9e
Merge branch 'main' into njw-project-aliases
mo-nathan Jan 19, 2025
d8f0ba4
PR feedback
mo-nathan Jan 19, 2025
e6ed733
Switch to underscore test names
mo-nathan Jan 19, 2025
ebd42a5
Switch to submit button and cleanup button name
mo-nathan Jan 19, 2025
15d7e37
Add links to targets and remove show link
mo-nathan Jan 19, 2025
e63b77e
Add alias lookup when saving a field slip form
mo-nathan Jan 19, 2025
aff4fd3
Fix broken tests
mo-nathan Jan 22, 2025
cd9ad1b
Merge branch 'main' into njw-project-aliases
mo-nathan Jan 22, 2025
120b5c2
Merge branch 'main' into njw-project-aliases
mo-nathan Jan 23, 2025
d9fd3a0
Update user_str based on new interface for lookup_unique_text_name
mo-nathan Jan 23, 2025
8ed460f
Merge branch 'main' into njw-project-aliases
mo-nathan Jan 25, 2025
03a9b4d
Add aliases to the project members tab
mo-nathan Jan 27, 2025
737701c
Merge branch 'main' into njw-project-aliases
mo-nathan Jan 27, 2025
2ad744d
Add missing partial
mo-nathan Jan 27, 2025
121ed35
Add missing locale string
mo-nathan Jan 27, 2025
796de68
Merge branch 'main' into njw-project-aliases
mo-nathan Jan 28, 2025
126b8a6
Attempt to get modal project alias form working
mo-nathan Jan 29, 2025
c5ec29e
Try adding what might be a needed id in a span
mo-nathan Jan 30, 2025
b9ac087
Fix project alias edit modal
mo-nathan Jan 31, 2025
dc8c31d
Merge branch 'main' into njw-project-aliases
mo-nathan Jan 31, 2025
3c2bf02
Switch to modal for AliasController#new
mo-nathan Feb 2, 2025
1d4eab8
Merge branch 'main' into njw-project-aliases
mo-nathan Feb 9, 2025
64d265b
Merge branch 'main' into njw-project-aliases
mo-nathan Feb 10, 2025
b82e1b1
Got ProjectAliasController#edit modal workflow working
mo-nathan Feb 12, 2025
81b477e
Enable ProjectAlias#new workflow, prevent duplicate aliases, and fix …
mo-nathan Feb 12, 2025
225106b
Merge branch 'main' into njw-project-aliases
mo-nathan Feb 15, 2025
5480e09
Add migration for project alias uniqueness
mo-nathan Feb 15, 2025
cdc7cb3
Flash messages and remove JSON responses
mo-nathan Feb 15, 2025
89c88e0
Add remove buttons and use render_project_alias_user_change everywhere
mo-nathan Feb 15, 2025
2493142
Rubocop
mo-nathan Feb 15, 2025
3ed48d0
Updates to README_CODE
mo-nathan Feb 17, 2025
7aac17b
Merge branch 'main' into njw-project-aliases
mo-nathan Feb 17, 2025
6db7518
Add support for project aliases on the project locations index page
mo-nathan Feb 17, 2025
04cad07
Add notes about Turbo to README_CODE.md
mo-nathan Feb 17, 2025
7016f02
Improve formatting of README_CODE.md
mo-nathan Feb 17, 2025
d397f42
More formatting of README_CODE.md
mo-nathan Feb 17, 2025
d203a22
Cleanup handling of target_id for ProjectAlias
mo-nathan Feb 17, 2025
e1395bc
Rubocop and tests
mo-nathan Feb 17, 2025
56d2698
Full coverage for AliasController
mo-nathan Feb 17, 2025
228abaa
Replace login name with Textile name
mo-nathan Feb 18, 2025
31e4ebe
Switch to using make_table for project alias index
mo-nathan Feb 18, 2025
e5536f9
Add comment to ProjectAlias model
mo-nathan Feb 18, 2025
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
103 changes: 103 additions & 0 deletions app/controllers/projects/aliases_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# frozen_string_literal: true

module Projects
class AliasesController < ApplicationController
before_action :login_required
before_action :pass_query_params, except: [:index]
before_action :set_project_alias, only: [:show, :edit, :update, :destroy]

def index
@project = Project.find(params[:project_id])
@project_aliases = ProjectAlias.all
respond_to do |format|
format.html
format.json { render(json: @project_aliases) }
end
end

def show
respond_to do |format|
format.html
format.json { render(json: @project_alias) }
end
end

def new
@project_alias = ProjectAlias.new(project_id: params.require(:project_id))
end

def edit; end

def create
@project_alias = ProjectAlias.new(project_alias_params)

respond_to do |format|
if @project_alias.save
format.html do
project_alias_redirect(@project_alias)
end
format.json do
render(json: @project_alias, status: :created,
location: @project_alias)
end
else
format.html { render(:new) }
format.json do
render(json: @project_alias.errors, status: :unprocessable_entity)
end
end
end
end

def update
respond_to do |format|
if @project_alias.update(project_alias_params)
format.html do
redirect_to(project_alias_path(
project_id: @project_alias.project_id,
id: @project_alias.id
),
notice: :project_alias_updated.t)
end
format.json { render(json: @project_alias) }
else
format.html { render(:edit) }
format.json do
render(json: @project_alias.errors, status: :unprocessable_entity)
end
end
end
end

def destroy
project_id = @project_alias.project_id
@project_alias.destroy
respond_to do |format|
format.html do
redirect_to(project_aliases_pat(project_id:),
notice: :project_alias_deleted.t)
end
format.json { head(:no_content) }
end
end

private

def project_alias_redirect(project_alias)
redirect_to(project_alias_path(
project_id: project_alias.project_id,
id: project_alias.id
),
notice: :project_alias_created.t)
end

def set_project_alias
@project_alias = ProjectAlias.find(params[:id])
end

def project_alias_params
params.require(:project_alias).permit(:name, :project_id, :target_type,
:location_id, :user_id)
end
end
end
1 change: 1 addition & 0 deletions app/javascript/controllers/autocompleter_controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ export default class extends Controller {
// to refresh the primer (as with location_containing a changed lat/lng).
//
swap({ detail }) {
console.log("swap called");
Copy link
Contributor

@nimmolo nimmolo Jan 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that this Stimulus controller has a method verbose. If you switch your

console.log("swap called")

to

this.verbose("swap called")

and then uncomment the actual method body of verbose, it will log a whole trace of what it's executing (as defined by wherever Jason and I left lines that say this.verbose("Say something");

However that may give you more info than you want.

let type;
if (this.hasSelectTarget) {
type = this.selectTarget.value;
Expand Down
1 change: 1 addition & 0 deletions app/models/location.rb
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ class Location < AbstractModel # rubocop:disable Metrics/ClassLength
has_many :interests, as: :target, dependent: :destroy, inverse_of: :target
has_many :observations
has_many :projects
has_many :project_aliases, as: :target, dependent: :destroy
has_many :species_lists
has_many :herbaria # should be at most one, but nothing preventing more
has_many :users # via profile location
Expand Down
2 changes: 2 additions & 0 deletions app/models/project.rb
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ class Project < AbstractModel # rubocop:disable Metrics/ClassLength
has_many :project_species_lists, dependent: :destroy
has_many :species_lists, through: :project_species_lists

has_many :project_aliases, dependent: :destroy

before_destroy :orphan_drafts
validates :field_slip_prefix, uniqueness: true, allow_blank: true
validates :field_slip_prefix,
Expand Down
20 changes: 20 additions & 0 deletions app/models/project_alias.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# frozen_string_literal: true

class ProjectAlias < ApplicationRecord
belongs_to :target, polymorphic: true
belongs_to :project

validates :name, presence: true

def location_id=(id)
self.target_id = id
end

def user_id=(id)
self.target_id = id
end

def target_type=(type)
type.capitalize
end
end
1 change: 1 addition & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ class User < AbstractModel # rubocop:disable Metrics/ClassLength
has_many :projects_created, class_name: "Project"
has_many :project_members, dependent: :destroy
has_many :projects, through: :project_members, source: :projects
has_many :project_aliases, as: :target, dependent: :destroy
has_many :publications
has_many :queued_emails
has_many :sequences
Expand Down
50 changes: 50 additions & 0 deletions app/views/controllers/projects/aliases/_form.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<%
type = project_alias.target_type.downcase.to_sym || :location
value = project_alias.target.name || ""
%>
<%= form_with(model: project_alias,
data: { controller: :autocompleter, type: }) do |form| %>
<% if project_alias.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(project_alias.errors.count, "error") %> prohibited this project alias from being saved:</h2>
<ul>
<% project_alias.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>

<div class="field">
<%= text_field_with_label(form:, field: :name, label: "#{:Name.t}:", inline: true) %>
</div>
mo-nathan marked this conversation as resolved.
Show resolved Hide resolved

<div class="field">
<%= form.hidden_field(:project_id, value: project_alias.project_id) %>
</div>

<%= tag.div(class: "form-group dropdown",
data: { autocompleter_target: "wrap" } ) do %>
<div class="field">
<%= select_with_label(form:,
field: :target_type,
label: "#{:project_alias_type.t}:",
options: [[:USER.l, :user], [:LOCATION.l, :location]],
inline: true,
selected: type,
data: { autocompleter_target: "select",
action: "autocompleter#swap" }) %>
</div>

<%= autocompleter_hidden_field(form:, type:) %>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this needs the arg hidden_value: @project.location_id or whichever should be prefilled.

I anticipate an issue here, because if I understand correctly you're asking for the stimulus controller to do something magical that it does not yet have the ability to do. There is only ever one hidden field and one field in the HTML, and although the type can swap only the initial values can be prefilled.

If you want each type's default option (whether Location or User) to be prefilled if the user changes back and forth in the select, it seems we will need to store both of these hidden prefill values as data attributes on the Stimulus root autocompleter element, as something like data-hidden-value-location and data-hidden-value-user.

Then we will need to add a mechanism to the Stimulus autocompleter controller swap function that checks for the appropriate prefill value of the new autocompleter type when swapping, and fills it in the hidden field.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm using:

<%= autocompleter_hidden_field(form:, type:, hidden_value: project_alias.target_id) %>

which seems to be working fine. If you think there's still an issue, let me know how to see it.

<%= form.text_field(
:term, value: value, class: "form-control",
data: { autocompleter_target: "input" }
) %>
<%= autocompleter_dropdown %>
<% end %>

<div class="actions">
<%= form.submit %>
</div>
mo-nathan marked this conversation as resolved.
Show resolved Hide resolved
<% end %>
12 changes: 12 additions & 0 deletions app/views/controllers/projects/aliases/edit.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<%
add_project_banner(@project_alias.project)
@container = :wide
mo-nathan marked this conversation as resolved.
Show resolved Hide resolved
project_id = @project_alias.project_id
%>

<h1>Editing Project Alias</h1>

<%= render('form', project_alias: @project_alias) %>

<%= link_to 'Show', project_alias_path(project_id:, id: @project_alias.id) %> |
<%= link_to 'Back', project_aliases_path(project_id:) %>
35 changes: 35 additions & 0 deletions app/views/controllers/projects/aliases/index.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<%
add_project_banner(@project)
@container = :wide
project_id = @project.id
%>

<h1>Project Aliases</h1>

<table class="table table-striped table-project-members mt-3">
<thead>
<tr>
<th>Name</th>
<th>Target Type</th>
<th>Target</th>
<th>Actions</th>
</tr>
</thead>

<tbody>
<% @project_aliases.each do |project_alias| %>
<tr>
<td><%= project_alias.name %></td>
<td><%= project_alias.target_type %></td>
<td><%= project_alias.target.try(:name) %></td>
<td>
<%= link_to 'Show', project_alias_path(project_id:, id: project_alias.id) %>
<%= link_to 'Edit', edit_project_alias_path(project_id:, id: project_alias.id) %>
<%= link_to 'Delete', project_alias_path(project_id:, id: project_alias.id), method: :delete, data: { confirm: 'Are you sure?' } %>
</td>
</tr>
<% end %>
</tbody>
</table>

<%= link_to 'New Project Alias', new_project_alias_path(project_id:) %>
11 changes: 11 additions & 0 deletions app/views/controllers/projects/aliases/new.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<%
add_project_banner(@project_alias.project)
@container = :wide
mo-nathan marked this conversation as resolved.
Show resolved Hide resolved
project_id = @project_alias.project_id
%>

<h1>New Project Alias</h1>

<%= render('form', project_alias: @project_alias) %>

<%= link_to('Back', project_aliases_path(project_id: @project_alias.project_id)) %>
23 changes: 23 additions & 0 deletions app/views/controllers/projects/aliases/show.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<%
add_project_banner(@project_alias.project)
@container = :wide
project_id = @project_alias.project_id
%>

<p>
<strong>Name:</strong>
<%= @project_alias.name %>
</p>

<p>
<strong>Target Type:</strong>
<%= @project_alias.target_type %>
</p>

<p>
<strong>Target:</strong>
<%= @project_alias.target.try(:name) %>
</p>

<%= link_to 'Edit', edit_project_alias_path(project_id:, id: @project_alias.id) %> |
<%= link_to 'Back', project_aliases_path %>
6 changes: 6 additions & 0 deletions config/locales/en.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2893,6 +2893,12 @@
field_slips_too_many_field_slips: You have requested more than [MAX] slips.
field_slips_one_per_page: One field slip per page. Print shops prefer this. Otherwise 6/page which works best on US letter page.

# Project Aliases
project_alias_type: Alias Type
project_alias_created: Field slip was successfully created.
project_alias_destroyed: Field slip was successfully destroyed.
project_alias_updated: Field slip was successfully updated.

##############################################################################

# LESS POPULAR PAGES
Expand Down
1 change: 1 addition & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -662,6 +662,7 @@ def route_actions_hash
controller: "projects/locations"
resources :members, only: [:new, :create, :edit, :update, :index],
controller: "projects/members", param: :candidate
resources :aliases, controller: "projects/aliases"
resources :violations, only: [:index], controller: "projects/violations"
end
# resourceful route won't work because it requires an additional id
Expand Down
18 changes: 18 additions & 0 deletions db/migrate/20241226192904_create_project_aliases.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# frozen_string_literal: true

class CreateProjectAliases < ActiveRecord::Migration[7.1]
def change
create_table(:project_aliases) do |t|
t.integer(:project_id, null: false)
t.integer(:target_id, null: false)
t.string(:target_type, null: false)
t.string(:name)

t.timestamps

t.foreign_key(:projects)
t.index([:target_type, :target_id])
t.index(:project_id)
end
end
end
14 changes: 13 additions & 1 deletion db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema[7.2].define(version: 2024_12_09_041049) do
ActiveRecord::Schema[7.2].define(version: 2024_12_26_192904) do
create_table "api_keys", id: :integer, charset: "utf8mb3", force: :cascade do |t|
t.datetime "created_at", precision: nil
t.datetime "last_used", precision: nil
Expand Down Expand Up @@ -558,6 +558,17 @@
t.datetime "updated_at", null: false
end

create_table "project_aliases", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
t.integer "project_id", null: false
t.integer "target_id", null: false
t.string "target_type", null: false
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["project_id"], name: "index_project_aliases_on_project_id"
t.index ["target_type", "target_id"], name: "index_project_aliases_on_target_type_and_target_id"
end

create_table "project_images", charset: "utf8mb3", force: :cascade do |t|
t.integer "image_id", null: false
t.integer "project_id", null: false
Expand Down Expand Up @@ -965,6 +976,7 @@
t.index ["observation_id"], name: "observation_index"
end

add_foreign_key "project_aliases", "projects"
add_foreign_key "solid_queue_blocked_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade
add_foreign_key "solid_queue_claimed_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade
add_foreign_key "solid_queue_failed_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade
Expand Down
13 changes: 13 additions & 0 deletions test/fixtures/project_aliases.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html

one:
target: rolf
target_type: User
name: MyString
project: eol_project

two:
target: albion
target_type: Location
name: MyString
project: eol_project
16 changes: 16 additions & 0 deletions test/models/project_alias_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# frozen_string_literal: true

require "test_helper"

class ProjectAliasTest < ActiveSupport::TestCase
test "valid user aliases" do
pa = Project.find_by(target_type: "User")
assert_equal("User", pa.target_type)
assert_equal(User, pa.target.class)
end

test "valid location aliases" do
pa = Project.find_by(target_type: "Location")
assert_equal(Location, pa.target.class)
mo-nathan marked this conversation as resolved.
Show resolved Hide resolved
end
end
Loading