From 3ed7adc8b0a0d03042058f00b50e4059301b68cb Mon Sep 17 00:00:00 2001 From: SeDemal Date: Thu, 1 Aug 2024 23:43:26 +0200 Subject: [PATCH] feat: add default sorting and fix Icon sizing warnings --- packages/translation/src/lang/en.ts | 12 +- packages/widgets/src/downloads/component.tsx | 141 ++++++++++--------- packages/widgets/src/downloads/index.ts | 62 ++++---- 3 files changed, 125 insertions(+), 90 deletions(-) diff --git a/packages/translation/src/lang/en.ts b/packages/translation/src/lang/en.ts index 109dccfdb..f6e30cc0e 100644 --- a/packages/translation/src/lang/en.ts +++ b/packages/translation/src/lang/en.ts @@ -1040,6 +1040,15 @@ export default { columns: { label: "Columns to show", }, + enableRowSorting: { + label: "Enable items sorting", + }, + defaultSort: { + label: "Column used for sorting by default", + }, + descendingDefaultSort: { + label: "Invert sorting", + }, showCompletedUsenet: { label: "Show usenet entries marked as completed", }, @@ -1058,9 +1067,6 @@ export default { applyFilterToRatio: { label: "Use filter to calculate Ratio", }, - enableRowSorting: { - label: "Enable items sorting", - }, }, errors: { noColumns: "Select Columns in Items", diff --git a/packages/widgets/src/downloads/component.tsx b/packages/widgets/src/downloads/component.tsx index 769379ce1..2f557e70f 100644 --- a/packages/widgets/src/downloads/component.tsx +++ b/packages/widgets/src/downloads/component.tsx @@ -49,13 +49,13 @@ import { useScopedI18n } from "@homarr/translation/client"; import type { WidgetComponentProps } from "../definition"; //TODO: -// - Data Subscription permission issues <- Need help +// - Rename getData function and following +// - Update data on integration added <- update useSubscription integrationIds not working? +// - Make modals sizes relative (Based on whole screen) // - table tbody hide under thead and keep transparency <- Need help -// - Add integrations to shouldHide options <- Potential help needed -// - default sorting option <- but I don't wannaaaaa.... +// - Add integrations to shouldHide options <- Need help // - Move columns ratio table to css vars // - tests maybe? -// - Unexpected value xxxxx parsing width/height attribute <- Need help (Actually impacts all widgets using cq and var sizes...), Not critical //Ratio table for relative width between columns const columnsRatios: Record = { @@ -93,25 +93,10 @@ export default function DownloadClientsWidget({ //Translations const t = useScopedI18n("widget.downloads"); const tCommon = useScopedI18n("common"); - const noIntegrationError = useScopedI18n("integration.permission")("use"); //Item modal state and selection const [clickedIndex, setClickedIndex] = useState(0); const [opened, { open, close }] = useDisclosure(false); - if (integrationIds.length === 0) - return ( -
- {noIntegrationError} -
- ); - - if (options.columns.length === 0) - return ( -
- {t("errors.noColumns")} -
- ); - //Get API mutation functions const { mutate: mutateResumeItem } = clientApi.widget.downloads.resumeItem.useMutation(); const { mutate: mutatePauseItem } = clientApi.widget.downloads.pauseItem.useMutation(); @@ -175,7 +160,8 @@ export default function DownloadClientsWidget({ }, }; }), - ), + ) + .sort(({ type: typeA }, { type: typeB }) => typeA.length - typeB.length), [currentItems, integrationIds, options], ); @@ -316,9 +302,9 @@ export default function DownloadClientsWidget({ size="calc(var(--ratioWidth)*0.75)" > {isPaused ? ( - + ) : ( - + )} @@ -350,7 +336,7 @@ export default function DownloadClientsWidget({ - + @@ -373,7 +359,7 @@ export default function DownloadClientsWidget({ return ( category !== undefined && ( - + ) ); @@ -388,13 +374,13 @@ export default function DownloadClientsWidget({ }, }, { - ...columnsDefBase({ key: "id", showHeader: false }), + ...columnsDefBase({ key: "id", showHeader: false, align: "center" }), enableSorting: false, Cell: ({ cell }) => { const id = cell.getValue(); return ( - + ); }, @@ -493,7 +479,7 @@ export default function DownloadClientsWidget({ Cell: ({ cell }) => { const time = cell.getValue(); return time === 0 ? ( - + ) : ( {dayjs().add(time).fromNow()} ); @@ -553,6 +539,10 @@ export default function DownloadClientsWidget({ setOptions({ newOptions: { columns: columnOrder } }); }, initialState: { + sorting: + options.defaultSort != undefined + ? [{ id: options.defaultSort, desc: options.descendingDefaultSort }] + : undefined, columnVisibility: { actions: false, added: false, @@ -591,6 +581,21 @@ export default function DownloadClientsWidget({ { up: 0, down: 0 }, ); + if (integrationIds.length === 0) + return ( +
+ {tCommon("errors.noIntegration")} +
+ ); + + if (options.columns.length === 0) + return ( +
+ {t("errors.noColumns")} +
+ ); + //InfoModal and ClientControls hook might trigger here. + //The actual widget return ( @@ -621,42 +626,50 @@ interface ItemInfoModalProps { } const ItemInfoModal = ({ items, currentIndex, opened, onClose }: ItemInfoModalProps) => { - const item = useMemo(() => items[currentIndex], [items, currentIndex, opened]); + const item = useMemo( + () => items[currentIndex], + [items, currentIndex, opened], + ); const t = useScopedI18n("widget.downloads.states"); return ( - {item === undefined ?
{"No item found"}
: - - {item.name} - - - {`${item.integration.name} (${item.integration.kind})`} - - - - - - - - - - - - - - - } + {item === undefined ? ( +
{"No item found"}
+ ) : ( + + {item.name} + + + {`${item.integration.name} (${item.integration.kind})`} + + + + + + + + + + + + + + + + )}
); }; @@ -708,7 +721,9 @@ const ClientsControl = ({ clients, style }: ClientsControlProps) => { clients.forEach((client) => client.paused ? pausedIntegrations.push(client.integration.id) : activeIntegrations.push(client.integration.id), ); - const totalSpeed = humanFileSize(clients.reduce((count, { rates: { down } }) => count + down, 0))?.toString().concat("/s"); + const totalSpeed = humanFileSize(clients.reduce((count, { rates: { down } }) => count + down, 0)) + ?.toString() + .concat("/s"); const { mutate: mutateResumeQueue } = clientApi.widget.downloads.resume.useMutation(); const { mutate: mutatePauseQueue } = clientApi.widget.downloads.pause.useMutation(); const [opened, { open, close }] = useDisclosure(false); @@ -728,7 +743,7 @@ const ClientsControl = ({ clients, style }: ClientsControlProps) => { variant="light" onClick={() => mutateResumeQueue({ integrationIds: pausedIntegrations })} > - + @@ -807,7 +822,7 @@ const ClientsControl = ({ clients, style }: ClientsControlProps) => { variant="light" onClick={() => mutatePauseQueue({ integrationIds: activeIntegrations })} > - + diff --git a/packages/widgets/src/downloads/index.ts b/packages/widgets/src/downloads/index.ts index 9f0000694..8bc2e8624 100644 --- a/packages/widgets/src/downloads/index.ts +++ b/packages/widgets/src/downloads/index.ts @@ -6,35 +6,46 @@ import { createWidgetDefinition } from "../definition"; import { optionsBuilder } from "../options"; import type { ExtendedDownloadClientItem } from "@homarr/integrations"; +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 columnsSort = columnsList.filter((v) => !["actions","id","state"].includes(v)); + export const { definition, componentLoader, serverDataLoader } = createWidgetDefinition("downloads", { icon: IconDownload, options: optionsBuilder.from( (factory) => ({ columns: factory.multiSelect({ defaultValue: ["integration", "name", "progress", "time", "actions"], - options: ( - [ - "id", - "actions", - "added", - "category", - "downSpeed", - "index", - "integration", - "name", - "progress", - "ratio", - "received", - "sent", - "size", - "state", - "time", - "type", - "upSpeed", - ] as const satisfies (keyof ExtendedDownloadClientItem)[] - ).map((value) => ({ value, label: (t) => t(`widget.downloads.items.${value}.columnTitle`) })), + 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, }), @@ -57,11 +68,14 @@ export const { definition, componentLoader, serverDataLoader } = createWidgetDef applyFilterToRatio: factory.switch({ defaultValue: true, }), - enableRowSorting: factory.switch({ - defaultValue: false, - }), }), { + defaultSort: { + shouldHide: (options) => !options.enableRowSorting, + }, + descendingDefaultSort: { + shouldHide: (options) => !options.enableRowSorting, + }, showCompletedUsenet: { shouldHide: () => false, //Get from presence of usenet client in integration list },