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

Refactor Projects Overview Query to Reduce Complexity #2612

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
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
15 changes: 12 additions & 3 deletions lib/lightning/projects.ex
Original file line number Diff line number Diff line change
Expand Up @@ -51,19 +51,28 @@ defmodule Lightning.Projects do
def get_projects_overview(%User{id: user_id}, opts \\ []) do
order_by = Keyword.get(opts, :order_by, {:asc, :name})

latest_activities_subquery =
from(wo in WorkOrder,
join: w in assoc(wo, :workflow),
group_by: w.project_id,
select: %{project_id: w.project_id, last_activity: max(wo.last_activity)}
)

from(p in Project,
join: pu in assoc(p, :project_users),
left_join: w in assoc(p, :workflows),
left_join: pu_all in assoc(p, :project_users),
left_join: la in subquery(latest_activities_subquery),
on: la.project_id == p.id,
where: pu.user_id == ^user_id and is_nil(w.deleted_at),
group_by: [p.id, pu.role],
group_by: [p.id, pu.role, la.last_activity],
select: %ProjectOverviewRow{
id: p.id,
name: p.name,
role: pu.role,
workflows_count: count(w.id, :distinct),
collaborators_count: count(pu_all.user_id, :distinct),
last_activity: max(w.updated_at)
last_activity: la.last_activity
},
order_by: ^dynamic_order_by(order_by)
)
Expand All @@ -75,7 +84,7 @@ defmodule Lightning.Projects do
end

defp dynamic_order_by({direction, :last_activity}) do
{direction, dynamic([_p, _pu, w, _pu_all], max(w.updated_at))}
{direction, dynamic([_p, _pu, _w, _pu_all, la], la.last_activity)}
end

