Skip to content

Commit 7f6cf6e

Browse files
hamir-suspectdexyk
andauthored
feat(front): add listing mode to workflow queries and UI (#680)
## 📝 Description <img width="1382" height="336" alt="image" src="https://github.com/user-attachments/assets/185610a3-5781-4f43-b3b6-56e35d96eafa" /> ## ✅ Checklist - [ ] I have tested this change - [ ] This change requires documentation update --------- Co-authored-by: Dejan K <[email protected]>
1 parent 603c449 commit 7f6cf6e

File tree

12 files changed

+231
-48
lines changed

12 files changed

+231
-48
lines changed

front/assets/js/memory_cookie.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ export class MemoryCookie {
3131
rootSidebar: false,
3232
rootRequester: true,
3333
projectType: "",
34-
projectRequester: false,
34+
projectListing: "all_pipelines",
35+
projectRequester: "false",
3536
logDark: false,
3637
logWrap: true,
3738
logLive: true,

front/assets/js/project/components/choose_select.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ export class ChooseSelect {
1919
let value = e.target.value;
2020
let key = e.target.getAttribute("data-key")
2121

22+
if (key === "listing_requester") {
23+
this.updateListingRequester(value)
24+
return
25+
}
26+
2227
MemoryCookie.set('project' + key.charAt(0).toUpperCase() + key.slice(1), value)
2328

2429
var u = new Url;
@@ -27,4 +32,30 @@ export class ChooseSelect {
2732
window.location.href = u.toString()
2833
})
2934
}
35+
36+
updateListingRequester(value) {
37+
const selection = this.selectionFor(value)
38+
39+
MemoryCookie.set('projectListing', selection.listing)
40+
MemoryCookie.set('projectRequester', selection.requester)
41+
42+
const url = new Url
43+
url.query['listing'] = selection.listing
44+
url.query['requester'] = selection.requester
45+
delete url.query['page_token']
46+
delete url.query['direction']
47+
48+
window.location.href = url.toString()
49+
}
50+
51+
selectionFor(value) {
52+
switch (value) {
53+
case 'all_by_me':
54+
return { listing: 'all_pipelines', requester: 'true' }
55+
case 'latest_per_branch':
56+
return { listing: 'latest', requester: 'false' }
57+
default:
58+
return { listing: 'all_pipelines', requester: 'false' }
59+
}
60+
}
3061
}

