Skip to content

Commit 0274776

Browse files
lewisbirkstimja
andauthored
Configuration for default displaying names and duration globally (#844)
Co-authored-by: Tim Jacomb <[email protected]>
1 parent 0dcad05 commit 0274776

File tree

9 files changed

+136
-41
lines changed

9 files changed

+136
-41
lines changed

src/main/frontend/common/user/user-preferences-provider.tsx

Lines changed: 47 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,4 @@
1-
import {
2-
createContext,
3-
ReactNode,
4-
useContext,
5-
useEffect,
6-
useState,
7-
} from "react";
1+
import { createContext, ReactNode, useContext, useState } from "react";
82

93
interface PipelineGraphViewPreferences {
104
showNames: boolean;
@@ -24,24 +18,40 @@ const UserPreferencesContext = createContext<
2418

2519
const makeKey = (setting: string) => `pgv-graph-view.${setting}`;
2620

27-
const loadFromLocalStorage = <T,>(key: string, fallback: T): T => {
28-
if (typeof window === "undefined") {
21+
const parsePreferenceValue = <T,>(
22+
value: string | undefined,
23+
fallback: T,
24+
): T => {
25+
if (value === undefined) {
2926
return fallback;
3027
}
28+
if (typeof fallback === "boolean") {
29+
return (value === "true") as typeof fallback;
30+
}
31+
return value as unknown as T;
32+
};
33+
34+
const loadFromLocalStorage = <T,>(key: string, fallback: T): T => {
3135
try {
32-
const value = window.localStorage.getItem(key);
33-
if (value !== null) {
34-
if (typeof fallback === "boolean") {
35-
return (value === "true") as typeof fallback;
36-
}
37-
return value as unknown as T;
38-
}
36+
const value = window.localStorage.getItem(key) ?? undefined;
37+
return parsePreferenceValue(value, fallback);
3938
} catch (e) {
4039
console.error(`Error loading localStorage key "${key}"`, e);
4140
}
4241
return fallback;
4342
};
4443

44+
const loadFromDOM = <T,>(key: string, fallback: T): T => {
45+
const preferencesModule = document.querySelector(
46+
"[data-module='user-preferences']",
47+
);
48+
const value =
49+
preferencesModule && "dataset" in preferencesModule
50+
? (preferencesModule as HTMLElement).dataset[key]
51+
: undefined;
52+
return parsePreferenceValue(value, fallback);
53+
};
54+
4555
export const UserPreferencesProvider = ({
4656
children,
4757
}: {
@@ -51,27 +61,38 @@ export const UserPreferencesProvider = ({
5161
const stageDurationsKey = makeKey("stageDurations");
5262

5363
const [showNames, setShowNames] = useState<boolean>(
54-
loadFromLocalStorage(stageNamesKey, defaultPreferences.showNames),
64+
loadFromLocalStorage(
65+
stageNamesKey,
66+
loadFromDOM("preferenceShowStageNames", defaultPreferences.showNames),
67+
),
5568
);
5669
const [showDurations, setShowDurations] = useState<boolean>(
57-
loadFromLocalStorage(stageDurationsKey, defaultPreferences.showDurations),
70+
loadFromLocalStorage(
71+
stageDurationsKey,
72+
loadFromDOM(
73+
"preferenceShowStageDurations",
74+
defaultPreferences.showDurations,
75+
),
76+
),
5877
);
5978

60-
useEffect(() => {
61-
window.localStorage.setItem(stageNamesKey, String(showNames));
62-
}, [showNames]);
79+
const persistShowNames = (val: boolean) => {
80+
window.localStorage.setItem(stageNamesKey, String(val));
81+
setShowNames(val);
82+
};
6383

64-
useEffect(() => {
65-
window.localStorage.setItem(stageDurationsKey, String(showDurations));
66-
}, [showDurations]);
84+
const persistShowDurations = (val: boolean) => {
85+
window.localStorage.setItem(stageDurationsKey, String(val));
86+
setShowDurations(val);
87+
};
6788

6889
return (
6990
<UserPreferencesContext.Provider
7091
value={{
7192
showNames,
72-
setShowNames,
93+
setShowNames: persistShowNames,
7394
showDurations,
74-
setShowDurations,
95+
setShowDurations: persistShowDurations,
7596
}}
7697
>
7798
{children}

src/main/java/io/jenkins/plugins/pipelinegraphview/PipelineGraphViewConfiguration.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
public class PipelineGraphViewConfiguration extends GlobalConfiguration {
1515

1616
private boolean showGraphOnJobPage;
17+
private boolean showStageNames;
18+
private boolean showStageDurations;
1719
private boolean showGraphOnBuildPage;
1820

1921
public PipelineGraphViewConfiguration() {
@@ -30,6 +32,26 @@ public void setShowGraphOnJobPage(boolean showGraphOnJobPage) {
3032
save();
3133
}
3234

35+
public boolean isShowStageNames() {
36+
return showStageNames;
37+
}
38+
39+
@DataBoundSetter
40+
public void setShowStageNames(boolean showStageNames) {
41+
this.showStageNames = showStageNames;
42+
save();
43+
}
44+
45+
public boolean isShowStageDurations() {
46+
return showStageDurations;
47+
}
48+
49+
@DataBoundSetter
50+
public void setShowStageDurations(boolean showStageDurations) {
51+
this.showStageDurations = showStageDurations;
52+
save();
53+
}
54+
3355
public boolean isShowGraphOnBuildPage() {
3456
return showGraphOnBuildPage;
3557
}

src/main/java/io/jenkins/plugins/pipelinegraphview/multipipelinegraphview/MultiPipelineGraphViewAction.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.fasterxml.jackson.core.JsonProcessingException;
44
import com.fasterxml.jackson.databind.ObjectMapper;
55
import hudson.model.Action;
6+
import hudson.model.Item;
67
import hudson.security.Permission;
78
import hudson.util.HttpResponses;
89
import hudson.util.RunList;
@@ -40,17 +41,28 @@ public boolean isBuildable() {
4041
}
4142

4243
public Permission getPermission() {
43-
return target.BUILD;
44+
return Item.BUILD;
4445
}
4546

4647
public Permission getConfigurePermission() {
47-
return target.CONFIGURE;
48+
return Item.CONFIGURE;
4849
}
4950

51+
@SuppressWarnings("unused")
5052
public boolean isShowGraphOnJobPage() {
5153
return PipelineGraphViewConfiguration.get().isShowGraphOnJobPage();
5254
}
5355

56+
@SuppressWarnings("unused")
57+
public boolean isShowStageNames() {
58+
return PipelineGraphViewConfiguration.get().isShowStageNames();
59+
}
60+
61+
@SuppressWarnings("unused")
62+
public boolean isShowStageDurations() {
63+
return PipelineGraphViewConfiguration.get().isShowStageDurations();
64+
}
65+
5466
@GET
5567
@WebMethod(name = "tree")
5668
public HttpResponse getTree(StaplerRequest2 req) throws JsonProcessingException {

src/main/resources/io/jenkins/plugins/pipelinegraphview/PipelineGraphViewConfiguration/config.jelly

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,20 @@
22

33
<?jelly escape-by-default='true'?>
44
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form">
5-
<f:section title="${%Pipeline graph view}">
5+
<f:section title="${%pipelineStages}">
66
<f:entry>
7-
<f:checkbox field="showGraphOnJobPage" title="${%Show pipeline graph on job page}" />
7+
<f:checkbox field="showGraphOnJobPage" title="${%pipelineStageShowOnPage}" />
88
</f:entry>
99
<f:entry>
10-
<f:checkbox field="showGraphOnBuildPage" title="${%Show pipeline graph on build page}" />
10+
<f:checkbox field="showStageNames" title="${%pipelineStageShowStageNames}" />
11+
</f:entry>
12+
<f:entry>
13+
<f:checkbox field="showStageDurations" title="${%pipelineStageShowStageDurations}" />
14+
</f:entry>
15+
</f:section>
16+
<f:section title="${%pipelineGraph}">
17+
<f:entry>
18+
<f:checkbox field="showGraphOnBuildPage" title="${%pipelineGraphShowOnPage}" />
1119
</f:entry>
1220
</f:section>
1321
</j:jelly>
Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,6 @@
1-
Show\ pipeline\ graph\ on\ job\ page=Show pipeline graph on job page
2-
Show\ pipeline\ graph\ on\ build\ page=Show pipeline graph on build page
1+
pipelineStages=Pipeline Stages
2+
pipelineStageShowOnPage=Show pipeline stages on job page
3+
pipelineStageShowStageNames=Show stage names by default
4+
pipelineStageShowStageDurations=Show stage durations by default
5+
pipelineGraph=Pipeline Graph
6+
pipelineGraphShowOnPage=Show pipeline graph on build page

src/main/resources/io/jenkins/plugins/pipelinegraphview/multipipelinegraphview/MultiPipelineGraphViewAction/index.jelly

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424
<template data-module="permissions"
2525
data-permission-configure="${configPermission}"
2626
/>
27+
<template data-module="user-preferences"
28+
data-preference-show-stage-names="${it.showStageNames}"
29+
data-preference-show-stage-durations="${it.showStageDurations}"/>
2730

2831
<div id="multiple-pipeline-root"
2932
data-current-job-path="${rootURL + '/' + it.jobUrl}"

src/main/resources/io/jenkins/plugins/pipelinegraphview/multipipelinegraphview/MultiPipelineGraphViewAction/jobMain.jelly

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
</j:set>
88
<!-- workaround floatingBox elements overlapping until page is reworked -->
99
<div class="clearfix" />
10+
<template data-module="user-preferences"
11+
data-preference-show-stage-names="${it.showStageNames}"
12+
data-preference-show-stage-durations="${it.showStageDurations}"/>
13+
1014
<l:card title="${%Stages}" expandable="multi-pipeline-graph" controls="${controls}">
1115
<div id="multiple-pipeline-root"
1216
data-current-job-path="${rootURL + '/' + it.jobUrl}"

src/test/java/io/jenkins/plugins/pipelinegraphview/PipelineGraphViewTest.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import io.jenkins.plugins.casc.misc.ConfiguredWithCode;
77
import io.jenkins.plugins.casc.misc.JenkinsConfiguredWithCodeRule;
88
import io.jenkins.plugins.casc.misc.junit.jupiter.WithJenkinsConfiguredWithCode;
9+
import io.jenkins.plugins.pipelinegraphview.playwright.ManageAppearancePage;
910
import io.jenkins.plugins.pipelinegraphview.playwright.PipelineJobPage;
1011
import io.jenkins.plugins.pipelinegraphview.playwright.PlaywrightConfig;
1112
import io.jenkins.plugins.pipelinegraphview.utils.PipelineState;
@@ -27,11 +28,19 @@ class PipelineGraphViewTest {
2728
// http://localhost:8080/jenkins
2829

2930
@Test
30-
@ConfiguredWithCode("configure-appearance.yml")
3131
void smokeTest(Page p, JenkinsConfiguredWithCodeRule j) throws Exception {
3232
String name = "Integration Tests";
3333
WorkflowRun run = TestUtils.createAndRunJob(j, name, "smokeTest.jenkinsfile", Result.FAILURE);
3434

35+
new ManageAppearancePage(p, j.jenkins.getRootUrl())
36+
.goTo()
37+
.displayPipelineOnBuildPage()
38+
.displayPipelineOnJobPage()
39+
.setPipelineGraphAsConsoleProvider()
40+
.displayNamesOnStageViewByDefault()
41+
.displayDurationsOnStageViewByDefault()
42+
.save();
43+
3544
new PipelineJobPage(p, run.getParent())
3645
.goTo()
3746
.hasBuilds(1)

src/test/java/io/jenkins/plugins/pipelinegraphview/playwright/ManageAppearancePage.java

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,22 +11,22 @@
1111
public class ManageAppearancePage extends JenkinsPage<ManageAppearancePage> {
1212

1313
private static final Logger log = LoggerFactory.getLogger(ManageAppearancePage.class);
14-
private final String baseUrl;
14+
private final String manageUrl;
1515

1616
public ManageAppearancePage(Page page, String baseUrl) {
1717
super(page, baseUrl + "manage/appearance/");
18-
this.baseUrl = baseUrl;
18+
this.manageUrl = baseUrl + "manage/";
1919
}
2020

2121
public ManageAppearancePage displayPipelineOnJobPage() {
22-
log.info("Clicking on the 'Show pipeline graph on job' checkbox");
23-
page.getByText("Show pipeline graph on job").click();
22+
log.info("Clicking on the 'Show pipeline stages on job page' checkbox");
23+
page.getByText("Show pipeline stages on job page").click();
2424
return this;
2525
}
2626

2727
public ManageAppearancePage displayPipelineOnBuildPage() {
28-
log.info("Clicking on the 'Show pipeline graph on build' checkbox");
29-
page.getByText("Show pipeline graph on build").click();
28+
log.info("Clicking on the 'Show pipeline graph on build page' checkbox");
29+
page.getByText("Show pipeline graph on build page").click();
3030
return this;
3131
}
3232

@@ -39,12 +39,24 @@ public ManageAppearancePage setPipelineGraphAsConsoleProvider() {
3939
return this;
4040
}
4141

42+
public ManageAppearancePage displayNamesOnStageViewByDefault() {
43+
log.info("Clicking on the 'Display names on stage view by default' checkbox");
44+
page.getByText("Show stage names by default").click();
45+
return this;
46+
}
47+
48+
public ManageAppearancePage displayDurationsOnStageViewByDefault() {
49+
log.info("Clicking on the 'Display durations on stage view by default' checkbox");
50+
page.getByText("Show stage durations by default").click();
51+
return this;
52+
}
53+
4254
public void save() {
4355
log.info("Saving the changes");
4456
Locator button = page.getByRole(
4557
AriaRole.BUTTON, new Page.GetByRoleOptions().setExact(true).setName("Save"));
4658
assertThat(button).isEnabled();
4759
button.click();
48-
isAtUrl(this.baseUrl + "manage/");
60+
isAtUrl(this.manageUrl);
4961
}
5062
}

0 commit comments

Comments
 (0)