github-issue-tower-defence-management 1.116.9 → 1.117.1

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.
Files changed (76) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +3 -3
  3. package/bin/adapter/entry-points/console/consoleReadApi.js +13 -1
  4. package/bin/adapter/entry-points/console/consoleReadApi.js.map +1 -1
  5. package/bin/adapter/entry-points/console/ui-dist/assets/index-CJJsRF8i.js +101 -0
  6. package/bin/adapter/entry-points/console/ui-dist/assets/{index-D1V2fi29.css → index-DGVKvwux.css} +1 -1
  7. package/bin/adapter/entry-points/console/ui-dist/index.html +2 -2
  8. package/bin/adapter/repositories/FileSystemSubAgentTranscriptDirectoryResolver.js +9 -2
  9. package/bin/adapter/repositories/FileSystemSubAgentTranscriptDirectoryResolver.js.map +1 -1
  10. package/bin/adapter/repositories/TranscriptSessionSubAgentActivityRepository.js +3 -2
  11. package/bin/adapter/repositories/TranscriptSessionSubAgentActivityRepository.js.map +1 -1
  12. package/bin/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.js +1 -0
  13. package/bin/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.js.map +1 -1
  14. package/bin/domain/usecases/NotifySilentLiveSessionsUseCase.js +13 -3
  15. package/bin/domain/usecases/NotifySilentLiveSessionsUseCase.js.map +1 -1
  16. package/package.json +1 -1
  17. package/src/adapter/entry-points/console/consoleReadApi.test.ts +4 -0
  18. package/src/adapter/entry-points/console/consoleReadApi.ts +18 -0
  19. package/src/adapter/entry-points/console/ui/e2e/consoleTestHarness.ts +2 -0
  20. package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsoleItemDetail.stories.tsx +2 -0
  21. package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsoleItemDetail.test.tsx +3 -1
  22. package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsoleItemDetail.tsx +1 -1
  23. package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsolePullRequestDetail.test.tsx +1 -0
  24. package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsolePullRequestDetail.tsx +1 -1
  25. package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsolePullRequestStatusBadges.stories.tsx +15 -5
  26. package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsolePullRequestStatusBadges.test.tsx +38 -8
  27. package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsolePullRequestStatusBadges.tsx +35 -12
  28. package/src/adapter/entry-points/console/ui/src/features/console/hooks/useConsoleDetailPrefetch.test.ts +117 -0
  29. package/src/adapter/entry-points/console/ui/src/features/console/hooks/useConsoleDetailPrefetch.ts +83 -0
  30. package/src/adapter/entry-points/console/ui/src/features/console/hooks/useConsoleItemDetailData.test.ts +2 -0
  31. package/src/adapter/entry-points/console/ui/src/features/console/hooks/useConsoleItemDetailData.ts +1 -0
  32. package/src/adapter/entry-points/console/ui/src/features/console/hooks/useConsoleOperations.test.ts +67 -0
  33. package/src/adapter/entry-points/console/ui/src/features/console/hooks/useConsoleOperations.ts +26 -6
  34. package/src/adapter/entry-points/console/ui/src/features/console/lib/consoleApi.test.ts +21 -0
  35. package/src/adapter/entry-points/console/ui/src/features/console/lib/consoleApi.ts +14 -0
  36. package/src/adapter/entry-points/console/ui/src/features/console/lib/resourceCache.test.ts +48 -0
  37. package/src/adapter/entry-points/console/ui/src/features/console/lib/resourceCache.ts +24 -0
  38. package/src/adapter/entry-points/console/ui/src/features/console/logic/types.ts +4 -0
  39. package/src/adapter/entry-points/console/ui/src/features/console/pages/ConsoleItemDetailContainer.test.tsx +1 -0
  40. package/src/adapter/entry-points/console/ui/src/features/console/pages/ConsolePage.tsx +9 -1
  41. package/src/adapter/entry-points/console/ui/src/features/console/testing/fixtures.ts +1 -0
  42. package/src/adapter/entry-points/console/ui/src/index.css +10 -1
  43. package/src/adapter/entry-points/console/ui-dist/assets/index-CJJsRF8i.js +101 -0
  44. package/src/adapter/entry-points/console/ui-dist/assets/{index-D1V2fi29.css → index-DGVKvwux.css} +1 -1
  45. package/src/adapter/entry-points/console/ui-dist/index.html +2 -2
  46. package/src/adapter/entry-points/console/webServer.test.ts +2 -0
  47. package/src/adapter/repositories/FileSystemSubAgentTranscriptDirectoryResolver.test.ts +40 -4
  48. package/src/adapter/repositories/FileSystemSubAgentTranscriptDirectoryResolver.ts +12 -6
  49. package/src/adapter/repositories/TranscriptSessionSubAgentActivityRepository.test.ts +107 -29
  50. package/src/adapter/repositories/TranscriptSessionSubAgentActivityRepository.ts +7 -2
  51. package/src/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.ts +1 -0
  52. package/src/domain/usecases/CheckIssueReviewReadinessUseCase.test.ts +1 -0
  53. package/src/domain/usecases/IssueRejectionEvaluator.test.ts +1 -0
  54. package/src/domain/usecases/NotifySilentLiveSessionsUseCase.test.ts +84 -4
  55. package/src/domain/usecases/NotifySilentLiveSessionsUseCase.ts +16 -3
  56. package/src/domain/usecases/RevertOrphanedPreparationUseCase.test.ts +1 -0
  57. package/src/domain/usecases/StartPreparationUseCase.test.ts +9 -0
  58. package/src/domain/usecases/adapter-interfaces/IssueRepository.ts +1 -0
  59. package/src/domain/usecases/adapter-interfaces/SessionSubAgentActivityRepository.ts +1 -0
  60. package/src/domain/usecases/adapter-interfaces/SubAgentTranscriptDirectoryResolver.ts +4 -1
  61. package/types/adapter/entry-points/console/consoleReadApi.d.ts +4 -0
  62. package/types/adapter/entry-points/console/consoleReadApi.d.ts.map +1 -1
  63. package/types/adapter/repositories/FileSystemSubAgentTranscriptDirectoryResolver.d.ts +1 -1
  64. package/types/adapter/repositories/FileSystemSubAgentTranscriptDirectoryResolver.d.ts.map +1 -1
  65. package/types/adapter/repositories/TranscriptSessionSubAgentActivityRepository.d.ts +1 -1
  66. package/types/adapter/repositories/TranscriptSessionSubAgentActivityRepository.d.ts.map +1 -1
  67. package/types/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.d.ts.map +1 -1
  68. package/types/domain/usecases/NotifySilentLiveSessionsUseCase.d.ts.map +1 -1
  69. package/types/domain/usecases/adapter-interfaces/IssueRepository.d.ts +1 -0
  70. package/types/domain/usecases/adapter-interfaces/IssueRepository.d.ts.map +1 -1
  71. package/types/domain/usecases/adapter-interfaces/SessionSubAgentActivityRepository.d.ts +1 -1
  72. package/types/domain/usecases/adapter-interfaces/SessionSubAgentActivityRepository.d.ts.map +1 -1
  73. package/types/domain/usecases/adapter-interfaces/SubAgentTranscriptDirectoryResolver.d.ts +1 -1
  74. package/types/domain/usecases/adapter-interfaces/SubAgentTranscriptDirectoryResolver.d.ts.map +1 -1
  75. package/bin/adapter/entry-points/console/ui-dist/assets/index-Bm0wt3Mn.js +0 -101
  76. package/src/adapter/entry-points/console/ui-dist/assets/index-Bm0wt3Mn.js +0 -101
