mirror of
https://github.com/gethomepage/homepage.git
synced 2026-10-03 17:31:17 -07:00
Yay drop all these max fields
This commit is contained in:
@@ -85,6 +85,7 @@ To ensure cohesiveness of various widgets, the following should be used as a gui
|
||||
- Note that we reserve the right to decline widgets for projects that are very young (eg < ~1y) or those with a small reach (eg low GitHub stars). Again, this is in an effort to keep overall widget maintenance under control.
|
||||
- Widgets should be only one row of blocks
|
||||
- Widgets should be no more than 4 blocks wide and generally conform to the styling / design choices of other widgets
|
||||
- Use `withWidgetFields(service, defaultFields)` from `utils/widget-fields` to apply default fields and cap configured fields without mutating the service. The helper limits widgets to 4 fields.
|
||||
- Minimize the number of API calls
|
||||
- Avoid the use of custom proxy unless absolutely necessary
|
||||
- Widgets should be 'read-only', as in they should not make write changes using the relevant tool's API. Homepage widgets are designed to surface information, not to be a (usually worse) replacement for the tool itself.
|
||||
|
||||
@@ -5,12 +5,11 @@ import { useTranslation } from "next-i18next/pages";
|
||||
import useWidgetAPI from "utils/proxy/use-widget-api";
|
||||
import withWidgetFields from "utils/widget-fields";
|
||||
|
||||
const MAX_FIELDS = 4;
|
||||
const DEFAULT_FIELDS = ["running", "stopped", "total", "image_updates"];
|
||||
|
||||
export default function Component({ service: configuredService }) {
|
||||
const { t } = useTranslation();
|
||||
const service = withWidgetFields(configuredService, DEFAULT_FIELDS, MAX_FIELDS);
|
||||
const service = withWidgetFields(configuredService, DEFAULT_FIELDS);
|
||||
const { widget } = service;
|
||||
|
||||
const envNotSet = widget.env == null || widget.env === "";
|
||||
|
||||
@@ -6,12 +6,11 @@ import useWidgetAPI from "utils/proxy/use-widget-api";
|
||||
import withWidgetFields from "utils/widget-fields";
|
||||
|
||||
const BACKREST_DEFAULT_FIELDS = ["num_success_latest", "num_failure_latest", "num_failure_30", "bytes_added_30"];
|
||||
const MAX_ALLOWED_FIELDS = 4;
|
||||
|
||||
export default function Component({ service: configuredService }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const service = withWidgetFields(configuredService, BACKREST_DEFAULT_FIELDS, MAX_ALLOWED_FIELDS);
|
||||
const service = withWidgetFields(configuredService, BACKREST_DEFAULT_FIELDS);
|
||||
const { widget } = service;
|
||||
|
||||
const { data, error } = useWidgetAPI(widget, "summary");
|
||||
|
||||
@@ -5,12 +5,11 @@ import { useTranslation } from "next-i18next/pages";
|
||||
import useWidgetAPI from "utils/proxy/use-widget-api";
|
||||
import withWidgetFields from "utils/widget-fields";
|
||||
|
||||
const MAX_FIELDS = 4;
|
||||
const DEFAULT_FIELDS = ["running", "total", "cpu", "memory"];
|
||||
|
||||
export default function Component({ service: configuredService }) {
|
||||
const { t } = useTranslation();
|
||||
const service = withWidgetFields(configuredService, DEFAULT_FIELDS, MAX_FIELDS);
|
||||
const service = withWidgetFields(configuredService, DEFAULT_FIELDS);
|
||||
const { widget } = service;
|
||||
|
||||
const { data: stats, error: statsError } = useWidgetAPI(widget, "dashboard/stats");
|
||||
|
||||
@@ -6,11 +6,10 @@ import useWidgetAPI from "utils/proxy/use-widget-api";
|
||||
import withWidgetFields from "utils/widget-fields";
|
||||
|
||||
export const fritzboxDefaultFields = ["connectionStatus", "uptime", "maxDown", "maxUp"];
|
||||
const MAX_ALLOWED_FIELDS = 4;
|
||||
|
||||
export default function Component({ service: configuredService }) {
|
||||
const { t } = useTranslation();
|
||||
const service = withWidgetFields(configuredService, fritzboxDefaultFields, MAX_ALLOWED_FIELDS);
|
||||
const service = withWidgetFields(configuredService, fritzboxDefaultFields);
|
||||
const { widget } = service;
|
||||
const { data: fritzboxData, error: fritzboxError } = useWidgetAPI(widget, "status");
|
||||
|
||||
|
||||
@@ -6,11 +6,10 @@ import useWidgetAPI from "utils/proxy/use-widget-api";
|
||||
import withWidgetFields from "utils/widget-fields";
|
||||
|
||||
export const karakeepDefaultFields = ["bookmarks", "favorites", "archived", "highlights"];
|
||||
const MAX_ALLOWED_FIELDS = 4;
|
||||
|
||||
export default function Component({ service: configuredService }) {
|
||||
const { t } = useTranslation();
|
||||
const service = withWidgetFields(configuredService, karakeepDefaultFields, MAX_ALLOWED_FIELDS);
|
||||
const service = withWidgetFields(configuredService, karakeepDefaultFields);
|
||||
const { widget } = service;
|
||||
|
||||
const { data: statsData, error: statsError } = useWidgetAPI(widget, "stats");
|
||||
|
||||
@@ -5,7 +5,6 @@ import { useTranslation } from "next-i18next/pages";
|
||||
import useWidgetAPI from "utils/proxy/use-widget-api";
|
||||
import withWidgetFields from "utils/widget-fields";
|
||||
|
||||
const MAX_ALLOWED_FIELDS = 4;
|
||||
const SUMMARY_FIELDS = ["servers", "stacks", "containers"];
|
||||
const STACK_FIELDS = ["total", "running", "down", "unhealthy"];
|
||||
const CONTAINER_FIELDS = ["total", "running", "stopped", "unhealthy"];
|
||||
@@ -18,7 +17,7 @@ export default function Component({ service: configuredService }) {
|
||||
: configuredWidget.showStacks
|
||||
? STACK_FIELDS
|
||||
: CONTAINER_FIELDS;
|
||||
const service = withWidgetFields(configuredService, defaultFields, MAX_ALLOWED_FIELDS);
|
||||
const service = withWidgetFields(configuredService, defaultFields);
|
||||
const { widget } = service;
|
||||
const containersEndpoint = !(!widget.showSummary && widget.showStacks) ? "containers" : "";
|
||||
const { data: containersData, error: containersError } = useWidgetAPI(widget, containersEndpoint);
|
||||
|
||||
@@ -6,11 +6,10 @@ import useWidgetAPI from "utils/proxy/use-widget-api";
|
||||
import withWidgetFields from "utils/widget-fields";
|
||||
|
||||
const DEFAULT_FIELDS = ["itemsHandled", "episodesHandled", "moviesHandled", "reclaimable"];
|
||||
const MAX_FIELDS = 4;
|
||||
|
||||
export default function Component({ service: configuredService }) {
|
||||
const { t } = useTranslation();
|
||||
const service = withWidgetFields(configuredService, DEFAULT_FIELDS, MAX_FIELDS);
|
||||
const service = withWidgetFields(configuredService, DEFAULT_FIELDS);
|
||||
const { widget } = service;
|
||||
|
||||
const { data, error } = useWidgetAPI(widget);
|
||||
|
||||
@@ -5,12 +5,11 @@ import { useTranslation } from "next-i18next/pages";
|
||||
import useWidgetAPI from "utils/proxy/use-widget-api";
|
||||
import withWidgetFields from "utils/widget-fields";
|
||||
|
||||
const MAX_ALLOWED_FIELDS = 4;
|
||||
const DEFAULT_FIELDS = ["sites", "resources", "targets", "traffic"];
|
||||
|
||||
export default function Component({ service: configuredService }) {
|
||||
const { t } = useTranslation();
|
||||
const service = withWidgetFields(configuredService, DEFAULT_FIELDS, MAX_ALLOWED_FIELDS);
|
||||
const service = withWidgetFields(configuredService, DEFAULT_FIELDS);
|
||||
const { widget } = service;
|
||||
|
||||
const { data: sitesData, error: sitesError } = useWidgetAPI(widget, "sites");
|
||||
|
||||
@@ -6,10 +6,9 @@ import useWidgetAPI from "utils/proxy/use-widget-api";
|
||||
import withWidgetFields from "utils/widget-fields";
|
||||
|
||||
const ROMM_DEFAULT_FIELDS = ["platforms", "totalRoms", "saves", "states"];
|
||||
const MAX_ALLOWED_FIELDS = 4;
|
||||
|
||||
export default function Component({ service: configuredService }) {
|
||||
const service = withWidgetFields(configuredService, ROMM_DEFAULT_FIELDS, MAX_ALLOWED_FIELDS);
|
||||
const service = withWidgetFields(configuredService, ROMM_DEFAULT_FIELDS);
|
||||
const { widget } = service;
|
||||
const { t } = useTranslation();
|
||||
const { data: response, error: responseError } = useWidgetAPI(widget, "statistics");
|
||||
|
||||
@@ -5,10 +5,9 @@ import useWidgetAPI from "utils/proxy/use-widget-api";
|
||||
import withWidgetFields from "utils/widget-fields";
|
||||
|
||||
export const seerrDefaultFields = ["pending", "approved", "completed"];
|
||||
const MAX_ALLOWED_FIELDS = 4;
|
||||
|
||||
export default function Component({ service: configuredService }) {
|
||||
const service = withWidgetFields(configuredService, seerrDefaultFields, MAX_ALLOWED_FIELDS);
|
||||
const service = withWidgetFields(configuredService, seerrDefaultFields);
|
||||
const { widget } = service;
|
||||
const isIssueEnabled = widget.fields.includes("issues");
|
||||
|
||||
|
||||
@@ -6,11 +6,10 @@ import useWidgetAPI from "utils/proxy/use-widget-api";
|
||||
import withWidgetFields from "utils/widget-fields";
|
||||
|
||||
const slskdDefaultFields = ["slskStatus", "downloads", "uploads", "sharedFiles"];
|
||||
const MAX_ALLOWED_FIELDS = 4;
|
||||
|
||||
export default function Component({ service: configuredService }) {
|
||||
const { t } = useTranslation();
|
||||
const service = withWidgetFields(configuredService, slskdDefaultFields, MAX_ALLOWED_FIELDS);
|
||||
const service = withWidgetFields(configuredService, slskdDefaultFields);
|
||||
const { widget } = service;
|
||||
|
||||
const { data: appData, error: appError } = useWidgetAPI(widget, "application");
|
||||
|
||||
@@ -6,12 +6,11 @@ import useWidgetAPI from "utils/proxy/use-widget-api";
|
||||
import withWidgetFields from "utils/widget-fields";
|
||||
|
||||
const DEFAULT_FIELDS = ["address", "last_seen", "expires"];
|
||||
const MAX_ALLOWED_FIELDS = 4;
|
||||
|
||||
export default function Component({ service: configuredService }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const service = withWidgetFields(configuredService, DEFAULT_FIELDS, MAX_ALLOWED_FIELDS);
|
||||
const service = withWidgetFields(configuredService, DEFAULT_FIELDS);
|
||||
const { widget } = service;
|
||||
|
||||
const { data: tailscaleData, error: tailscaleError } = useWidgetAPI(widget, "device");
|
||||
|
||||
@@ -5,14 +5,12 @@ import { useTranslation } from "next-i18next/pages";
|
||||
import useWidgetAPI from "utils/proxy/use-widget-api";
|
||||
import withWidgetFields from "utils/widget-fields";
|
||||
|
||||
const MAX_ALLOWED_FIELDS = 4;
|
||||
|
||||
export const technitiumDefaultFields = ["totalQueries", "totalAuthoritative", "totalCached", "totalServerFailure"];
|
||||
|
||||
export default function Component({ service: configuredService }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const service = withWidgetFields(configuredService, technitiumDefaultFields, MAX_ALLOWED_FIELDS);
|
||||
const service = withWidgetFields(configuredService, technitiumDefaultFields);
|
||||
const { widget } = service;
|
||||
|
||||
const params = {
|
||||
|
||||
@@ -3,9 +3,9 @@ import Container from "components/services/widget/container";
|
||||
import { useTranslation } from "next-i18next/pages";
|
||||
|
||||
import useWidgetAPI from "utils/proxy/use-widget-api";
|
||||
import withWidgetFields from "utils/widget-fields";
|
||||
|
||||
const UNRAID_DEFAULT_FIELDS = ["status", "cpu", "memoryPercent", "notifications"];
|
||||
const MAX_ALLOWED_FIELDS = 4;
|
||||
|
||||
const POOLS = ["pool1", "pool2", "pool3", "pool4"];
|
||||
const POOL_FIELDS = [
|
||||
@@ -14,8 +14,9 @@ const POOL_FIELDS = [
|
||||
{ param: "UsedPercent", label: "poolUsed", valueKey: "fsUsedPercent", valueType: "common.percent" },
|
||||
];
|
||||
|
||||
export default function Component({ service }) {
|
||||
export default function Component({ service: configuredService }) {
|
||||
const { t } = useTranslation();
|
||||
const service = withWidgetFields(configuredService, UNRAID_DEFAULT_FIELDS);
|
||||
const { widget } = service;
|
||||
|
||||
const { data, error } = useWidgetAPI(widget);
|
||||
@@ -24,12 +25,6 @@ export default function Component({ service }) {
|
||||
return <Container service={service} error={error} />;
|
||||
}
|
||||
|
||||
if (!widget.fields?.length) {
|
||||
widget.fields = UNRAID_DEFAULT_FIELDS;
|
||||
} else if (widget.fields.length > MAX_ALLOWED_FIELDS) {
|
||||
widget.fields = widget.fields.slice(0, MAX_ALLOWED_FIELDS);
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
return (
|
||||
<Container service={service}>
|
||||
|
||||
@@ -20,14 +20,17 @@ describe("widgets/unraid/component", () => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("defaults widget.fields and filters down to 4 visible blocks while loading", () => {
|
||||
it("defaults fields and filters down to 4 visible blocks while loading", () => {
|
||||
useWidgetAPI.mockReturnValue({ data: undefined, error: undefined });
|
||||
|
||||
const service = { widget: { type: "unraid" } };
|
||||
const { container } = renderWithProviders(<Component service={service} />, { settings: { hideErrors: false } });
|
||||
|
||||
// Component sets default fields
|
||||
expect(service.widget.fields).toEqual(["status", "cpu", "memoryPercent", "notifications"]);
|
||||
expect(service.widget.fields).toBeUndefined();
|
||||
expect(useWidgetAPI).toHaveBeenCalledWith({
|
||||
type: "unraid",
|
||||
fields: ["status", "cpu", "memoryPercent", "notifications"],
|
||||
});
|
||||
|
||||
// Container filters the many placeholder Blocks down to the selected fields.
|
||||
expect(container.querySelectorAll(".service-block")).toHaveLength(4);
|
||||
|
||||
@@ -5,7 +5,6 @@ import { useTranslation } from "next-i18next/pages";
|
||||
import useWidgetAPI from "utils/proxy/use-widget-api";
|
||||
import withWidgetFields from "utils/widget-fields";
|
||||
|
||||
const MAX_ALLOWED_FIELDS = 4;
|
||||
const DEFAULT_FIELDS = ["activeSubscriptions", "nextRenewingSubscription", "thisMonthlyCost", "nextMonthlyCost"];
|
||||
|
||||
const todayDate = new Date();
|
||||
@@ -20,7 +19,7 @@ function toApiMonthYear(offset = 0) {
|
||||
|
||||
export default function Component({ service: configuredService }) {
|
||||
const { t } = useTranslation();
|
||||
const service = withWidgetFields(configuredService, DEFAULT_FIELDS, MAX_ALLOWED_FIELDS);
|
||||
const service = withWidgetFields(configuredService, DEFAULT_FIELDS);
|
||||
const { widget } = service;
|
||||
|
||||
const subscriptionsEndPoint =
|
||||
|
||||
Reference in New Issue
Block a user