front/assets/js/workflow_list.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export var WorkflowList = {
77
pagination: null,
88
pollmanList: null,
99
container: null,
10-
queryParams: ['page_token', 'direction', 'date_from', 'date_to', 'author'],
10+
queryParams: ['page_token', 'direction', 'date_from', 'date_to', 'author', 'listing', 'requester'],
1111

1212
init: function() {
1313
if(this.initiated === true) { return; }

front/lib/front/memory_cookie.ex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ defmodule Front.MemoryCookie do
1818
"rootSidebar" => false,
1919
"rootRequester" => true,
2020
"projectType" => "",
21+
"projectListing" => "all_pipelines",
2122
"projectRequester" => "false",
2223
"logDark" => false,
2324
"logWrap" => true,

front/lib/front/project_page/model.ex

Lines changed: 59 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
defmodule Front.ProjectPage.Model do
22
use TypedStruct
33
alias Front.{Async, Decorators, Models}
4+
alias InternalApi.PlumberWF.ListKeysetRequest.Direction, as: KeysetDirection
45
require Logger
56

67
typedstruct do
78
field(:project, Front.Model.Project.t())
89
field(:page_token, String.t())
910
field(:direction, String.t())
11+
field(:list_mode, String.t())
1012
field(:user_page?, boolean())
1113
field(:ref_types, String.t())
1214
field(:workflows, [Front.Model.Workflow.t()], enforce: true)
@@ -35,6 +37,7 @@ defmodule Front.ProjectPage.Model do
3537
field(:user_id, String.t())
3638
field(:page_token, String.t(), default: "")
3739
field(:direction, String.t())
40+
field(:list_mode, String.t(), default: "latest")
3841
field(:user_page?, boolean())
3942
field(:ref_types, [String.t()])
4043
end
@@ -51,7 +54,8 @@ defmodule Front.ProjectPage.Model do
5154
@spec get(LoadParams.t()) :: {:ok, __MODULE__.t()} | {:error, String.t()}
5255
def get(params, opts \\ []) do
5356
with true <- first_page?(params),
54-
true <- everyones_page?(params) do
57+
true <- everyones_page?(params),
58+
true <- cacheable_mode?(params) do
5559
fetch_from_cache(params, opts[:force_cold_boot])
5660
else
5761
false ->
@@ -79,7 +83,7 @@ defmodule Front.ProjectPage.Model do
7983
end
8084

8185
def cache_key(params) do
82-
"#{cache_prefix()}/#{cache_version()}/project_id=#{params.project_id}/ref_types=#{params.ref_types}/"
86+
"#{cache_prefix()}/#{cache_version()}/project_id=#{params.project_id}/ref_types=#{params.ref_types}/list_mode=#{params.list_mode}/"
8387
end
8488

8589
@spec refresh(LoadParams.t()) :: {:ok, t(), atom()} | {:error, String.t()}
@@ -167,6 +171,7 @@ defmodule Front.ProjectPage.Model do
167171
project: project,
168172
page_token: params.page_token,
169173
direction: params.direction,
174+
list_mode: params.list_mode,
170175
user_page?: params.user_page?,
171176
ref_types: params.ref_types,
172177
workflows: workflows,
@@ -186,8 +191,16 @@ defmodule Front.ProjectPage.Model do
186191

187192
defp first_page?(params), do: params.page_token == ""
188193
defp everyones_page?(params), do: params.user_page? == false
194+
defp cacheable_mode?(params), do: (params.list_mode || "latest") == "latest"
189195

190196
defp list_workflows(params) do
197+
case params.list_mode do
198+
"all_pipelines" -> list_workflows_keyset(params)
199+
_ -> list_workflows_latest(params)
200+
end
201+
end
202+
203+
defp list_workflows_latest(params) do
191204
list_params = [
192205
page_size: 10,
193206
page_token: params.page_token,
@@ -196,12 +209,7 @@ defmodule Front.ProjectPage.Model do
196209
git_ref_types: params.ref_types
197210
]
198211

199-
list_params =
200-
if params.user_page? do
201-
list_params |> Keyword.merge(requester_id: params.user_id)
202-
else
203-
list_params
204-
end
212+
list_params = maybe_put_requester(list_params, params.user_page?, params.user_id)
205213

206214
workflow_api_metric_name =
207215
if params.user_page? do
@@ -222,4 +230,47 @@ defmodule Front.ProjectPage.Model do
222230

223231
{workflows, next_page_token, previous_page_token}
224232
end
233+
234+
defp list_workflows_keyset(params) do
235+
direction = keyset_direction(params.direction)
236+
237+
list_params =
238+
[
239+
page_size: 10,
240+
page_token: params.page_token,
241+
direction: direction,
242+
project_id: params.project_id,
243+
git_ref_types: params.ref_types
244+
]
245+
|> maybe_put_requester(params.user_page?, params.user_id)
246+
|> Enum.reject(fn {_, value} -> is_nil(value) or value == "" end)
247+
248+
workflow_api_metric_name =
249+
if params.user_page? do
250+
"project_page_model_list_keyset_by_me"
251+
else
252+
"project_page_model_list_keyset"
253+
end
254+
255+
{wfs, next_page_token, previous_page_token} =
256+
Watchman.benchmark(workflow_api_metric_name, fn ->
257+
Models.Workflow.list_keyset(list_params)
258+
end)
259+
260+
workflows =
261+
Watchman.benchmark("project_page_model_decorate_workflows", fn ->
262+
Decorators.Workflow.decorate_many(wfs)
263+
end)
264+
265+
{workflows, next_page_token, previous_page_token}
266+
end
267+
268+
defp maybe_put_requester(list_params, true, requester_id),
269+
do: Keyword.merge(list_params, requester_id: requester_id)
270+
271+
defp maybe_put_requester(list_params, _requester?, _requester_id), do: list_params
272+
273+
defp keyset_direction("next"), do: KeysetDirection.value(:NEXT)
274+
defp keyset_direction("previous"), do: KeysetDirection.value(:PREVIOUS)
275+
defp keyset_direction(_), do: nil
225276
end

front/lib/front_web/controllers/project_controller.ex

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ defmodule FrontWeb.ProjectController do
107107
user_id: user_id,
108108
page_token: params["page_token"] || "",
109109
direction: params["direction"] || "",
110+
list_mode: workflow_list_mode_setting(conn),
110111
user_page?: user_page?(conn),
111112
ref_types: ref_types(conn)
112113
)
@@ -819,6 +820,7 @@ defmodule FrontWeb.ProjectController do
819820
user_id: user_id,
820821
page_token: params["page_token"] || "",
821822
direction: params["direction"] || "",
823+
list_mode: workflow_list_mode_setting(conn),
822824
user_page?: user_page?(conn),
823825
ref_types: ref_types(conn)
824826
)
@@ -841,6 +843,9 @@ defmodule FrontWeb.ProjectController do
841843
branches: model.branches,
842844
type: workflow_list_type_setting(conn),
843845
requester: model.user_page?,
846+
listing: model.list_mode,
847+
listing_requester: combined_listing_requester(model.list_mode, model.user_page?),
848+
all_pipelines_enabled: show_all_pipelines?(conn),
844849
notice: conn |> get_flash(:notice),
845850
social_metatags: true,
846851
workflows: model.workflows
@@ -887,6 +892,7 @@ defmodule FrontWeb.ProjectController do
887892
user_id: user_id,
888893
page_token: params["page_token"] || "",
889894
direction: params["direction"] || "",
895+
list_mode: workflow_list_mode_setting(conn),
890896
user_page?: false,
891897
ref_types: ref_types(conn)
892898
)
@@ -897,8 +903,10 @@ defmodule FrontWeb.ProjectController do
897903
state: "poll",
898904
href: "/projects/#{project.id}/workflows",
899905
params: [
906+
requester: data.user_page?,
900907
page_token: params.page_token,
901-
direction: params.direction
908+
direction: params.direction,
909+
listing: data.list_mode || workflow_list_mode_setting(conn)
902910
]
903911
}
904912

