Skip to content

Commit 9eea6df

Browse files
committed
refactor: make externalJobUrl to be a function that returns an ExternalJobURL type
1 parent 6d6d356 commit 9eea6df

File tree

6 files changed

+57
-65
lines changed

6 files changed

+57
-65
lines changed

example.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,9 +139,14 @@ const run = async () => {
139139
createBullBoard({
140140
queues: [
141141
new BullMQAdapter(exampleBullMq, { delimiter: '.' }),
142-
new BullAdapter(exampleBull, { delimiter: '.' }),
142+
new BullAdapter(exampleBull, {
143+
externalJobUrl: (job) => ({ href: `https://my-app.com/${job.id}` }),
144+
}),
143145
new BullMQAdapter(newRegistration, { delimiter: '.' }),
144-
new BullMQAdapter(resetPassword, { delimiter: ';', displayName: 'Reset Password' }),
146+
new BullMQAdapter(resetPassword, {
147+
delimiter: ';',
148+
displayName: 'Reset Password',
149+
}),
145150
],
146151
serverAdapter,
147152
});

packages/api/src/handlers/queues.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,8 @@ export const formatJob = (job: QueueJob, queue: BaseAdapter): AppJob => {
3333
name: queue.format('name', jobProps, jobProps.name || ''),
3434
returnValue: queue.format('returnValue', jobProps.returnvalue),
3535
isFailed: !!jobProps.failedReason || (Array.isArray(stacktrace) && stacktrace.length > 0),
36-
externalUrl: queue.externalJobUrl?.href
37-
? {
38-
displayText: queue.externalJobUrl.displayText,
39-
href: queue.externalJobUrl.href(jobProps),
40-
}
41-
: undefined,
36+
externalUrl:
37+
typeof queue.externalJobUrl === 'function' ? queue.externalJobUrl(jobProps) : undefined,
4238
};
4339
};
4440

packages/api/typings/app.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,6 @@ export type JobCleanStatus = 'completed' | 'wait' | 'active' | 'delayed' | 'fail
66

77
export type JobRetryStatus = 'completed' | 'failed';
88

9-
type JobUrl = {
10-
displayText?: string
11-
href: ((job: QueueJobJson) => string)
12-
}
13-
149
type Library = 'bull' | 'bullmq';
1510

1611
type Values<T> = T[keyof T];
@@ -30,6 +25,10 @@ export type JobStatus<Lib extends Library = 'bullmq'> = Lib extends 'bullmq'
3025
: never;
3126

3227
export type JobCounts = Record<Status, number>;
28+
export type ExternalJobUrl = {
29+
displayText?: string;
30+
href: string;
31+
};
3332

3433
export interface QueueAdapterOptions {
3534
readOnlyMode: boolean;
@@ -38,7 +37,7 @@ export interface QueueAdapterOptions {
3837
description: string;
3938
displayName: string;
4039
delimiter: string;
41-
externalJobUrl?: JobUrl;
40+
externalJobUrl?: (job: QueueJobJson) => ExternalJobUrl;
4241
}
4342

4443
export type BullBoardQueues = Map<string, BaseAdapter>;
@@ -57,7 +56,9 @@ export interface QueueJob {
5756
toJSON(): QueueJobJson;
5857

5958
getState(): Promise<Status | 'stuck' | 'waiting-children' | 'prioritized' | 'unknown'>;
59+
6060
update?(jobData: Record<string, any>): Promise<void>;
61+
6162
updateData?(jobData: Record<string, any>): Promise<void>;
6263
}
6364

@@ -122,7 +123,7 @@ export interface AppJob {
122123
isFailed: boolean;
123124
externalUrl?: {
124125
displayText?: string;
125-
href: string
126+
href: string;
126127
};
127128
}
128129

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,7 @@
11
import React from 'react';
22

33
export const UpRightFromSquareSolid = () => (
4-
<svg
5-
xmlns="http://www.w3.org/2000/svg"
6-
viewBox="0 0 512 512"
7-
width="16"
8-
height="16"
9-
role="img"
10-
>
11-
<style>
12-
{`
13-
.urfss {fill:rgb(0, 0, 0)}
14-
15-
.dark-mode .urfss {fill:rgb(255, 255, 255)}
16-
`}
17-
</style>
18-
<path
19-
className="urfss"
20-
d="M352 0c-12.9 0-24.6 7.8-29.6 19.8s-2.2 25.7 6.9 34.9L370.7 96 201.4 265.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L416 141.3l41.4 41.4c9.2 9.2 22.9 11.9 34.9 6.9s19.8-16.6 19.8-29.6l0-128c0-17.7-14.3-32-32-32L352 0zM80 32C35.8 32 0 67.8 0 112L0 432c0 44.2 35.8 80 80 80l320 0c44.2 0 80-35.8 80-80l0-112c0-17.7-14.3-32-32-32s-32 14.3-32 32l0 112c0 8.8-7.2 16-16 16L80 448c-8.8 0-16-7.2-16-16l0-320c0-8.8 7.2-16 16-16l112 0c17.7 0 32-14.3 32-32s-14.3-32-32-32L80 32z"
21-
/>
4+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 512 512">
5+
<path d="M352 0c-12.9 0-24.6 7.8-29.6 19.8s-2.2 25.7 6.9 34.9L370.7 96 201.4 265.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L416 141.3l41.4 41.4c9.2 9.2 22.9 11.9 34.9 6.9s19.8-16.6 19.8-29.6V32c0-17.7-14.3-32-32-32H352zM80 32C35.8 32 0 67.8 0 112v320c0 44.2 35.8 80 80 80h320c44.2 0 80-35.8 80-80V320c0-17.7-14.3-32-32-32s-32 14.3-32 32v112c0 8.8-7.2 16-16 16H80c-8.8 0-16-7.2-16-16V112c0-8.8 7.2-16 16-16h112c17.7 0 32-14.3 32-32s-14.3-32-32-32H80z" />
226
</svg>
23-
)
7+
);

