github-issue-tower-defence-management 1.142.2 → 1.143.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/umino-project.yml +2 -8
- package/CHANGELOG.md +14 -0
- package/README.md +2 -2
- package/bin/adapter/entry-points/console/ui-dist/assets/{index-BaGbcbYI.css → index-Bp-p-XOs.css} +1 -1
- package/bin/adapter/entry-points/console/ui-dist/assets/index-C1KKZ_a1.js +81 -0
- package/bin/adapter/entry-points/console/ui-dist/index.html +2 -2
- package/bin/domain/usecases/OauthTokenSelectUseCase.js +2 -2
- package/bin/domain/usecases/OauthTokenSelectUseCase.js.map +1 -1
- package/package.json +1 -1
- package/src/adapter/entry-points/console/ui/src/features/console/components/content/ConsoleCopyCodeButton.stories.tsx +28 -0
- package/src/adapter/entry-points/console/ui/src/features/console/components/content/ConsoleCopyCodeButton.test.tsx +65 -0
- package/src/adapter/entry-points/console/ui/src/features/console/components/content/ConsoleCopyCodeButton.tsx +19 -0
- package/src/adapter/entry-points/console/ui/src/features/console/components/content/ConsoleMarkdownContent.test.tsx +103 -1
- package/src/adapter/entry-points/console/ui/src/features/console/components/content/ConsoleMarkdownContent.tsx +41 -5
- package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsoleCopyUrlButton.tsx +10 -42
- package/src/adapter/entry-points/console/ui/src/features/console/components/shared/ConsoleClipboardCopyButton.stories.tsx +32 -0
- package/src/adapter/entry-points/console/ui/src/features/console/components/shared/ConsoleClipboardCopyButton.test.tsx +67 -0
- package/src/adapter/entry-points/console/ui/src/features/console/components/shared/ConsoleClipboardCopyButton.tsx +57 -0
- package/src/adapter/entry-points/console/ui/src/index.css +31 -0
- package/src/adapter/entry-points/console/ui-dist/assets/{index-BaGbcbYI.css → index-Bp-p-XOs.css} +1 -1
- package/src/adapter/entry-points/console/ui-dist/assets/index-C1KKZ_a1.js +81 -0
- package/src/adapter/entry-points/console/ui-dist/index.html +2 -2
- package/src/adapter/entry-points/handlers/LiveSessionOauthTokenSelectHandler.test.ts +2 -2
- package/src/domain/usecases/OauthTokenSelectUseCase.test.ts +33 -11
- package/src/domain/usecases/OauthTokenSelectUseCase.ts +2 -2
- package/types/domain/usecases/OauthTokenSelectUseCase.d.ts +2 -2
- package/types/domain/usecases/OauthTokenSelectUseCase.d.ts.map +1 -1
- package/bin/adapter/entry-points/console/ui-dist/assets/index-2c5E3tdu.js +0 -81
- package/src/adapter/entry-points/console/ui-dist/assets/index-2c5E3tdu.js +0 -81
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>TDPM Console</title>
|
|
7
|
-
<script type="module" crossorigin src="/assets/index-
|
|
8
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
7
|
+
<script type="module" crossorigin src="/assets/index-C1KKZ_a1.js"></script>
|
|
8
|
+
<link rel="stylesheet" crossorigin href="/assets/index-Bp-p-XOs.css">
|
|
9
9
|
</head>
|
|
10
10
|
<body>
|
|
11
11
|
<div id="root"></div>
|
|
@@ -308,8 +308,8 @@ describe('LiveSessionOauthTokenSelectHandler', () => {
|
|
|
308
308
|
expect(output.selectedName).toBeNull();
|
|
309
309
|
const diagnostics = output.diagnostics.join('\n');
|
|
310
310
|
expect(diagnostics).toContain('No eligible token');
|
|
311
|
-
expect(diagnostics).toContain('5h >=
|
|
312
|
-
expect(diagnostics).toContain('7d >=
|
|
311
|
+
expect(diagnostics).toContain('5h >= 25% free');
|
|
312
|
+
expect(diagnostics).toContain('7d >= 3% free');
|
|
313
313
|
expect(diagnostics).not.toContain('fake-busy');
|
|
314
314
|
});
|
|
315
315
|
|
|
@@ -59,11 +59,11 @@ describe('OauthTokenSelectUseCase', () => {
|
|
|
59
59
|
expect(result.selected?.token).toBe('fake-token-soon');
|
|
60
60
|
});
|
|
61
61
|
|
|
62
|
-
it('excludes a token whose 5h window is less than
|
|
62
|
+
it('excludes a token whose 5h window is less than 25% free', () => {
|
|
63
63
|
const result = useCase.run(
|
|
64
64
|
[
|
|
65
|
-
candidate('busy5h', snapshot({ fiveHourUtilization: 0.
|
|
66
|
-
candidate('ok', snapshot({ fiveHourUtilization: 0.
|
|
65
|
+
candidate('busy5h', snapshot({ fiveHourUtilization: 0.76 })),
|
|
66
|
+
candidate('ok', snapshot({ fiveHourUtilization: 0.75 })),
|
|
67
67
|
],
|
|
68
68
|
NOW,
|
|
69
69
|
);
|
|
@@ -74,20 +74,22 @@ describe('OauthTokenSelectUseCase', () => {
|
|
|
74
74
|
expect(busy?.exclusionReason).toContain('5h window');
|
|
75
75
|
});
|
|
76
76
|
|
|
77
|
-
it('treats exactly
|
|
77
|
+
it('treats exactly 75% used 5h utilization as eligible (boundary)', () => {
|
|
78
78
|
const result = useCase.run(
|
|
79
|
-
[candidate('boundary', snapshot({ fiveHourUtilization: 0.
|
|
79
|
+
[candidate('boundary', snapshot({ fiveHourUtilization: 0.75 }))],
|
|
80
80
|
NOW,
|
|
81
81
|
);
|
|
82
82
|
|
|
83
83
|
expect(result.selected?.name).toBe('boundary');
|
|
84
|
+
const boundary = result.metrics.find((m) => m.name === 'boundary');
|
|
85
|
+
expect(boundary?.fiveHourFreeRatio).toBe(0.25);
|
|
84
86
|
});
|
|
85
87
|
|
|
86
|
-
it('excludes a token whose 7d window is less than
|
|
88
|
+
it('excludes a token whose 7d window is less than 3% free', () => {
|
|
87
89
|
const result = useCase.run(
|
|
88
90
|
[
|
|
89
|
-
candidate('busy7d', snapshot({ sevenDayUtilization: 0.
|
|
90
|
-
candidate('ok', snapshot({ sevenDayUtilization: 0.
|
|
91
|
+
candidate('busy7d', snapshot({ sevenDayUtilization: 0.98 })),
|
|
92
|
+
candidate('ok', snapshot({ sevenDayUtilization: 0.97 })),
|
|
91
93
|
],
|
|
92
94
|
NOW,
|
|
93
95
|
);
|
|
@@ -98,13 +100,33 @@ describe('OauthTokenSelectUseCase', () => {
|
|
|
98
100
|
expect(busy?.exclusionReason).toContain('7d window');
|
|
99
101
|
});
|
|
100
102
|
|
|
101
|
-
it('treats
|
|
103
|
+
it('treats exactly 97% used 7d utilization as eligible (boundary)', () => {
|
|
102
104
|
const result = useCase.run(
|
|
103
|
-
[candidate('boundary', snapshot({ sevenDayUtilization: 0.
|
|
105
|
+
[candidate('boundary', snapshot({ sevenDayUtilization: 0.97 }))],
|
|
104
106
|
NOW,
|
|
105
107
|
);
|
|
106
108
|
|
|
107
109
|
expect(result.selected?.name).toBe('boundary');
|
|
110
|
+
const boundary = result.metrics.find((m) => m.name === 'boundary');
|
|
111
|
+
expect(boundary?.sevenDayFreeRatio).toBeCloseTo(0.03, 9);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('proceeds when 5h is exactly 25% free and 7d is exactly 3% free (combined boundary)', () => {
|
|
115
|
+
const result = useCase.run(
|
|
116
|
+
[
|
|
117
|
+
candidate(
|
|
118
|
+
'boundary',
|
|
119
|
+
snapshot({ fiveHourUtilization: 0.75, sevenDayUtilization: 0.97 }),
|
|
120
|
+
),
|
|
121
|
+
],
|
|
122
|
+
NOW,
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
expect(result.selected?.name).toBe('boundary');
|
|
126
|
+
const boundary = result.metrics.find((m) => m.name === 'boundary');
|
|
127
|
+
expect(boundary?.eligible).toBe(true);
|
|
128
|
+
expect(boundary?.fiveHourFreeRatio).toBe(0.25);
|
|
129
|
+
expect(boundary?.sevenDayFreeRatio).toBeCloseTo(0.03, 9);
|
|
108
130
|
});
|
|
109
131
|
|
|
110
132
|
it('treats a token with no snapshot as fully free', () => {
|
|
@@ -165,7 +187,7 @@ describe('OauthTokenSelectUseCase', () => {
|
|
|
165
187
|
const result = useCase.run(
|
|
166
188
|
[
|
|
167
189
|
candidate('busy', snapshot({ fiveHourUtilization: 0.9 })),
|
|
168
|
-
candidate('alsoBusy', snapshot({ sevenDayUtilization: 0.
|
|
190
|
+
candidate('alsoBusy', snapshot({ sevenDayUtilization: 0.98 })),
|
|
169
191
|
],
|
|
170
192
|
NOW,
|
|
171
193
|
);
|
|
@@ -41,8 +41,8 @@ export type OauthTokenSelectResult = {
|
|
|
41
41
|
const SECONDS_PER_DAY = 86400;
|
|
42
42
|
const SEVEN_DAYS_IN_SECONDS = 7 * SECONDS_PER_DAY;
|
|
43
43
|
|
|
44
|
-
export const FIVE_HOUR_MIN_FREE_RATIO = 0.
|
|
45
|
-
export const SEVEN_DAY_MIN_FREE_RATIO = 0.
|
|
44
|
+
export const FIVE_HOUR_MIN_FREE_RATIO = 0.25;
|
|
45
|
+
export const SEVEN_DAY_MIN_FREE_RATIO = 0.03;
|
|
46
46
|
|
|
47
47
|
export const selectWeightedCandidate = <Entry>(
|
|
48
48
|
eligible: Entry[],
|
|
@@ -28,8 +28,8 @@ export type OauthTokenSelectResult = {
|
|
|
28
28
|
selected: OauthTokenCandidate | null;
|
|
29
29
|
metrics: OauthTokenCandidateMetrics[];
|
|
30
30
|
};
|
|
31
|
-
export declare const FIVE_HOUR_MIN_FREE_RATIO = 0.
|
|
32
|
-
export declare const SEVEN_DAY_MIN_FREE_RATIO = 0.
|
|
31
|
+
export declare const FIVE_HOUR_MIN_FREE_RATIO = 0.25;
|
|
32
|
+
export declare const SEVEN_DAY_MIN_FREE_RATIO = 0.03;
|
|
33
33
|
export declare const selectWeightedCandidate: <Entry>(eligible: Entry[], candidateOf: (entry: Entry) => OauthTokenCandidate, deterministicBest: Entry, random: SelectionRandom) => Entry;
|
|
34
34
|
export declare class OauthTokenSelectUseCase {
|
|
35
35
|
run: (candidates: OauthTokenCandidate[], nowEpochSeconds: number, random?: SelectionRandom) => OauthTokenSelectResult;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OauthTokenSelectUseCase.d.ts","sourceRoot":"","sources":["../../../src/domain/usecases/OauthTokenSelectUseCase.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,wBAAwB,GAAG;IACrC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,wBAAwB,GAAG,IAAI,CAAC;IAC1C,oBAAoB,EAAE,OAAO,CAAC;IAC9B,eAAe,EAAE,OAAO,CAAC;IACzB,aAAa,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,MAAM,MAAM,CAAC;AAE3C,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAE1C,eAAO,MAAM,iBAAiB,GAAI,WAAW,mBAAmB,KAAG,MAGlE,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,OAAO,CAAC;IAClB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACrC,OAAO,EAAE,0BAA0B,EAAE,CAAC;CACvC,CAAC;AAKF,eAAO,MAAM,wBAAwB,
|
|
1
|
+
{"version":3,"file":"OauthTokenSelectUseCase.d.ts","sourceRoot":"","sources":["../../../src/domain/usecases/OauthTokenSelectUseCase.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,wBAAwB,GAAG;IACrC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,wBAAwB,GAAG,IAAI,CAAC;IAC1C,oBAAoB,EAAE,OAAO,CAAC;IAC9B,eAAe,EAAE,OAAO,CAAC;IACzB,aAAa,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,MAAM,MAAM,CAAC;AAE3C,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAE1C,eAAO,MAAM,iBAAiB,GAAI,WAAW,mBAAmB,KAAG,MAGlE,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,OAAO,CAAC;IAClB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACrC,OAAO,EAAE,0BAA0B,EAAE,CAAC;CACvC,CAAC;AAKF,eAAO,MAAM,wBAAwB,OAAO,CAAC;AAC7C,eAAO,MAAM,wBAAwB,OAAO,CAAC;AAE7C,eAAO,MAAM,uBAAuB,GAAI,KAAK,EAC3C,UAAU,KAAK,EAAE,EACjB,aAAa,CAAC,KAAK,EAAE,KAAK,KAAK,mBAAmB,EAClD,mBAAmB,KAAK,EACxB,QAAQ,eAAe,KACtB,KAoBF,CAAC;AAEF,qBAAa,uBAAuB;IAClC,GAAG,GACD,YAAY,mBAAmB,EAAE,EACjC,iBAAiB,MAAM,EACvB,SAAQ,eAA6B,KACpC,sBAAsB,CA2BvB;IAEF,OAAO,CAAC,QAAQ,CAiCd;IAEF,OAAO,CAAC,eAAe,CAuBrB;IAEF,OAAO,CAAC,iBAAiB,CAWvB;IAEF,OAAO,CAAC,iBAAiB,CAWvB;IAEF,OAAO,CAAC,gBAAgB,CActB;IAEF,OAAO,CAAC,aAAa,CAGwC;IAE7D,OAAO,CAAC,wBAAwB,CAG9B;IAEF,OAAO,CAAC,SAAS,CAAsD;CACxE"}
|