@@ -915,6 +923,9 @@ defmodule FrontWeb.ProjectController do
915923
pollman: pollman,
916924
title: "#{project.name}#{data.organization.name}",
917925
requester: data.user_page?,
926+
listing: data.list_mode,
927+
listing_requester: combined_listing_requester(data.list_mode, data.user_page?),
928+
all_pipelines_enabled: show_all_pipelines?(conn),
918929
type: workflow_list_type_setting(conn),
919930
notice: conn |> get_flash(:notice),
920931
social_metatags: true
@@ -938,7 +949,8 @@ defmodule FrontWeb.ProjectController do
938949
requester: user_page?(conn),
939950
page_token: conn.params["page_token"] || "",
940951
direction: conn.params["direction"] || "",
941-
type: conn.params["type"] || memory["projectType"]
952+
type: conn.params["type"] || memory["projectType"],
953+
listing: model.list_mode || workflow_list_mode_setting(conn)
942954
]
943955
}
944956
end
@@ -949,13 +961,43 @@ defmodule FrontWeb.ProjectController do
949961
conn.params["type"] || memory["projectType"]
950962
end
951963

964+
defp workflow_list_mode_setting(conn) do
965+
memory = conn.req_cookies["memory"] |> MemoryCookie.values()
966+
967+
requested_mode = conn.params["listing"] || memory["projectListing"] || "all_pipelines"
968+
969+
if show_all_pipelines?(conn) do
970+
normalize_list_mode(requested_mode)
971+
else
972+
"latest"
973+
end
974+
end
975+
976+
defp normalize_list_mode("all_pipelines"), do: "all_pipelines"
977+
defp normalize_list_mode(_), do: "latest"
978+
979+
defp show_all_pipelines?(conn) do
980+
FeatureProvider.feature_enabled?(:project_page_all_pipelines,
981+
param: conn.assigns.organization_id
982+
)
983+
end
984+
952985
defp filters(conn) do
986+
list_mode = workflow_list_mode_setting(conn)
987+
requester? = user_page?(conn)
988+
953989
%{
954990
type: workflow_list_type_setting(conn),
955-
requester: user_page?(conn)
991+
requester: requester?,
992+
listing: list_mode,
993+
listing_requester: combined_listing_requester(list_mode, requester?)
956994
}
957995
end
958996

997+
defp combined_listing_requester(_, true), do: "all_by_me"
998+
defp combined_listing_requester("all_pipelines", _), do: "all_pipelines"
999+
defp combined_listing_requester(_, _), do: "latest_per_branch"
1000+
9591001
defp ref_types(conn) do
9601002
conn |> workflow_list_type_setting() |> String.split(",", trim: true)
9611003
end