packages/ui/src/components/JobCard/JobCard.module.css

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -113,14 +113,21 @@
113113
padding: 0.25rem 0.5rem;
114114
border-radius: 0.25rem;
115115
transition: background-color 0.2s;
116-
}
117116

118-
.externalLink:hover {
119-
text-decoration: underline;
117+
&:hover {
118+
text-decoration: underline;
119+
}
120+
121+
&:focus {
122+
outline-offset: 2px;
123+
}
124+
125+
> svg {
126+
fill: var(--button-icon-fill);
127+
}
120128
}
121129

122-
.externalLink:focus {
123-
outline-offset: 2px;
130+
.externalLink:hover {
124131
}
125132

126133
.titleWithLink {

packages/ui/src/components/JobCard/JobCard.tsx

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -59,36 +59,35 @@ export const JobCard = ({
5959
return (
6060
<Collapsible.Root asChild={true} open={isExpandedCard}>
6161
<Card className={s.card}>
62-
<div className={s.header}>
63-
<div className={s.titleWithLink}>
64-
{jobUrl ? (
65-
<Link className={s.jobLink} to={jobUrl}>
66-
{JobTitle}
67-
</Link>
68-
) : (
69-
JobTitle
70-
)}
62+
<div className={s.header}>
63+
<div className={s.titleWithLink}>
64+
{jobUrl ? (
65+
<Link className={s.jobLink} to={jobUrl}>
66+
{JobTitle}
67+
</Link>
68+
) : (
69+
JobTitle
70+
)}
71+
72+
{job.externalUrl && (
73+
<a
74+
className={s.externalLink}
75+
href={job.externalUrl.href}
76+
target="_blank"
77+
rel="noopener noreferrer"
78+
>
79+
{job.externalUrl.displayText ?? <UpRightFromSquareSolid />}
80+
</a>
81+
)}
82+
</div>
7183

72-
{job.externalUrl && (
73-
<a
74-
className={s.externalLink}
75-
href={job.externalUrl.href}
76-
target="_blank"
77-
rel="noopener noreferrer"
78-
aria-label="View job in app"
79-
>
80-
{job.externalUrl.displayText ?? <UpRightFromSquareSolid />}
81-
</a>
84+
{showCollapseExpandBtn && (
85+
<Button className={s.collapseBtn} onClick={() => setLocalCollapse(!isExpandedCard)}>
86+
{isExpandedCard ? <ChevronUp /> : <ChevronDown />}
87+
</Button>
8288
)}
8389
</div>
8490

85-
{showCollapseExpandBtn && (
86-
<Button className={s.collapseBtn} onClick={() => setLocalCollapse(!isExpandedCard)}>
87-
{isExpandedCard ? <ChevronUp /> : <ChevronDown />}
88-
</Button>
89-
)}
90-
</div>
91-
9291
<Collapsible.Content asChild={true}>
9392
<div className={s.details}>
9493
<div className={s.sideInfo}>

0 commit comments

Comments
 (0)