@@ -22,6 +22,7 @@ import type {
22
22
  ConsoleListItem,
23
23
  ConsoleTabName,
24
24
  } from '../logic/types';
25
+ import type { ConsoleCaches } from './useConsoleCaches';
25
26
  import type { ConsoleOverlayState } from './useConsoleOverlay';
26
27
  import { useConsoleToken } from './useConsoleToken';
27
28
 
@@ -113,15 +114,29 @@ export const useConsoleOperations = (
113
114
  pjcode: string | null,
114
115
  mode: ConsoleTabName,
115
116
  overlayState: ConsoleOverlayState,
117
+ caches?: ConsoleCaches,
116
118
  ): ConsoleOperationsApi => {
117
119
  const { appendToken } = useConsoleToken();
118
120
  const { patchOverlay } = overlayState;
119
121
 
122
+ const invalidateItemContent = useCallback(
123
+ (item: ConsoleListItem) => {
124
+ if (caches === undefined) {
125
+ return;
126
+ }
127
+ const key = `${item.repo}#${item.number}`;
128
+ caches.body.invalidate(key);
129
+ caches.comments.invalidate(key);
130
+ },
131
+ [caches],
132
+ );
133
+
120
134
  const markDone = useCallback(
121
135
  (item: ConsoleListItem) => {
136
+ invalidateItemContent(item);
122
137
  patchOverlay(overlayKeyForItem(item), { done: true }, mode);
123
138
  },
124
- [patchOverlay, mode],
139
+ [invalidateItemContent, patchOverlay, mode],
125
140
  );
126
141
 
127
142
  const reviewPullRequest = useCallback(
@@ -173,13 +188,14 @@ export const useConsoleOperations = (
173
188
  storyOptionId: option.id,
174
189
  };
175
190
  await postConsoleOperation(appendToken, TRIAGE_OPERATION_PATH, request);
191
+ invalidateItemContent(item);
176
192
  patchOverlay(
177
193
  overlayKeyForItem(item),
178
194
  { done: true, story: { name: option.name, color: option.color } },
179
195
  mode,
180
196
  );
181
197
  },
182
- [pjcode, appendToken, patchOverlay, mode],
198
+ [pjcode, appendToken, invalidateItemContent, patchOverlay, mode],
183
199
  );
