Skip to content

Commit e53252e

Browse files
authored
Externalise start and end node names (#714)
1 parent 8c82c77 commit e53252e

25 files changed

+215
-171
lines changed

src/main/frontend/common/RestClient.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import {
22
Result,
33
StageInfo,
44
} from "../pipeline-graph-view/pipeline-graph/main/PipelineGraphModel.tsx";
5-
import { ResourceBundle } from "./i18n/messages.ts";
5+
import { ResourceBundle } from "./i18n/index.ts";
66

77
export interface RunStatus {
88
stages: StageInfo[];

src/main/frontend/common/i18n/index.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,8 @@ export * from "./i18n-provider.tsx";
22
export * from "./locale-provider.tsx";
33
export type { MessageContext } from "./message-format.ts";
44
export type { ResourceBundle } from "./messages.ts";
5-
export { Messages, ResourceBundleName } from "./messages.ts";
5+
export {
6+
LocalizedMessageKey,
7+
Messages,
8+
ResourceBundleName,
9+
} from "./messages.ts";

src/main/frontend/common/i18n/messages.spec.ts

+15-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
import { Mock, vi } from "vitest";
22

33
import { getResourceBundle } from "../RestClient.tsx";
4-
import { getMessages, Messages, ResourceBundleName } from "./messages.ts";
4+
import {
5+
getMessages,
6+
LocalizedMessageKey,
7+
Messages,
8+
ResourceBundleName,
9+
} from "./messages.ts";
510

611
vi.mock("../RestClient.tsx", () => ({
712
getResourceBundle: vi.fn(),
@@ -53,9 +58,15 @@ describe("Messages", () => {
5358

5459
const messages = await getMessages("en", [ResourceBundleName.messages]);
5560

56-
expect(messages.format("Util.second", { 0: 5 })).toEqual("5 sec");
57-
expect(messages.format("Util.day", { 0: 1 })).toEqual("1 day");
58-
expect(messages.format("Util.day", { 0: 2 })).toEqual("2 days");
61+
expect(messages.format(LocalizedMessageKey.second, { 0: 5 })).toEqual(
62+
"5 sec",
63+
);
64+
expect(messages.format(LocalizedMessageKey.day, { 0: 1 })).toEqual(
65+
"1 day",
66+
);
67+
expect(messages.format(LocalizedMessageKey.day, { 0: 2 })).toEqual(
68+
"2 days",
69+
);
5970
expect(messages.format("A.property")).toEqual("");
6071
});
6172
});

src/main/frontend/common/i18n/messages.ts

+34-13
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ import {
66
} from "./message-format.ts";
77

88
export type ResourceBundle = {
9-
[key: string]: string;
9+
[key: MessageKeyType]: string;
1010
};
1111

1212
export class Messages {
13-
private readonly mapping: Record<string, CompiledMessage>;
13+
private readonly mapping: Record<MessageKeyType, CompiledMessage>;
1414

1515
constructor(messages: ResourceBundle, locale: string) {
1616
const entries = Object.entries(messages);
@@ -23,7 +23,7 @@ export class Messages {
2323
}
2424
}
2525

26-
private get(key: string): CompiledMessage {
26+
private get(key: MessageKeyType): CompiledMessage {
2727
const message = this.mapping[key];
2828
if (message != null) {
2929
return message;
@@ -37,7 +37,10 @@ export class Messages {
3737
};
3838
}
3939

40-
format(key: string, args: MessageContext | undefined = undefined): string {
40+
format(
41+
key: MessageKeyType,
42+
args: MessageContext | undefined = undefined,
43+
): string {
4144
const message = this.get(key);
4245
return message.format(args);
4346
}
@@ -63,16 +66,34 @@ export async function getMessages(
6366
return new Messages(messages, locale);
6467
}
6568

69+
export type MessageKeyType = LocalizedMessageKey | string;
70+
71+
export enum LocalizedMessageKey {
72+
millisecond = "timings.millisecond",
73+
second = "timings.second",
74+
minute = "timings.minute",
75+
hour = "timings.hour",
76+
day = "timings.day",
77+
month = "timings.month",
78+
year = "timings.year",
79+
startedAgo = "startedAgo",
80+
noBuilds = "noBuilds",
81+
start = "node.start",
82+
end = "node.end",
83+
}
84+
6685
const DEFAULT_MESSAGES: ResourceBundle = {
67-
"Util.millisecond": "{0} ms",
68-
"Util.second": "{0} sec",
69-
"Util.minute": "{0} min",
70-
"Util.hour": "{0} hr",
71-
"Util.day": "{0} {0,choice,0#days|1#day|1<days}",
72-
"Util.month": "{0} mo",
73-
"Util.year": "{0} yr",
74-
startedAgo: "Started {0} ago",
75-
noBuilds: "No builds",
86+
[LocalizedMessageKey.millisecond]: "{0} ms",
87+
[LocalizedMessageKey.second]: "{0} sec",
88+
[LocalizedMessageKey.minute]: "{0} min",
89+
[LocalizedMessageKey.hour]: "{0} hr",
90+
[LocalizedMessageKey.day]: "{0} {0,choice,0#days|1#day|1<days}",
91+
[LocalizedMessageKey.month]: "{0} mo",
92+
[LocalizedMessageKey.year]: "{0} yr",
93+
[LocalizedMessageKey.startedAgo]: "Started {0} ago",
94+
[LocalizedMessageKey.noBuilds]: "No builds",
95+
[LocalizedMessageKey.start]: "Start",
96+
[LocalizedMessageKey.end]: "End",
7697
};
7798

7899
export function defaultMessages(locale: string): Messages {

src/main/frontend/common/utils/timings.spec.tsx

+9-10
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,20 @@
33
import { render } from "@testing-library/react";
44
import { vi } from "vitest";
55

6-
import { I18NContext } from "../i18n/i18n-provider.tsx";
7-
import { Messages } from "../i18n/messages.ts";
6+
import { I18NContext, LocalizedMessageKey, Messages } from "../i18n/index.ts";
87
import { Paused, Started, Total } from "./timings.tsx";
98

109
describe("Timings", () => {
1110
const translations = new Messages(
1211
{
13-
"Util.year": "{0} yr",
14-
"Util.month": "{0} mo",
15-
"Util.day": "{0} day",
16-
"Util.hour": "{0} hr",
17-
"Util.minute": "{0} min",
18-
"Util.second": "{0} sec",
19-
"Util.millisecond": "{0} ms",
20-
startedAgo: "Started {0} ago",
12+
[LocalizedMessageKey.year]: "{0} yr",
13+
[LocalizedMessageKey.month]: "{0} mo",
14+
[LocalizedMessageKey.day]: "{0} day",
15+
[LocalizedMessageKey.hour]: "{0} hr",
16+
[LocalizedMessageKey.minute]: "{0} min",
17+
[LocalizedMessageKey.second]: "{0} sec",
18+
[LocalizedMessageKey.millisecond]: "{0} ms",
19+
[LocalizedMessageKey.startedAgo]: "Started {0} ago",
2120
},
2221
"en",
2322
);

src/main/frontend/common/utils/timings.tsx

+18-26
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { useContext } from "react";
22

3-
import { I18NContext } from "../i18n/i18n-provider";
4-
import { Messages } from "../i18n/messages";
3+
import { I18NContext, LocalizedMessageKey, Messages } from "../i18n/index.ts";
54

65
const ONE_SECOND_MS: number = 1000;
76
const ONE_MINUTE_MS: number = 60 * ONE_SECOND_MS;
@@ -10,15 +9,6 @@ const ONE_DAY_MS: number = 24 * ONE_HOUR_MS;
109
const ONE_MONTH_MS: number = 30 * ONE_DAY_MS;
1110
const ONE_YEAR_MS: number = 365 * ONE_DAY_MS;
1211

13-
const YEAR = "Util.year";
14-
const MONTH = "Util.month";
15-
const HOURS = "Util.hour";
16-
const DAY = "Util.day";
17-
const MINUTE = "Util.minute";
18-
const SECOND = "Util.second";
19-
const MILLIS = "Util.millisecond";
20-
const STARTED_AGO = "startedAgo";
21-
2212
/**
2313
* Create a string representation of a time duration.
2414
* If the quantity of the most significant unit is big (>=10), then we use only that most significant unit in the string representation.
@@ -60,48 +50,50 @@ function getTimeSpanString(duration: number, messages: Messages): string {
6050
if (years > 0) {
6151
return makeTimeSpanString(
6252
years,
63-
messages.format(YEAR, { "0": years }),
53+
messages.format(LocalizedMessageKey.year, { "0": years }),
6454
months,
65-
messages.format(MONTH, { "0": months }),
55+
messages.format(LocalizedMessageKey.month, { "0": months }),
6656
);
6757
} else if (months > 0) {
6858
return makeTimeSpanString(
6959
months,
70-
messages.format(MONTH, { "0": months }),
60+
messages.format(LocalizedMessageKey.month, { "0": months }),
7161
days,
72-
messages.format(DAY, { "0": days }),
62+
messages.format(LocalizedMessageKey.day, { "0": days }),
7363
);
7464
} else if (days > 0) {
7565
return makeTimeSpanString(
7666
days,
77-
messages.format(DAY, { "0": days }),
67+
messages.format(LocalizedMessageKey.day, { "0": days }),
7868
hours,
79-
messages.format(HOURS, { "0": hours }),
69+
messages.format(LocalizedMessageKey.hour, { "0": hours }),
8070
);
8171
} else if (hours > 0) {
8272
return makeTimeSpanString(
8373
hours,
84-
messages.format(HOURS, { "0": hours }),
74+
messages.format(LocalizedMessageKey.hour, { "0": hours }),
8575
minutes,
86-
messages.format(MINUTE, { "0": minutes }),
76+
messages.format(LocalizedMessageKey.minute, { "0": minutes }),
8777
);
8878
} else if (minutes > 0) {
8979
return makeTimeSpanString(
9080
minutes,
91-
messages.format(MINUTE, { "0": minutes }),
81+
messages.format(LocalizedMessageKey.minute, { "0": minutes }),
9282
seconds,
93-
messages.format(SECOND, { "0": seconds }),
83+
messages.format(LocalizedMessageKey.second, { "0": seconds }),
9484
);
9585
} else if (seconds >= 10) {
96-
return messages.format(SECOND, { "0": seconds });
86+
return messages.format(LocalizedMessageKey.second, { "0": seconds });
9787
} else if (seconds >= 1) {
98-
return messages.format(SECOND, {
88+
return messages.format(LocalizedMessageKey.second, {
9989
"0": seconds + Math.floor(millis / 100) / 10,
10090
});
10191
} else if (millis >= 100) {
102-
return messages.format(SECOND, { "0": Math.floor(millis / 10) / 100 });
92+
return messages.format(LocalizedMessageKey.second, {
93+
"0": Math.floor(millis / 10) / 100,
94+
});
10395
} else {
104-
return messages.format(MILLIS, { "0": millis });
96+
return messages.format(LocalizedMessageKey.millisecond, { "0": millis });
10597
}
10698
}
10799

@@ -123,7 +115,7 @@ export function Started({ since }: { since: number }) {
123115

124116
return (
125117
<>
126-
{messages.format(STARTED_AGO, {
118+
{messages.format(LocalizedMessageKey.startedAgo, {
127119
"0": getTimeSpanString(Math.abs(since - Date.now()), messages),
128120
})}
129121
</>

src/main/frontend/multi-pipeline-graph-view/multi-pipeline-graph/main/MultiPipelineGraph.tsx

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import { useContext, useEffect, useState } from "react";
22

3-
import { I18NContext, LocaleContext } from "../../../common/i18n/index.ts";
3+
import {
4+
I18NContext,
5+
LocaleContext,
6+
LocalizedMessageKey,
7+
} from "../../../common/i18n/index.ts";
48
import { RunInfo } from "./MultiPipelineGraphModel.ts";
59
import SingleRun from "./SingleRun.tsx";
610
import startPollingRunsStatus from "./support/startPollingRunsStatus.ts";
@@ -48,7 +52,7 @@ export const MultiPipelineGraph = () => {
4852
{Object.keys(groupedRuns).length === 0 ? (
4953
<div className="pgv-stages__group">
5054
<div className="pgv-stages__heading">
51-
{messages.format("noBuilds")}
55+
{messages.format(LocalizedMessageKey.noBuilds)}
5256
</div>
5357
</div>
5458
) : (

src/main/frontend/pipeline-graph-view/pipeline-graph/main/PipelineGraph.tsx

+10-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import { useEffect, useState } from "react";
1+
import { useContext, useEffect, useState } from "react";
22

3+
import { I18NContext } from "../../../common/i18n/index.ts";
34
import { layoutGraph } from "./PipelineGraphLayout";
45
import {
56
CompositeConnection,
@@ -63,8 +64,15 @@ export function PipelineGraph(props: Props) {
6364
}
6465
}, [layout, selectedStage, stages]);
6566

67+
const messages = useContext(I18NContext);
68+
6669
const updateLayout = (newStages: StageInfo[] = []) => {
67-
const newLayout = layoutGraph(newStages, layoutState, collapsed ?? false);
70+
const newLayout = layoutGraph(
71+
newStages,
72+
layoutState,
73+
collapsed ?? false,
74+
messages,
75+
);
6876
setNodeColumns(newLayout.nodeColumns);
6977
setConnections(newLayout.connections);
7078
setBigLabels(newLayout.bigLabels);

src/main/frontend/pipeline-graph-view/pipeline-graph/main/PipelineGraphLayout.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { LocalizedMessageKey, Messages } from "../../../common/i18n/index.ts";
12
import {
23
CompositeConnection,
34
LayoutInfo,
@@ -27,14 +28,15 @@ export function layoutGraph(
2728
newStages: Array<StageInfo>,
2829
layout: LayoutInfo,
2930
collapsed: boolean,
31+
messages: Messages,
3032
): PositionedGraph {
3133
const stageNodeColumns = createNodeColumns(newStages, collapsed);
3234
const { nodeSpacingH, ypStart } = layout;
3335

3436
const startNode: NodeInfo = {
3537
x: 0,
3638
y: 0,
37-
name: "Start",
39+
name: messages.format(LocalizedMessageKey.start),
3840
id: -1,
3941
isPlaceholder: true,
4042
key: "start-node",
@@ -44,7 +46,7 @@ export function layoutGraph(
4446
const endNode: NodeInfo = {
4547
x: 0,
4648
y: 0,
47-
name: "End",
49+
name: messages.format(LocalizedMessageKey.end),
4850
id: -3,
4951
isPlaceholder: true,
5052
key: "end-node",

src/main/resources/io/jenkins/plugins/pipelinegraphview/Messages.properties

+10-7
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,13 @@
2323
startedAgo=Started {0} ago
2424
noBuilds=No builds
2525

26-
Util.millisecond={0} ms
27-
Util.second={0} sec
28-
Util.minute={0} min
29-
Util.hour ={0} hr
30-
Util.day ={0} {0,choice,0#days|1#day|1<days}
31-
Util.month ={0} mo
32-
Util.year ={0} yr
26+
node.start=Start
27+
node.end=End
28+
29+
timings.millisecond={0} ms
30+
timings.second={0} sec
31+
timings.minute={0} min
32+
timings.hour ={0} hr
33+
timings.day ={0} {0,choice,0#days|1#day|1<days}
34+
timings.month ={0} mo
35+
timings.year ={0} yr

src/main/resources/io/jenkins/plugins/pipelinegraphview/Messages_bg.properties

+7-7
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,17 @@
2323
startedAgo=\
2424
Стартирано преди {0}
2525

26-
Util.millisecond=\
26+
timings.millisecond=\
2727
{0} {0,choice,0#милисекунди|1#милисекунда|1<милисекунди}
28-
Util.second=\
28+
timings.second=\
2929
{0} {0,choice,0#секунди|1#секунда|1секунди}
30-
Util.minute=\
30+
timings.minute=\
3131
{0} {0,choice,0#минути|1#минута|1<минути}
32-
Util.hour =\
32+
timings.hour =\
3333
{0} {0,choice,0#часа|1#час|1<часа}
34-
Util.day =\
34+
timings.day =\
3535
{0} {0,choice,0#дни|1#ден|1<дни}
36-
Util.month =\
36+
timings.month =\
3737
{0} {0,choice,0#месеца|1#месец|1<месеца}
38-
Util.year =\
38+
timings.year =\
3939
{0} {0,choice,0#години|1#година|1<години}

0 commit comments

Comments
 (0)