Feature: Firefly widget (#4683)

Signed-off-by: Amjad Alsharafi <26300843+Amjad50@users.noreply.github.com>
Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com>
pull/4691/head
Amjad Alsharafi 3 weeks ago committed by GitHub
parent e6a821ecc3
commit cae304b7eb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,17 @@
---
title: Firefly III
description: Firefly III Widget Configuration
---
Learn more about [Firefly III](https://www.firefly-iii.org/).
Find your API key under `Options > Profile > OAuth > Personal Access Tokens`.
Allowed fields: `["networth" ,"budget"]`.
```yaml
widget:
type: firefly
url: https://firefly.host.or.ip
key: personalaccesstoken.personalaccesstoken.personalaccesstoken
```

@ -33,6 +33,7 @@ You can also find a list of all available service widgets in the sidebar navigat
- [ESPHome](esphome.md)
- [EVCC](evcc.md)
- [Fileflows](fileflows.md)
- [Firefly III](firefly.md)
- [Flood](flood.md)
- [FreshRSS](freshrss.md)
- [Frigate](frigate.md)

@ -56,6 +56,7 @@ nav:
- widgets/services/esphome.md
- widgets/services/evcc.md
- widgets/services/fileflows.md
- widgets/services/firefly.md
- widgets/services/flood.md
- widgets/services/freshrss.md
- widgets/services/frigate.md

@ -702,6 +702,10 @@
"processed": "Processed",
"time": "Time"
},
"firefly": {
"networth": "Net Worth",
"budget": "Budget"
},
"grafana": {
"dashboards": "Dashboards",
"datasources": "Data Sources",

@ -48,6 +48,7 @@ export default async function credentialedProxyHandler(req, res, map) {
"tandoor",
"pterodactyl",
"vikunja",
"firefly",
].includes(widget.type)
) {
headers.Authorization = `Bearer ${widget.key}`;

@ -30,6 +30,7 @@ const components = {
esphome: dynamic(() => import("./esphome/component")),
evcc: dynamic(() => import("./evcc/component")),
fileflows: dynamic(() => import("./fileflows/component")),
firefly: dynamic(() => import("./firefly/component")),
flood: dynamic(() => import("./flood/component")),
freshrss: dynamic(() => import("./freshrss/component")),
frigate: dynamic(() => import("./frigate/component")),

@ -0,0 +1,71 @@
import { useTranslation } from "next-i18next";
import Container from "components/services/widget/container";
import Block from "components/services/widget/block";
import useWidgetAPI from "utils/proxy/use-widget-api";
export default function Component({ service }) {
const { t } = useTranslation();
const { widget } = service;
const startOfMonth = new Date();
startOfMonth.setDate(1);
startOfMonth.setHours(0, 0, 0, 0);
const startOfMonthFormatted = startOfMonth.toISOString().split("T")[0];
const endOfMonth = new Date(startOfMonth);
endOfMonth.setMonth(endOfMonth.getMonth() + 1);
endOfMonth.setDate(0);
endOfMonth.setHours(23, 59, 59, 999);
const endOfMonthFormatted = endOfMonth.toISOString().split("T")[0];
const { data: summaryData, error: summaryError } = useWidgetAPI(widget, "summary", {
start: startOfMonthFormatted,
end: endOfMonthFormatted,
});
const { data: budgetData, error: budgetError } = useWidgetAPI(widget, "budgets", {
start: startOfMonthFormatted,
end: endOfMonthFormatted,
});
if (summaryError || budgetError) {
return <Container service={service} error="Failed to load Firefly account summary and budgets" />;
}
if (!summaryData || !budgetData) {
return (
<Container service={service}>
<Block label="firefly.networth" />
<Block label="firefly.budget" />
</Container>
);
}
const netWorth = Object.keys(summaryData)
.filter((key) => key.includes("net-worth-in"))
.map((key) => summaryData[key]);
let budgetValue = null;
if (budgetData.data?.length && budgetData.data[0].type === "available_budgets") {
const budgetAmount = parseFloat(budgetData.data[0].attributes.amount);
const budgetSpent = -parseFloat(budgetData.data[0].attributes.spent_in_budgets[0]?.sum ?? "0");
const budgetCurrency = budgetData.data[0].attributes.currency_symbol;
budgetValue = `${budgetCurrency} ${t("common.number", {
value: budgetSpent,
minimumFractionDigits: 2,
})} / ${budgetCurrency} ${t("common.number", {
value: budgetAmount,
minimumFractionDigits: 2,
})}`;
}
return (
<Container service={service}>
<Block label="firefly.networth" value={netWorth[0].value_parsed} />
<Block label="firefly.budget" value={budgetValue} />
</Container>
);
}

@ -0,0 +1,19 @@
import credentialedProxyHandler from "utils/proxy/handlers/credentialed";
const widget = {
api: "{url}/api/{endpoint}",
proxyHandler: credentialedProxyHandler,
mappings: {
summary: {
endpoint: "v1/summary/basic",
params: ["start", "end"],
},
budgets: {
endpoint: "v1/available-budgets",
params: ["start", "end"],
},
},
};
export default widget;

@ -24,6 +24,7 @@ import emby from "./emby/widget";
import esphome from "./esphome/widget";
import evcc from "./evcc/widget";
import fileflows from "./fileflows/widget";
import firefly from "./firefly/widget";
import flood from "./flood/widget";
import freshrss from "./freshrss/widget";
import frigate from "./frigate/widget";
@ -157,6 +158,7 @@ const widgets = {
esphome,
evcc,
fileflows,
firefly,
flood,
freshrss,
frigate,

Loading…
Cancel
Save