* fix(deps): update dependency drizzle-zod to ^0.8.2 * chore: update zod to v4 import * fix: path is no longer available in transform context * fix: AnyZodObject does no longer exist * fix: auth env.ts using wrong createEnv and remove unused file env-validation.ts * fix: required_error no longer exists on z.string * fix: zod error map is deprecated and replaced with config * fix: default requires callback now * fix: migrate zod resolver for mantine * fix: remove unused form translation file * fix: wrong enum type * fix: record now requires two arguments * fix: add-confirm-password-refinement type issues * fix: add missing first record argument for entityStateSchema * fix: migrate superrefine to check * fix(deps): upgrade zod-form-data to v3 * fix: migrate superRefine to check for mediaUploadSchema * fix: authProvidersSchema default is array * fix: use stringbool instead of custom implementation * fix: record requires first argument * fix: migrate superRefine to check for certificate router * fix: confirm pasword refinement is overwriting types * fix: email optional not working * fix: migrate intersection to object converter * fix: safe parse return value rename * fix: easier access for min and max number value * fix: migrate superRefine to check for oldmarr import file * fix: inference of enum shape for old-import board-size wrong * fix: errors renamed to issues * chore: address pull request feedback * fix: zod form requires object * fix: inference for use-zod-form not working * fix: remove unnecessary convertion * fix(deps): upgrade trpc-to-openapi to v3 * fix: build error * fix: migrate missing zod imports to v4 * fix: migrate zod records to v4 * fix: missing core package dependency in api module * fix: unable to convert custom zod schema to openapi schema * fix(deps): upgrade zod to v4 * chore(renovate): enable zod dependency updates * test: add simple unit test for convertIntersectionToZodObject --------- Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
123 lines
4.0 KiB
TypeScript
123 lines
4.0 KiB
TypeScript
import { IconDownload } from "@tabler/icons-react";
|
|
import { z } from "zod/v4";
|
|
|
|
import { getIntegrationKindsByCategory } from "@homarr/definitions";
|
|
import type { ExtendedDownloadClientItem } from "@homarr/integrations";
|
|
|
|
import { createWidgetDefinition } from "../definition";
|
|
import { optionsBuilder } from "../options";
|
|
|
|
const columnsList = [
|
|
"id",
|
|
"actions",
|
|
"added",
|
|
"category",
|
|
"downSpeed",
|
|
"index",
|
|
"integration",
|
|
"name",
|
|
"progress",
|
|
"ratio",
|
|
"received",
|
|
"sent",
|
|
"size",
|
|
"state",
|
|
"time",
|
|
"type",
|
|
"upSpeed",
|
|
] as const satisfies (keyof ExtendedDownloadClientItem)[];
|
|
const sortingExclusion = ["actions", "id", "state"] as const satisfies readonly (typeof columnsList)[number][];
|
|
const columnsSort = columnsList.filter((column) =>
|
|
sortingExclusion.some((exclusion) => exclusion !== column),
|
|
) as Exclude<typeof columnsList, (typeof sortingExclusion)[number]>;
|
|
|
|
export const { definition, componentLoader } = createWidgetDefinition("downloads", {
|
|
icon: IconDownload,
|
|
createOptions() {
|
|
return optionsBuilder.from(
|
|
(factory) => ({
|
|
columns: factory.multiSelect({
|
|
defaultValue: ["integration", "name", "progress", "time", "actions"],
|
|
options: columnsList.map((value) => ({
|
|
value,
|
|
label: (t) => t(`widget.downloads.items.${value}.columnTitle`),
|
|
})),
|
|
searchable: true,
|
|
}),
|
|
enableRowSorting: factory.switch({
|
|
defaultValue: false,
|
|
}),
|
|
defaultSort: factory.select({
|
|
defaultValue: "type",
|
|
options: columnsSort.map((value) => ({
|
|
value,
|
|
label: (t) => t(`widget.downloads.items.${value}.columnTitle`),
|
|
})),
|
|
}),
|
|
descendingDefaultSort: factory.switch({
|
|
defaultValue: false,
|
|
}),
|
|
showCompletedUsenet: factory.switch({
|
|
defaultValue: true,
|
|
}),
|
|
showCompletedTorrent: factory.switch({
|
|
defaultValue: true,
|
|
}),
|
|
showCompletedHttp: factory.switch({
|
|
defaultValue: true,
|
|
}),
|
|
activeTorrentThreshold: factory.number({
|
|
//in KiB/s
|
|
validate: z.number().min(0),
|
|
defaultValue: 0,
|
|
step: 1,
|
|
}),
|
|
categoryFilter: factory.multiText({
|
|
defaultValue: [] as string[],
|
|
validate: z.string(),
|
|
}),
|
|
filterIsWhitelist: factory.switch({
|
|
defaultValue: false,
|
|
}),
|
|
applyFilterToRatio: factory.switch({
|
|
defaultValue: true,
|
|
}),
|
|
limitPerIntegration: factory.number({
|
|
defaultValue: 50,
|
|
validate: z.number().min(1),
|
|
withDescription: true,
|
|
}),
|
|
}),
|
|
{
|
|
defaultSort: {
|
|
shouldHide: (options) => !options.enableRowSorting,
|
|
},
|
|
descendingDefaultSort: {
|
|
shouldHide: (options) => !options.enableRowSorting,
|
|
},
|
|
showCompletedUsenet: {
|
|
shouldHide: (_, integrationKinds) =>
|
|
!getIntegrationKindsByCategory("usenet").some((kinds) => integrationKinds.includes(kinds)),
|
|
},
|
|
showCompletedTorrent: {
|
|
shouldHide: (_, integrationKinds) =>
|
|
!getIntegrationKindsByCategory("torrent").some((kinds) => integrationKinds.includes(kinds)),
|
|
},
|
|
showCompletedHttp: {
|
|
shouldHide: (_, integrationKinds) =>
|
|
!getIntegrationKindsByCategory("miscellaneous").some((kinds) => integrationKinds.includes(kinds)),
|
|
},
|
|
activeTorrentThreshold: {
|
|
shouldHide: (_, integrationKinds) =>
|
|
!getIntegrationKindsByCategory("torrent").some((kinds) => integrationKinds.includes(kinds)),
|
|
},
|
|
applyFilterToRatio: {
|
|
shouldHide: (_, integrationKinds) =>
|
|
!getIntegrationKindsByCategory("torrent").some((kinds) => integrationKinds.includes(kinds)),
|
|
},
|
|
},
|
|
);
|
|
},
|
|
supportedIntegrations: getIntegrationKindsByCategory("downloadClient"),
|
|
}).withDynamicImport(() => import("./component"));
|