184
200
 
185
201
  const setStatus = useCallback(
@@ -195,13 +211,14 @@ export const useConsoleOperations = (
195
211
  statusName: option.name,
196
212
  };
197
213
  await postConsoleOperation(appendToken, TRIAGE_OPERATION_PATH, request);
214
+ invalidateItemContent(item);
198
215
  patchOverlay(
199
216
  overlayKeyForItem(item),
200
217
  { done: true, status: { name: option.name, color: option.color } },
201
218
  mode,
202
219
  );
203
220
  },
204
- [pjcode, appendToken, patchOverlay, mode],
221
+ [pjcode, appendToken, invalidateItemContent, patchOverlay, mode],
205
222
  );
206
223
 
207
224
  const setInTmuxByHuman = useCallback(
@@ -216,13 +233,14 @@ export const useConsoleOperations = (
216
233
  projectItemId: item.projectItemId,
217
234
  };
218
235
  await postConsoleOperation(appendToken, INTMUX_OPERATION_PATH, request);
236
+ invalidateItemContent(item);
219
237
  patchOverlay(
220
238
  overlayKeyForItem(item),
221
239
  { done: true, status: { name: option.name, color: option.color } },
222
240
  mode,
223
241
  );
224
242
  },
225
- [pjcode, appendToken, patchOverlay, mode],
243
+ [pjcode, appendToken, invalidateItemContent, patchOverlay, mode],
226
244
  );
227
245
 
