feat(integrations): add ArchiveTeam Warrior widget (#5784)
* feat(integrations): add ArchiveTeam Warrior widget * feat(integrations): add support for basic auth for archive warrior * refactor(integrations): address ArchiveTeam Warrior review feedback * Increase cache duration from 1 to 5 minutes --------- Co-authored-by: Manuel <30572287+manuel-rw@users.noreply.github.com>
This commit is contained in:
1 parent
2ae83458e6
commit
dd57ee2102
14 files changed
+689
No files matched your search
@@ -0,0 +1,100 @@
|
||||
"use client";
|
||||
|
||||
import { Avatar, Badge, Card, Group, SimpleGrid, Stack, Text } from "@mantine/core";
|
||||
|
||||
import { clientApi } from "@homarr/api/client";
|
||||
import { humanFileSize } from "@homarr/common";
|
||||
import { getIconUrl } from "@homarr/definitions";
|
||||
|
||||
import type { WidgetComponentProps } from "../definition";
|
||||
|
||||
export default function ArchiveTeamWarriorWidget({
|
||||
integrationIds,
|
||||
options,
|
||||
}: WidgetComponentProps<"archiveTeamWarrior">) {
|
||||
const integrationId = integrationIds[0];
|
||||
|
||||
if (!integrationId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return <ArchiveTeamWarriorWidgetContent integrationId={integrationId} options={options} />;
|
||||
}
|
||||
|
||||
const ArchiveTeamWarriorWidgetContent = ({
|
||||
integrationId,
|
||||
options,
|
||||
}: {
|
||||
integrationId: string;
|
||||
options: WidgetComponentProps<"archiveTeamWarrior">["options"];
|
||||
}) => {
|
||||
const [data] = clientApi.widget.archiveTeamWarrior.getStatus.useSuspenseQuery({
|
||||
integrationId,
|
||||
});
|
||||
|
||||
const utils = clientApi.useUtils();
|
||||
|
||||
clientApi.widget.archiveTeamWarrior.subscribeStatus.useSubscription(
|
||||
{ integrationId },
|
||||
{
|
||||
onData: (next) => {
|
||||
utils.widget.archiveTeamWarrior.getStatus.setData({ integrationId }, next);
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
const status = data.status;
|
||||
const projectName = status.project?.title ?? status.selectedProject ?? "No project selected";
|
||||
|
||||
return (
|
||||
<Stack p="xs" gap="xs" h="100%">
|
||||
<Group justify="space-between" align="center" wrap="nowrap">
|
||||
<Group gap="xs" wrap="nowrap" miw={0}>
|
||||
<Avatar size="sm" radius="md" src={getIconUrl("archiveTeamWarrior")} />
|
||||
<Text size="sm" c="dimmed" lineClamp={1}>
|
||||
{projectName}
|
||||
</Text>
|
||||
</Group>
|
||||
|
||||
<Badge size="sm" color={status.status === "Running" ? "green" : "gray"}>
|
||||
{status.status}
|
||||
</Badge>
|
||||
</Group>
|
||||
|
||||
{options.showBroadcastMessage && status.broadcastMessage && (
|
||||
<Card withBorder p="xs">
|
||||
<Text size="xs" lineClamp={3}>
|
||||
{status.broadcastMessage}
|
||||
</Text>
|
||||
</Card>
|
||||
)}
|
||||
|
||||
<SimpleGrid cols={2} spacing="xs">
|
||||
<Metric label="Running" value={status.counts.running} />
|
||||
<Metric label="Done" value={status.counts.completed} />
|
||||
<Metric label="Failed" value={status.counts.failed} />
|
||||
<Metric label="Canceled" value={status.counts.canceled} />
|
||||
</SimpleGrid>
|
||||
|
||||
{status.bandwidth && (
|
||||
<SimpleGrid cols={2} spacing="xs">
|
||||
<Metric label="Download" value={formatBandwidth(status.bandwidth.receiving)} />
|
||||
<Metric label="Upload" value={formatBandwidth(status.bandwidth.sending)} />
|
||||
</SimpleGrid>
|
||||
)}
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
const Metric = ({ label, value }: { label: string; value: number | string }) => (
|
||||
<Stack gap={0} miw={0}>
|
||||
<Text size="md" fw={700} lineClamp={1}>
|
||||
{value}
|
||||
</Text>
|
||||
<Text size="xs" c="dimmed" lineClamp={1}>
|
||||
{label}
|
||||
</Text>
|
||||
</Stack>
|
||||
);
|
||||
|
||||
const formatBandwidth = (value?: number) => humanFileSize(Math.round(value ?? 0), "/s");
|
||||
@@ -0,0 +1,16 @@
|
||||
import { IconArchive } from "@tabler/icons-react";
|
||||
|
||||
import { createWidgetDefinition } from "../definition";
|
||||
import { optionsBuilder } from "../options";
|
||||
|
||||
export const { definition, componentLoader } = createWidgetDefinition("archiveTeamWarrior", {
|
||||
icon: IconArchive,
|
||||
createOptions() {
|
||||
return optionsBuilder.from((factory) => ({
|
||||
showBroadcastMessage: factory.switch({
|
||||
defaultValue: true,
|
||||
}),
|
||||
}));
|
||||
},
|
||||
supportedIntegrations: ["archiveTeamWarrior"],
|
||||
}).withDynamicImport(() => import("./component"));
|
||||
@@ -10,6 +10,7 @@ import type { SettingsContextProps } from "@homarr/settings/creator";
|
||||
import * as anchorNote from "./anchor-note";
|
||||
import * as audioStats from "./audio-stats";
|
||||
import * as app from "./app";
|
||||
import * as archiveTeamWarrior from "./archive-team-warrior";
|
||||
import * as bookmarks from "./bookmarks";
|
||||
import * as calendar from "./calendar";
|
||||
import * as clock from "./clock";
|
||||
@@ -67,6 +68,7 @@ export const widgetImports = {
|
||||
clock,
|
||||
weather,
|
||||
app,
|
||||
archiveTeamWarrior,
|
||||
anchorNote,
|
||||
notebook,
|
||||
iframe,
|
||||
|
||||
Reference in new issue
Block a user