@doc """
Expand Down
4 changes: 2 additions & 2 deletions lib/lightning_web/live/dashboard_live/components.ex
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ defmodule LightningWeb.DashboardLive.Components do
end

def user_projects_table(assigns) do
next_sort_icon = %{asc: "hero-chevron-down", desc: "hero-chevron-up"}
next_sort_icon = %{asc: "hero-chevron-up", desc: "hero-chevron-down"}

assigns =
assign(assigns,
Expand Down Expand Up @@ -200,7 +200,7 @@ defmodule LightningWeb.DashboardLive.Components do
<%= if project.last_activity do %>
<%= Lightning.Helpers.format_date(
project.last_activity,
"%d/%b/%Y %H:%M:%S"
"%d/%m/%Y %H:%M:%S"
) %>
<% else %>
No activity
Expand Down
140 changes: 124 additions & 16 deletions test/lightning/projects_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -1724,6 +1724,108 @@ defmodule Lightning.ProjectsTest do
] = result
end

test "returns the correct latest last_activity from all work_orders across workflows" do
user = insert(:user)

project_a =
%{id: project_a_id} =
insert(:project, name: "Project A", project_users: [%{user_id: user.id}])

workflow_a1 = insert(:simple_workflow, project: project_a)
workflow_a2 = insert(:simple_workflow, project: project_a)
workflow_a3 = insert(:simple_workflow, project: project_a)

insert(:workorder,
workflow: workflow_a1,
last_activity: ~U[2023-10-01 00:00:00Z]
)

insert(:workorder,
workflow: workflow_a2,
last_activity: ~U[2023-10-02 00:00:00Z]
)

insert(:workorder,
workflow: workflow_a3,
last_activity: ~U[2023-10-03 00:00:00Z]
)

project_b =
%{id: project_b_id} =
insert(:project, name: "Project B", project_users: [%{user_id: user.id}])

workflow_b1 = insert(:simple_workflow, project: project_b)
workflow_b2 = insert(:simple_workflow, project: project_b)
workflow_b3 = insert(:simple_workflow, project: project_b)

insert(:workorder,
workflow: workflow_b1,
last_activity: ~U[2023-09-29 00:00:00Z]
)

insert(:workorder,
workflow: workflow_b2,
last_activity: ~U[2023-10-05 00:00:00Z]
)

insert(:workorder,
workflow: workflow_b3,
last_activity: ~U[2023-10-04 00:00:00Z]
)

project_c =
%{id: project_c_id} =
insert(:project, name: "Project C", project_users: [%{user_id: user.id}])

workflow_c1 = insert(:simple_workflow, project: project_c)
workflow_c2 = insert(:simple_workflow, project: project_c)
workflow_c3 = insert(:simple_workflow, project: project_c)

insert(:workorder,
workflow: workflow_c1,
last_activity: ~U[2023-09-28 00:00:00Z]
)

insert(:workorder,
workflow: workflow_c2,
last_activity: ~U[2023-09-30 00:00:00Z]
)

insert(:workorder,
workflow: workflow_c3,
last_activity: ~U[2023-10-06 00:00:00Z]
)

result = Projects.get_projects_overview(user)

assert [
%ProjectOverviewRow{
id: ^project_a_id,
name: "Project A",
last_activity: ~U[2023-10-03 00:00:00.000000Z],
collaborators_count: 1,
role: :editor,
workflows_count: 3
},
%ProjectOverviewRow{
id: ^project_b_id,
name: "Project B",
last_activity: ~U[2023-10-05 00:00:00.000000Z],
collaborators_count: 1,
role: :editor,
workflows_count: 3
},
%ProjectOverviewRow{
id: ^project_c_id,
name: "Project C",
last_activity: ~U[2023-10-06 00:00:00.000000Z],
collaborators_count: 1,
role: :editor,
workflows_count: 3
}
] = Enum.sort_by(result, & &1.name)
end

test "orders projects by name ascending by default" do
user = insert(:user)

Expand All @@ -1741,7 +1843,7 @@ defmodule Lightning.ProjectsTest do
] = result
end

test "orders projects by last_activity (updated_at of workflows) descending when specified" do
test "orders projects by last_activity (latest workorder last_activity) descending when specified" do
user = insert(:user)

project_a =
Expand All @@ -1752,14 +1854,17 @@ defmodule Lightning.ProjectsTest do
%{id: project_b_id} =
insert(:project, name: "Project B", project_users: [%{user_id: user.id}])

insert(:simple_workflow,
project: project_a,
updated_at: ~N[2023-10-05 00:00:00]
workflow_a = insert(:simple_workflow, project: project_a)
workflow_b = insert(:simple_workflow, project: project_b)

insert(:workorder,
workflow: workflow_a,
last_activity: ~U[2023-10-05 00:00:00Z]
)

insert(:simple_workflow,
project: project_b,
updated_at: ~N[2023-10-10 00:00:00]
insert(:workorder,
workflow: workflow_b,
last_activity: ~U[2023-10-10 00:00:00Z]
)

result =
Expand All @@ -1782,22 +1887,25 @@ defmodule Lightning.ProjectsTest do
%{id: project_b_id} =
insert(:project, name: "Project B", project_users: [%{user_id: user.id}])

insert(:simple_workflow,
project: project_a,
updated_at: ~N[2023-10-05 00:00:00]
workflow_a = insert(:simple_workflow, project: project_a)
workflow_b = insert(:simple_workflow, project: project_b)

insert(:workorder,
workflow: workflow_a,
last_activity: ~U[2023-10-05 00:00:00Z]
)

insert(:simple_workflow,
project: project_b,
updated_at: ~N[2023-10-10 00:00:00]
insert(:workorder,
workflow: workflow_b,
last_activity: ~U[2023-10-10 00:00:00Z]
)

result =
Projects.get_projects_overview(user, order_by: {:asc, :last_activity})
Projects.get_projects_overview(user, order_by: {:desc, :last_activity})

assert [
%ProjectOverviewRow{id: ^project_a_id, name: "Project A"},
%ProjectOverviewRow{id: ^project_b_id, name: "Project B"}
%ProjectOverviewRow{id: ^project_b_id, name: "Project B"},
%ProjectOverviewRow{id: ^project_a_id, name: "Project A"}
] = result
end

Expand Down
34 changes: 16 additions & 18 deletions test/lightning_web/live/dashboard_live_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -72,32 +72,26 @@ defmodule LightningWeb.DashboardLiveTest do
project_3 =
insert(:project, project_users: [%{user: build(:user), role: :owner}])

insert(:simple_workflow,
project: project_1,
updated_at: ~N[2023-10-01 12:00:00]
)
workflow_1 = insert(:simple_workflow, project: project_1)

insert(:simple_workflow,
project: project_1,
updated_at: ~N[2023-10-02 12:00:00]
)
insert(:simple_workflow, project: project_2)

insert(:simple_workflow,
project: project_2,
updated_at: ~N[2023-10-05 12:00:00]
insert(:workorder,
workflow: workflow_1,
last_activity: ~U[2023-10-05 00:00:00Z]
)

insert(:simple_workflow,
project: project_2,
updated_at: ~N[2023-10-03 12:00:00]
insert(:workorder,
workflow: workflow_1,
last_activity: ~U[2023-10-10 00:00:00Z]
)

{:ok, view, _html} = live(conn, ~p"/projects")

refute has_element?(view, "#projects-table-row-#{project_3.id}")

assert_project_listed(view, project_1, user, ~N[2023-10-02 12:00:00])
assert_project_listed(view, project_2, user, ~N[2023-10-05 12:00:00])
assert_project_listed(view, project_1, user, ~N[2023-10-10 00:00:00])
assert_project_listed(view, project_2, user, nil)
end

test "projects list do not count deleted workflows", %{
Expand Down Expand Up @@ -295,7 +289,7 @@ defmodule LightningWeb.DashboardLiveTest do
end
end

defp assert_project_listed(view, project, user, max_updated_at) do
defp assert_project_listed(view, project, user, last_activity_date) do
assert has_element?(view, "tr#projects-table-row-#{project.id}")

assert has_element?(
Expand Down Expand Up @@ -344,7 +338,11 @@ defmodule LightningWeb.DashboardLiveTest do
)

formatted_date =
Lightning.Helpers.format_date(max_updated_at, "%d/%b/%Y %H:%M:%S")
if last_activity_date do
Lightning.Helpers.format_date(last_activity_date, "%d/%m/%Y %H:%M:%S")
else
"No activity"
end

assert has_element?(
view,
Expand Down