228
246
  const closeIssue = useCallback(
@@ -247,13 +265,15 @@ export const useConsoleOperations = (
247
265
  if (pjcode === null) {
248
266
  throw missingPjcodeError();
249
267
  }
250
- return postConsoleComment(appendToken, {
268
+ const comment = await postConsoleComment(appendToken, {
251
269
  pjcode,
252
270
  url: item.url,
253
271
  body,
254
272
  });
273
+ invalidateItemContent(item);
274
+ return comment;
255
275
  },
256
- [pjcode, appendToken],
276
+ [pjcode, appendToken, invalidateItemContent],
257
277
  );
258
278
 
259
279
  const addInlineReviewComment = useCallback(
@@ -191,6 +191,7 @@ describe('createConsoleApiClient', () => {
191
191
  found: true,
192
192
  status: {
193
193
  isConflicted: true,
194
+ mergeableStatus: 'CONFLICTING',
194
195
  isPassedAllCiJob: false,
195
196
  isCiStateSuccess: false,
196
197
  isBranchOutOfDate: true,
@@ -203,6 +204,7 @@ describe('createConsoleApiClient', () => {
203
204
  ).toEqual({
204
205
  found: true,
205
206
  isConflicted: true,
207
+ mergeableStatus: 'CONFLICTING',
206
208
  isPassedAllCiJob: false,
207
209
  isCiStateSuccess: false,
208
210
  isBranchOutOfDate: true,
@@ -210,6 +212,24 @@ describe('createConsoleApiClient', () => {
210
212
  });
211
213
  });
212
214
 
215
+ it('defaults the mergeable status to unknown when the server omits it', async () => {
216
+ mockFetchOnce({
217
+ found: true,
218
+ status: {
219
+ isConflicted: false,
220
+ isPassedAllCiJob: true,
221
+ isCiStateSuccess: true,
222
+ isBranchOutOfDate: false,
223
+ missingRequiredCheckNames: [],
224
+ },
225
+ });
226
+ const client = createConsoleApiClient(appendToken);
227
+ const status = await client.fetchPullRequestStatus(
228
+ 'https://github.com/o/r/pull/1',
229
+ );
230
+ expect(status.mergeableStatus).toBe('UNKNOWN');
231
+ });
232
+
213
233
  it('returns a not-found pull request status when the server reports none', async () => {
214
234
  mockFetchOnce({ found: false, status: null });
215
235
  const client = createConsoleApiClient(appendToken);
@@ -218,6 +238,7 @@ describe('createConsoleApiClient', () => {
218
238
  ).toEqual({
219
239
  found: false,
220
240
  isConflicted: false,
241
+ mergeableStatus: 'UNKNOWN',
221
242
  isPassedAllCiJob: false,
222
243
  isCiStateSuccess: false,
223
244
  isBranchOutOfDate: false,
@@ -3,6 +3,7 @@ import type {
3
3
  ConsoleComment,
4
4
  ConsoleCommit,
5
5
  ConsoleIssueState,
6
+ ConsoleMergeableStatus,
6
7
  ConsolePullRequestStatus,
7
8
  ConsoleRelatedPullRequest,
8
9
  } from '../logic/types';
@@ -136,6 +137,16 @@ const parseStringArray = (value: unknown): string[] =>
136
137
  ? value.filter((name): name is string => typeof name === 'string')
137
138
  : [];
138
139
 
140
+ const parseMergeableStatus = (value: unknown): ConsoleMergeableStatus => {
141
+ if (value === 'MERGEABLE') {
142
+ return 'MERGEABLE';
143
+ }
144
+ if (value === 'CONFLICTING') {
145
+ return 'CONFLICTING';
146
+ }
147
+ return 'UNKNOWN';
148
+ };
149
+
139
150
  const parseRelatedPrs = (payload: unknown): ConsoleRelatedPullRequest[] => {
140
151
  if (!isRecord(payload) || !Array.isArray(payload.relatedPullRequests)) {
141
152
  return [];
@@ -146,6 +157,7 @@ const parseRelatedPrs = (payload: unknown): ConsoleRelatedPullRequest[] => {
146
157
  createdAt: getString(pr.createdAt),
147
158
  isDraft: getBoolean(pr.isDraft),
148
159
  isConflicted: getBoolean(pr.isConflicted),
160
+ mergeableStatus: parseMergeableStatus(pr.mergeableStatus),
149
161
  isPassedAllCiJob: getBoolean(pr.isPassedAllCiJob),
150
162
  isCiStateSuccess: getBoolean(pr.isCiStateSuccess),
151
163
  isResolvedAllReviewComments: getBoolean(pr.isResolvedAllReviewComments),
@@ -160,6 +172,7 @@ const parsePullRequestStatus = (payload: unknown): ConsolePullRequestStatus => {
160
172
  return {
161
173
  found: false,
162
174
  isConflicted: false,
175
+ mergeableStatus: 'UNKNOWN',
163
176
  isPassedAllCiJob: false,
164
177
  isCiStateSuccess: false,
165
178
  isBranchOutOfDate: false,
@@ -170,6 +183,7 @@ const parsePullRequestStatus = (payload: unknown): ConsolePullRequestStatus => {
170
183
  return {
171
184
  found: true,
172
185
  isConflicted: getBoolean(status.isConflicted),
186
+ mergeableStatus: parseMergeableStatus(status.mergeableStatus),
173
187
  isPassedAllCiJob: getBoolean(status.isPassedAllCiJob),
174
188
  isCiStateSuccess: getBoolean(status.isCiStateSuccess),
175
189
  isBranchOutOfDate: getBoolean(status.isBranchOutOfDate),
@@ -37,6 +37,54 @@ describe('ResourceCache', () => {
37
37
  expect(await cache.load('k', 'u')).toBe('ok');
38
38
  expect(fetcher).toHaveBeenCalledTimes(2);
39
39
  });
40
+
41
+ it('prefetches into the cache and serves the next load from it', async () => {
42
+ const fetcher = jest.fn(async (url: string) => `value:${url}`);
43
+ const cache = new ResourceCache(fetcher);
44
+ cache.prefetch('k', 'u');
45
+ await Promise.resolve();
46
+ await Promise.resolve();
47
+ expect(cache.peek('k')).toBe('value:u');
48
+ expect(await cache.load('k', 'u')).toBe('value:u');
49
+ expect(fetcher).toHaveBeenCalledTimes(1);
50
+ });
51
+
52
+ it('does not prefetch a key that is already cached', async () => {
53
+ const fetcher = jest.fn(async (url: string) => `value:${url}`);
54
+ const cache = new ResourceCache(fetcher);
55
+ await cache.load('k', 'u');
56
+ cache.prefetch('k', 'u');
57
+ expect(fetcher).toHaveBeenCalledTimes(1);
58
+ });
59
+
60
+ it('does not start a second prefetch while one is in flight', async () => {
61
+ const fetcher = jest.fn(() => new Promise<string>(() => {}));
62
+ const cache = new ResourceCache(fetcher);
63
+ cache.prefetch('k', 'u');
64
+ cache.prefetch('k', 'u');
65
+ expect(fetcher).toHaveBeenCalledTimes(1);
66
+ });
67
+
68
+ it('swallows prefetch errors and leaves the key uncached', async () => {
69
+ const fetcher = jest
70
+ .fn<Promise<string>, [string]>()
71
+ .mockRejectedValue(new Error('boom'));
72
+ const cache = new ResourceCache(fetcher);
73
+ cache.prefetch('k', 'u');
74
+ await Promise.resolve();
75
+ await Promise.resolve();
76
+ expect(cache.peek('k')).toBeUndefined();
77
+ });
78
+
79
+ it('invalidate removes a cached value so the next load refetches', async () => {
80
+ const fetcher = jest.fn(async (url: string) => `value:${url}`);
81
+ const cache = new ResourceCache(fetcher);
82
+ await cache.load('k', 'u');
83
+ cache.invalidate('k');
84
+ expect(cache.peek('k')).toBeUndefined();
85
+ await cache.load('k', 'u');
86
+ expect(fetcher).toHaveBeenCalledTimes(2);
87
+ });
40
88
  });
41
89
 
42
90
  describe('runWithConcurrency', () => {
@@ -3,6 +3,7 @@ export type ResourceFetcher<T> = (url: string) => Promise<T>;
3
3
  export class ResourceCache<T> {
4
4
  private readonly cache = new Map<string, T>();
5
5
  private readonly inFlight = new Map<string, Promise<T>>();
6
+ private readonly prefetchInFlight = new Set<string>();
6
7
 
7
8
  constructor(private readonly fetcher: ResourceFetcher<T>) {}
8
9
 
@@ -30,6 +31,29 @@ export class ResourceCache<T> {
30
31
  this.inFlight.set(key, promise);
31
32
  return promise;
32
33
  };
34
+
35
+ prefetch = (key: string, url: string): void => {
36
+ if (
37
+ this.cache.has(key) ||
38
+ this.inFlight.has(key) ||
39
+ this.prefetchInFlight.has(key)
40
+ ) {
41
+ return;
42
+ }
43
+ this.prefetchInFlight.add(key);
44
+ this.fetcher(url)
45
+ .then((value) => {
46
+ this.cache.set(key, value);
47
+ })
48
+ .catch(() => {})
49
+ .finally(() => {
50
+ this.prefetchInFlight.delete(key);
51
+ });
52
+ };
53
+
54
+ invalidate = (key: string): void => {
55
+ this.cache.delete(key);
56
+ };
33
57
  }
34
58
 
35
59
  export const runWithConcurrency = async (
@@ -64,9 +64,12 @@ export type ConsoleIssueState = {
64
64
  title: string;
65
65
  };
66
66
 
67
+ export type ConsoleMergeableStatus = 'MERGEABLE' | 'CONFLICTING' | 'UNKNOWN';
68
+
67
69
  export type ConsolePullRequestStatus = {
68
70
  found: boolean;
69
71
  isConflicted: boolean;
72
+ mergeableStatus: ConsoleMergeableStatus;
70
73
  isPassedAllCiJob: boolean;
71
74
  isCiStateSuccess: boolean;
72
75
  isBranchOutOfDate: boolean;
@@ -100,6 +103,7 @@ export type ConsoleRelatedPullRequest = {
100
103
  createdAt: string;
101
104
  isDraft: boolean;
102
105
  isConflicted: boolean;
106
+ mergeableStatus: ConsoleMergeableStatus;
103
107
  isPassedAllCiJob: boolean;
104
108
  isCiStateSuccess: boolean;
105
109
  isResolvedAllReviewComments: boolean;
@@ -44,6 +44,7 @@ const buildCaches = (overrides: CachesOverrides = {}): ConsoleCaches => {
44
44
  fetchPullRequestStatus: async () => ({
45
45
  found: true,
46
46
  isConflicted: false,
47
+ mergeableStatus: 'MERGEABLE' as const,
47
48
  isPassedAllCiJob: true,
48
49
  isCiStateSuccess: true,
49
50
  isBranchOutOfDate: false,
@@ -7,6 +7,7 @@ import {
7
7
  } from '../components/operations/ConsoleUndoToast';
8
8
  import { useConsoleActionQueue } from '../hooks/useConsoleActionQueue';
9
9
  import { useConsoleCaches } from '../hooks/useConsoleCaches';
10
+ import { useConsoleDetailPrefetch } from '../hooks/useConsoleDetailPrefetch';
10
11
  import { useConsoleNavigation } from '../hooks/useConsoleNavigation';
11
12
  import { useConsoleOperations } from '../hooks/useConsoleOperations';
12
13
  import { useConsoleOverlay } from '../hooks/useConsoleOverlay';
@@ -78,7 +79,12 @@ export const ConsolePage = () => {
78
79
  navigation;
79
80
 
80
81
  const caches = useConsoleCaches();
81
- const operations = useConsoleOperations(pjcode, activeTab, overlayState);
82
+ const operations = useConsoleOperations(
83
+ pjcode,
84
+ activeTab,
85
+ overlayState,
86
+ caches,
87
+ );
82
88
  const actionQueue = useConsoleActionQueue();
83
89
  const now = Date.now();
84
90
 
@@ -120,6 +126,8 @@ export const ConsolePage = () => {
120
126
  );
121
127
  }, [selectedItemKey, activeSnapshot]);
122
128
 
129
+ useConsoleDetailPrefetch(caches, selectedItem, pendingItems);
130
+
123
131
  useEffect(() => {
124
132
  if (selectedItemKey === null) {
125
133
  return;
@@ -343,6 +343,7 @@ export const consoleRelatedPullRequestsFixture: ConsoleRelatedPullRequest[] = [
343
343
  createdAt: '2026-06-16T22:30:00.000Z',
344
344
  isDraft: false,
345
345
  isConflicted: false,
346
+ mergeableStatus: 'MERGEABLE',
346
347
  isPassedAllCiJob: true,
347
348
  isCiStateSuccess: true,
348
349
  isResolvedAllReviewComments: true,
@@ -351,6 +351,15 @@ body {
351
351
  opacity: 0.85;
352
352
  }
353
353
 
354
+ .console-detail-mergeable-chip {
355
+ font-weight: 600;
356
+ }
357
+
358
+ .console-detail-mergeable-chip-unknown {
359
+ opacity: 0.7;
360
+ font-weight: 400;
361
+ }
362
+
354
363
  .console-detail-labels {
355
364
  display: flex;
356
365
  flex-wrap: wrap;
@@ -655,7 +664,7 @@ body {
655
664
  }
656
665
 
657
666
  .console-op-button {
658
- padding: 7px 16px;
667
+ padding: 9px 16px;
659
668
  border: 1px solid #30363d;
660
669
  border-radius: 6px;
661
670
  background: #21262d;