front/lib/front_web/templates/project/_tabs.html.eex

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,15 @@
11
<style>
2+
#chooseSelect select optgroup {
3+
color: #999;
4+
font-style: normal;
5+
font-weight: normal;
6+
}
7+
8+
#chooseSelect select option {
9+
color: #000;
10+
font-weight: normal;
11+
}
12+
213
.project-jumpto {
314
position: relative;
415
}
@@ -51,23 +62,31 @@
5162

5263
<div class="flex item-start items-center-m mb3">
5364
<div class="flex-auto">
54-
<div id="chooseSelect" class="flex-m items-center">
55-
<select data-key="type" class="db form-control mb3 mb0-m mr3">
56-
<optgroup label="Show everything">
57-
<option value="" <%= if @type == "", do: "selected" %>>Branches, PRs and Tags</option>
65+
<div id="chooseSelect" class="flex-m items-center flex-wrap">
66+
<select data-key="listing_requester" class="db form-control mb3 mb0-m mr3">
67+
<optgroup label="Show all workflows">
68+
<option value="all_pipelines" <%= if @listing_requester == "all_pipelines", do: "selected" %>>Everyone's workflows</option>
69+
<option value="all_by_me" <%= if @listing_requester == "all_by_me", do: "selected" %>>My workflows</option>
70+
</optgroup>
71+
<optgroup label="Show latest workflows per branch, PR, or tag">
72+
<option value="latest_per_branch" <%= if @listing_requester == "latest_per_branch", do: "selected" %>>Latest workflows</option>
5873
</optgroup>
59-
<optgroup label="Filter per type">
60-
<option value="branch" <%= if @type == "branch", do: "selected" %>>Branches only</option>
61-
<option value="pr" <%= if @type == "pr", do: "selected" %>>Pull Requests only</option>
62-
<option value="tag" <%= if @type == "tag", do: "selected" %>>Tags only</option>
63-
</select>
64-
<select data-key="requester" class="db form-control mb3 mb0-m mr3">
65-
<option value="false" <%= if @requester == false, do: "selected" %>>by Everyone</option>
66-
<option value="true" <%= if @requester == true, do: "selected" %>>by Me</option>
6774
</select>
68-
<div class="project-jumpto">
69-
<input type="text" class="form-control" placeholder="Search…">
70-
<div class="jumpto-results"></div>
75+
<div class="flex items-center">
76+
<select data-key="type" class="db form-control mb3 mb0-m mr3">
77+
<optgroup label="Show everything">
78+
<option value="" <%= if @type == "", do: "selected" %>>Branches, PRs and Tags</option>
79+
</optgroup>
80+
<optgroup label="Filter per type">
81+
<option value="branch" <%= if @type == "branch", do: "selected" %>>Branches only</option>
82+
<option value="pr" <%= if @type == "pr", do: "selected" %>>Pull Requests only</option>
83+
<option value="tag" <%= if @type == "tag", do: "selected" %>>Tags only</option>
84+
</optgroup>
85+
</select>
86+
<div class="project-jumpto">
87+
<input type="text" class="form-control" placeholder="Search…">
88+
<div class="jumpto-results"></div>
89+
</div>
7190
</div>
7291
</div>
7392
</div>

front/lib/front_web/templates/project/private.html.eex

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,15 @@ window.InjectedDataByBackend.AssetsPath = "<%= assets_path() %>"
66

77
<div class="bg-washed-gray pa3 br3 mt3 ba b--black-075">
88
<div id="workflow-lists">
9-
<%= render FrontWeb.ProjectView, "_tabs.html", project: @project, conn: @conn, type: @type, requester: @requester, permissions: @permissions %>
9+
<%= render FrontWeb.ProjectView, "_tabs.html",
10+
project: @project,
11+
conn: @conn,
12+
type: @type,
13+
requester: @requester,
14+
listing: @listing,
15+
listing_requester: @listing_requester,
16+
permissions: @permissions,
17+
all_pipelines_enabled: @all_pipelines_enabled %>
1018
<%= render FrontWeb.DashboardView, "partials/_workflows.html", conn: @conn, workflows: @workflows, pagination: @pagination, pollman: @pollman, page: :project %>
1119
</div>
1220
</div>

0 commit comments

Comments
 (0)