feat(integrations): add ArchiveTeam Warrior widget#5784
Conversation
🚨 Preview Deployment Blocked - Security ProtectionYour pull request was blocked from triggering preview deployments Why was this blocked?
How to resolve this:Option 1: Get Collaborator Access (Recommended) Option 2: Request Permission Override For Repository Administrators:To disable this security check ( This security measure protects against malicious code execution in preview deployments. Only trusted collaborators should have the ability to trigger deployments. 🛡️ Learn more about this security featureThis protection prevents unauthorized users from:
Preview deployments are powerful but require trust. Only users with repository write access can trigger them. |
56226e1 to
dde277e
Compare
| archiveTeamWarrior: { | ||
| name: "ArchiveTeam Warrior", | ||
| secretKinds: [[], ["username", "password"]], | ||
| iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/archivebox.svg", |
There was a problem hiding this comment.
Is this really yours? If you have a more specific logo, you can add it via https://dashboardicons.com
There was a problem hiding this comment.
I do not maintain the project, I'm just a user of it. I did find their logo on that site and I will swap it over.
| const seesawFrameSchema = z.object({ | ||
| event_name: z.string(), | ||
| message: z.unknown(), | ||
| }); | ||
|
|
||
| const warriorStatusMessageSchema = z.object({ | ||
| status: z.string(), | ||
| }); | ||
|
|
||
| const warriorBroadcastMessageSchema = z.object({ | ||
| message: z.string().nullable(), | ||
| }); | ||
|
|
||
| const warriorProjectSelectedMessageSchema = z.object({ | ||
| project: z.string().nullable(), | ||
| }); | ||
|
|
||
| const warriorProjectSchema = z.object({ | ||
| project_id: z.number().optional(), | ||
| title: z.string().optional(), | ||
| project_html: z.string().optional(), | ||
| utc_deadline: z.string().nullable().optional(), | ||
| }); | ||
|
|
||
| const warriorItemSchema = z.object({ | ||
| id: z.string(), | ||
| name: z.string(), | ||
| status: z.string().nullable().optional(), | ||
| project: z.string().nullable().optional(), | ||
| start_time: z.number().optional(), | ||
| }); | ||
|
|
||
| const projectRefreshMessageSchema = z | ||
| .object({ | ||
| project: warriorProjectSchema.optional(), | ||
| status: z.string().optional(), | ||
| items: z.array(warriorItemSchema).optional(), | ||
| }) | ||
| .nullable(); | ||
|
|
||
| const itemStatusMessageSchema = z.object({ | ||
| item_id: z.string(), | ||
| }); | ||
|
|
||
| const pipelineStartItemMessageSchema = z.object({ | ||
| item: warriorItemSchema, | ||
| }); | ||
|
|
||
| const bandwidthMessageSchema = z.object({ | ||
| received: z.number().optional(), | ||
| sent: z.number().optional(), | ||
| receiving: z.number().optional(), | ||
| sending: z.number().optional(), | ||
| session_id: z.string().optional(), | ||
| }); | ||
|
|
||
| type WarriorProject = z.infer<typeof warriorProjectSchema>; | ||
| type WarriorItem = z.infer<typeof warriorItemSchema>; | ||
| type SeesawFrame = z.infer<typeof seesawFrameSchema>; |
There was a problem hiding this comment.
Can you put this in a separate file?
| const frames = this.parseSockJsMessage(event.data); | ||
|
|
||
| for (const frame of frames) { | ||
| switch (frame.event_name) { |
There was a problem hiding this comment.
I think this should be put in a separate function to reduce cognitive complexity
| const integrationInstance = await createIntegrationAsync(integration); | ||
| return await integrationInstance.getStatusAsync(); | ||
| }, | ||
| cacheDuration: dayjs.duration(10, "seconds"), |
There was a problem hiding this comment.
10 seconds is very short, does it really need to be that short?
There was a problem hiding this comment.
Most likely not. I'll update it to every minute.
| <Stack gap={0}> | ||
| <Text fw={700} lineClamp={1}> | ||
| ArchiveTeam Warrior | ||
| </Text> |
There was a problem hiding this comment.
We mostly remove the names of widgets now from them.
Can you remove this one too?
There was a problem hiding this comment.
For sure! First time here, thanks for letting me know.
| const formatBytesPerSecond = (value?: number) => { | ||
| if (!value) return "0 KB/s"; | ||
|
|
||
| if (value >= 1024 * 1024) { | ||
| return `${(value / 1024 / 1024).toFixed(1)} MB/s`; | ||
| } | ||
|
|
||
| return `${Math.round(value / 1024)} KB/s`; | ||
| }; |
There was a problem hiding this comment.
We already have a method for this. Please remove and use the existing one.
|
I think we can still improve the spacing and padding of the widget. |
I'm more than happy to give it a shot. I'd definitely appreciate your input as well :) |
|
Thanks for the review. I pushed updates addressing the requested changes:
|
|
Did you resolve the comments from my review? If yes, please always mark them as "resolved". |
| const integrationInstance = await createIntegrationAsync(integration); | ||
| return await integrationInstance.getStatusAsync(); | ||
| }, | ||
| cacheDuration: dayjs.duration(1, "minute"), |
There was a problem hiding this comment.
Is 1 minute really needed here? 5 minutes should be enough too
Homarr
Thank you for your contribution. Please ensure that your pull request meets the following pull request:
pnpm build, autofix withpnpm format:fix)devbranchx,y,ior any abbrevation)Summary
Adds a read-only ArchiveTeam Warrior integration and widget.
The widget connects to the Warrior web interface and reads the Seesaw/SockJS status stream to display:
This first iteration intentionally does not expose control actions such as stopping the Warrior, changing projects, or modifying settings.
Testing
pnpm lintpnpm format:fixpnpm typecheckpnpm build