diff --git a/client/src/components/column.tsx b/client/src/components/column.tsx index 04163ed..8ccd11c 100644 --- a/client/src/components/column.tsx +++ b/client/src/components/column.tsx @@ -18,6 +18,7 @@ dayjs.extend(utc); interface BaseColumnProps { id: keyof Obj & string; + dataId?: keyof Obj & string; i18ncat?: string; i18nkey?: string; dataSource: Obj[]; @@ -50,12 +51,15 @@ function Column(props: BaseColumnProps & FilteredColumnProps & CustomC dataIndex: props.id, title: t(props.i18nkey ?? `${props.i18ncat}.fields.${props.id}`), sorter: true, - sortOrder: getSortOrderForField(typedSorters, props.id), + sortOrder: getSortOrderForField(typedSorters, props.dataId ?? props.id), filterMultiple: props.allowMultipleFilters ?? true, }; if (props.filters && props.filteredValue) { columnProps.filters = props.filters; columnProps.filteredValue = props.filteredValue; + if (props.dataId) { + columnProps.key = props.dataId; + } } if (props.render) { columnProps.render = props.render; @@ -80,7 +84,7 @@ export function RichColumn(props: BaseColumnProps) { } interface FilteredQueryColumnProps extends BaseColumnProps { - filterValueQuery: UseQueryResult; + filterValueQuery: UseQueryResult; allowMultipleFilters?: boolean; } @@ -90,10 +94,13 @@ export function FilteredQueryColumn(props: FilteredQueryColumnProps) { let filters: ColumnFilterItem[] = []; if (query.data) { filters = query.data.map((item) => { - return { - text: item, - value: item, - }; + if (typeof item === "string") { + return { + text: item, + value: item, + }; + } + return item; }); } filters.push({ @@ -102,7 +109,7 @@ export function FilteredQueryColumn(props: FilteredQueryColumnProps) { }); const typedFilters = typeFilters(props.tableState.filters); - const filteredValue = getFiltersForField(typedFilters, props.id); + const filteredValue = getFiltersForField(typedFilters, props.dataId ?? props.id); return Column({ ...props, filters, filteredValue }); } @@ -160,10 +167,13 @@ export function SpoolIconColumn(props: SpoolIconColumnProps) { let filters: ColumnFilterItem[] = []; if (query.data) { filters = query.data.map((item) => { - return { - text: item, - value: item, - }; + if (typeof item === "string") { + return { + text: item, + value: item, + }; + } + return item; }); } filters.push({ @@ -172,7 +182,7 @@ export function SpoolIconColumn(props: SpoolIconColumnProps) { }); const typedFilters = typeFilters(props.tableState.filters); - const filteredValue = getFiltersForField(typedFilters, props.id); + const filteredValue = getFiltersForField(typedFilters, props.dataId ?? props.id); return Column({ ...props, diff --git a/client/src/components/otherModels.tsx b/client/src/components/otherModels.tsx index 178fbd0..19c01f5 100644 --- a/client/src/components/otherModels.tsx +++ b/client/src/components/otherModels.tsx @@ -1,10 +1,11 @@ import { useQuery } from "@tanstack/react-query"; import { IFilament } from "../pages/filaments/model"; import { IVendor } from "../pages/vendors/model"; +import { ColumnFilterItem } from "antd/es/table/interface"; -export function useSpoolmanFilamentFullNames() { +export function useSpoolmanFilamentFilter() { const apiEndpoint = import.meta.env.VITE_APIURL; - return useQuery({ + return useQuery({ queryKey: ["filaments"], queryFn: async () => { const response = await fetch(apiEndpoint + "/filament"); @@ -15,20 +16,28 @@ export function useSpoolmanFilamentFullNames() { }, select: (data) => { // Concatenate vendor name and filament name - let names = data + const names = data + // Remove empty names .filter((filament) => { return filament.name !== null && filament.name !== undefined && filament.name !== ""; }) + // Transform to ColumnFilterItem .map((filament) => { + let name = ""; if (filament.vendor?.name) { - return `${filament.vendor.name} - ${filament.name ?? ""}`; + name = `${filament.vendor.name} - ${filament.name ?? ""}`; } else { - return `${filament.name ?? ""}`; + name = `${filament.name ?? ""}`; } + return { + text: name, + value: filament.id, + }; }) - .sort(); - // Remove duplicates - names = [...new Set(names)]; + // Remove duplicates + .filter((item, index, self) => self.findIndex((t) => t.value === item.value) === index) + // Sort by name + .sort((a, b) => a.text.localeCompare(b.text)); return names; }, }); diff --git a/client/src/components/spoolSelectModal.tsx b/client/src/components/spoolSelectModal.tsx index a944151..b5863e0 100644 --- a/client/src/components/spoolSelectModal.tsx +++ b/client/src/components/spoolSelectModal.tsx @@ -5,7 +5,7 @@ import { FilteredQueryColumn, SortedColumn, SpoolIconColumn } from "./column"; import { TableState } from "../utils/saveload"; import { useTable } from "@refinedev/antd"; import { t } from "i18next"; -import { useSpoolmanFilamentFullNames, useSpoolmanMaterials } from "./otherModels"; +import { useSpoolmanFilamentFilter, useSpoolmanMaterials } from "./otherModels"; interface Props { visible: boolean; @@ -15,7 +15,8 @@ interface Props { } interface ISpoolCollapsed extends ISpool { - "filament.name": string; + combined_name: string; + "filament.id": number; "filament.material"?: string; } @@ -37,10 +38,10 @@ const SpoolSelectModal: React.FC = ({ visible, description, onCancel, onC pageSize: 10, }, sorters: { - mode: "off", + mode: "server", }, filters: { - mode: "off", + mode: "server", }, }); @@ -63,7 +64,8 @@ const SpoolSelectModal: React.FC = ({ visible, description, onCancel, onC } return { ...element, - "filament.name": filament_name, + combined_name: filament_name, + "filament.id": element.filament.id, "filament.material": element.filament.material, }; }), @@ -128,12 +130,13 @@ const SpoolSelectModal: React.FC = ({ visible, description, onCancel, onC tableState, })} {SpoolIconColumn({ - id: "filament.name", - i18ncat: "spool", + id: "combined_name", + dataId: "filament.id", + i18nkey: "spool.fields.filament_name", color: (record: ISpoolCollapsed) => record.filament.color_hex, dataSource, tableState, - filterValueQuery: useSpoolmanFilamentFullNames(), + filterValueQuery: useSpoolmanFilamentFilter(), })} {FilteredQueryColumn({ id: "filament.material", diff --git a/client/src/pages/filaments/list.tsx b/client/src/pages/filaments/list.tsx index 74893c9..7be2c0c 100644 --- a/client/src/pages/filaments/list.tsx +++ b/client/src/pages/filaments/list.tsx @@ -125,7 +125,7 @@ export const FilamentList: React.FC = () => { menu={{ items: allColumns.map((column_id) => ({ key: column_id, - label: t(`filament.fields.${column_id}`), + label: t(`filament.fields.${column_id.replace(".", "_")}`), })), selectedKeys: showColumns, selectable: true, @@ -159,7 +159,6 @@ export const FilamentList: React.FC = () => { dataSource, tableState, filterValueQuery: useSpoolmanVendors(), - allowMultipleFilters: false, })} {SpoolIconColumn({ id: "name", @@ -168,7 +167,6 @@ export const FilamentList: React.FC = () => { dataSource, tableState, filterValueQuery: useSpoolmanFilamentNames(), - allowMultipleFilters: false, })} {FilteredQueryColumn({ id: "material", @@ -176,7 +174,6 @@ export const FilamentList: React.FC = () => { dataSource, tableState, filterValueQuery: useSpoolmanMaterials(), - allowMultipleFilters: false, })} {SortedColumn({ id: "price", @@ -222,7 +219,6 @@ export const FilamentList: React.FC = () => { dataSource, tableState, filterValueQuery: useSpoolmanArticleNumbers(), - allowMultipleFilters: false, })} {NumberColumn({ id: "settings_extruder_temp", diff --git a/client/src/pages/spools/list.tsx b/client/src/pages/spools/list.tsx index 5b72bba..5fce1b9 100644 --- a/client/src/pages/spools/list.tsx +++ b/client/src/pages/spools/list.tsx @@ -18,7 +18,7 @@ import { import { setSpoolArchived } from "./functions"; import SelectAndPrint from "../../components/selectAndPrintDialog"; import { - useSpoolmanFilamentFullNames, + useSpoolmanFilamentFilter, useSpoolmanLocations, useSpoolmanLotNumbers, useSpoolmanMaterials, @@ -29,7 +29,8 @@ dayjs.extend(utc); const { confirm } = Modal; interface ISpoolCollapsed extends ISpool { - "filament.name": string; + combined_name: string; // Eg. "Prusa - PLA Red" + "filament.id": number; "filament.material"?: string; } @@ -71,7 +72,7 @@ export const SpoolList: React.FC = () => { // Create state for the columns to show const allColumns: (keyof ISpoolCollapsed & string)[] = [ "id", - "filament.name", + "combined_name", "filament.material", "used_weight", "remaining_weight", @@ -110,16 +111,14 @@ export const SpoolList: React.FC = () => { } return { ...element, - "filament.name": filament_name, + combined_name: filament_name, + "filament.id": element.filament.id, "filament.material": element.filament.material, }; }), [tableProps.dataSource] ); - // Filter and sort the dataSource - const filteredDataSource = dataSource; - // Function for opening an ant design modal that asks for confirmation for archiving a spool const archiveSpool = async (spool: ISpoolCollapsed, archive: boolean) => { await setSpoolArchived(spool, archive); @@ -182,7 +181,7 @@ export const SpoolList: React.FC = () => { menu={{ items: allColumns.map((column) => ({ key: column, - label: t(`spool.fields.${column}`), + label: t(`spool.fields.${column.replace(".", "_")}`), })), selectedKeys: showColumns, selectable: true, @@ -205,7 +204,7 @@ export const SpoolList: React.FC = () => { > { @@ -228,13 +227,13 @@ export const SpoolList: React.FC = () => { tableState, })} {SpoolIconColumn({ - id: "filament.name", + id: "combined_name", i18nkey: "spool.fields.filament_name", color: (record: ISpoolCollapsed) => record.filament.color_hex, dataSource, tableState, - filterValueQuery: useSpoolmanFilamentFullNames(), - allowMultipleFilters: false, + dataId: "filament.id", + filterValueQuery: useSpoolmanFilamentFilter(), })} {FilteredQueryColumn({ id: "filament.material", @@ -242,7 +241,6 @@ export const SpoolList: React.FC = () => { dataSource, tableState, filterValueQuery: useSpoolmanMaterials(), - allowMultipleFilters: false, })} {NumberColumn({ id: "used_weight", @@ -284,7 +282,6 @@ export const SpoolList: React.FC = () => { dataSource, tableState, filterValueQuery: useSpoolmanLocations(), - allowMultipleFilters: false, })} {FilteredQueryColumn({ id: "lot_nr", @@ -292,7 +289,6 @@ export const SpoolList: React.FC = () => { dataSource, tableState, filterValueQuery: useSpoolmanLotNumbers(), - allowMultipleFilters: false, })} {DateColumn({ id: "first_used",