From 5978607d335584bad3b546889d63a607f06109cc Mon Sep 17 00:00:00 2001 From: "Elias W. BA" Date: Sun, 27 Oct 2024 00:22:35 +0000 Subject: [PATCH] Refactor projects overview query to reduce complexity --- lib/lightning/projects.ex | 15 +- .../live/dashboard_live/components.ex | 4 +- test/lightning/projects_test.exs | 140 ++++++++++++++++-- .../live/dashboard_live_test.exs | 34 ++--- 4 files changed, 154 insertions(+), 39 deletions(-) diff --git a/lib/lightning/projects.ex b/lib/lightning/projects.ex index 7facecf0ac..1ac90f89c4 100644 --- a/lib/lightning/projects.ex +++ b/lib/lightning/projects.ex @@ -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) ) @@ -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 """ diff --git a/lib/lightning_web/live/dashboard_live/components.ex b/lib/lightning_web/live/dashboard_live/components.ex index e8719e81d4..5b04162097 100644 --- a/lib/lightning_web/live/dashboard_live/components.ex +++ b/lib/lightning_web/live/dashboard_live/components.ex @@ -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, @@ -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 diff --git a/test/lightning/projects_test.exs b/test/lightning/projects_test.exs index 0991b1a141..284cade8a8 100644 --- a/test/lightning/projects_test.exs +++ b/test/lightning/projects_test.exs @@ -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) @@ -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 = @@ -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 = @@ -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 diff --git a/test/lightning_web/live/dashboard_live_test.exs b/test/lightning_web/live/dashboard_live_test.exs index 04f0368daf..7f62b7f37d 100644 --- a/test/lightning_web/live/dashboard_live_test.exs +++ b/test/lightning_web/live/dashboard_live_test.exs @@ -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", %{ @@ -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?( @@ -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,