Client Table update
* Columns are now specified using the ant design columns property instead of being Table.Column components. This should make this WoW a bit more sense, we're not pretending to be components anymore. column.tsx now only returns objects, not nodes. * Added filament/spool collapsing as a useTable queryOptions so that the output object is directly the one we want, which will make the types play better together. * Added a more unified record action system. This enables us to add actions to column rightclick/long press, which is better UX for mobile devices. * Actions column is now hidden on smaller screens thanks to the above bullet.
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
import React from "react";
|
||||
import { IResourceComponentsProps, BaseRecord, useTranslate, useInvalidate } from "@refinedev/core";
|
||||
import { useTable, List, EditButton, ShowButton, CloneButton } from "@refinedev/antd";
|
||||
import { Table, Space, Button, Dropdown } from "antd";
|
||||
import { IResourceComponentsProps, useTranslate, useInvalidate, useNavigation } from "@refinedev/core";
|
||||
import { useTable, List } from "@refinedev/antd";
|
||||
import { Table, Button, Dropdown } from "antd";
|
||||
import dayjs from "dayjs";
|
||||
import utc from "dayjs/plugin/utc";
|
||||
import { IFilament } from "./model";
|
||||
import { EditOutlined, FilterOutlined } from "@ant-design/icons";
|
||||
import { EditOutlined, EyeOutlined, FilterOutlined, PlusSquareOutlined } from "@ant-design/icons";
|
||||
import { TableState, useInitialTableState, useStoreInitialState } from "../../utils/saveload";
|
||||
import {
|
||||
DateColumn,
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
RichColumn,
|
||||
SortedColumn,
|
||||
SpoolIconColumn,
|
||||
ActionsColumn,
|
||||
} from "../../components/column";
|
||||
import {
|
||||
useSpoolmanArticleNumbers,
|
||||
@@ -22,6 +23,7 @@ import {
|
||||
useSpoolmanVendors,
|
||||
} from "../../components/otherModels";
|
||||
import { useLiveify } from "../../components/liveify";
|
||||
import { removeUndefined } from "../../utils/filtering";
|
||||
|
||||
dayjs.extend(utc);
|
||||
|
||||
@@ -46,6 +48,26 @@ function translateColumnI18nKey(columnName: string): string {
|
||||
|
||||
const namespace = "filamentList-v2";
|
||||
|
||||
const allColumns: (keyof IFilamentCollapsed & string)[] = [
|
||||
"id",
|
||||
"vendor.name",
|
||||
"name",
|
||||
"material",
|
||||
"price",
|
||||
"density",
|
||||
"diameter",
|
||||
"weight",
|
||||
"spool_weight",
|
||||
"article_number",
|
||||
"settings_extruder_temp",
|
||||
"settings_bed_temp",
|
||||
"registered",
|
||||
"comment",
|
||||
];
|
||||
const defaultColumns = allColumns.filter(
|
||||
(column_id) => ["registered", "density", "diameter", "spool_weight"].indexOf(column_id) === -1
|
||||
);
|
||||
|
||||
export const FilamentList: React.FC<IResourceComponentsProps> = () => {
|
||||
const t = useTranslate();
|
||||
const invalidate = useInvalidate();
|
||||
@@ -57,54 +79,43 @@ export const FilamentList: React.FC<IResourceComponentsProps> = () => {
|
||||
// To provide the live updates, we use a custom solution (useLiveify) instead of the built-in refine "liveMode" feature.
|
||||
// This is because the built-in feature does not call the liveProvider subscriber with a list of IDs, but instead
|
||||
// calls it with a list of filters, sorters, etc. This means the server-side has to support this, which is quite hard.
|
||||
const { tableProps, sorters, setSorters, filters, setFilters, current, pageSize, setCurrent } = useTable<IFilament>({
|
||||
syncWithLocation: false,
|
||||
pagination: {
|
||||
mode: "server",
|
||||
current: initialState.pagination.current,
|
||||
pageSize: initialState.pagination.pageSize,
|
||||
},
|
||||
sorters: {
|
||||
mode: "server",
|
||||
initial: initialState.sorters,
|
||||
},
|
||||
filters: {
|
||||
mode: "server",
|
||||
initial: initialState.filters,
|
||||
},
|
||||
liveMode: "manual",
|
||||
onLiveEvent(event) {
|
||||
if (event.type === "created" || event.type === "deleted") {
|
||||
// updated is handled by the liveify
|
||||
invalidate({
|
||||
resource: "filament",
|
||||
invalidates: ["list"],
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
const { tableProps, sorters, setSorters, filters, setFilters, current, pageSize, setCurrent } =
|
||||
useTable<IFilamentCollapsed>({
|
||||
syncWithLocation: false,
|
||||
pagination: {
|
||||
mode: "server",
|
||||
current: initialState.pagination.current,
|
||||
pageSize: initialState.pagination.pageSize,
|
||||
},
|
||||
sorters: {
|
||||
mode: "server",
|
||||
initial: initialState.sorters,
|
||||
},
|
||||
filters: {
|
||||
mode: "server",
|
||||
initial: initialState.filters,
|
||||
},
|
||||
liveMode: "manual",
|
||||
onLiveEvent(event) {
|
||||
if (event.type === "created" || event.type === "deleted") {
|
||||
// updated is handled by the liveify
|
||||
invalidate({
|
||||
resource: "filament",
|
||||
invalidates: ["list"],
|
||||
});
|
||||
}
|
||||
},
|
||||
queryOptions: {
|
||||
select(data) {
|
||||
return {
|
||||
total: data.total,
|
||||
data: data.data.map(collapseFilament),
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Create state for the columns to show
|
||||
const allColumns: (keyof IFilamentCollapsed & string)[] = [
|
||||
"id",
|
||||
"vendor.name",
|
||||
"name",
|
||||
"material",
|
||||
"price",
|
||||
"density",
|
||||
"diameter",
|
||||
"weight",
|
||||
"spool_weight",
|
||||
"article_number",
|
||||
"settings_extruder_temp",
|
||||
"settings_bed_temp",
|
||||
"registered",
|
||||
"comment",
|
||||
];
|
||||
const defaultColumns = allColumns.filter(
|
||||
(column_id) => ["registered", "density", "diameter", "spool_weight"].indexOf(column_id) === -1
|
||||
);
|
||||
|
||||
const [showColumns, setShowColumns] = React.useState<string[]>(initialState.showColumns ?? defaultColumns);
|
||||
|
||||
// Store state in local storage
|
||||
@@ -116,9 +127,9 @@ export const FilamentList: React.FC<IResourceComponentsProps> = () => {
|
||||
};
|
||||
useStoreInitialState(namespace, tableState);
|
||||
|
||||
// Collapse the dataSource to a mutable list and add a filament_name field
|
||||
// Collapse the dataSource to a mutable list
|
||||
const queryDataSource: IFilamentCollapsed[] = React.useMemo(
|
||||
() => (tableProps.dataSource ?? []).map(collapseFilament),
|
||||
() => (tableProps.dataSource || []).map((record) => ({ ...record })),
|
||||
[tableProps.dataSource]
|
||||
);
|
||||
const dataSource = useLiveify("filament", queryDataSource, collapseFilament);
|
||||
@@ -127,6 +138,13 @@ export const FilamentList: React.FC<IResourceComponentsProps> = () => {
|
||||
tableProps.pagination.showSizeChanger = true;
|
||||
}
|
||||
|
||||
const { editUrl, showUrl, cloneUrl } = useNavigation();
|
||||
const actions = (record: IFilamentCollapsed) => [
|
||||
{ name: t("buttons.edit"), icon: <EditOutlined />, link: editUrl("filament", record.id) },
|
||||
{ name: t("buttons.show"), icon: <EyeOutlined />, link: showUrl("filament", record.id) },
|
||||
{ name: t("buttons.clone"), icon: <PlusSquareOutlined />, link: cloneUrl("filament", record.id) },
|
||||
];
|
||||
|
||||
return (
|
||||
<List
|
||||
headerButtons={({ defaultButtons }) => (
|
||||
@@ -168,130 +186,142 @@ export const FilamentList: React.FC<IResourceComponentsProps> = () => {
|
||||
</>
|
||||
)}
|
||||
>
|
||||
<Table {...tableProps} sticky scroll={{ x: "max-content" }} dataSource={dataSource} rowKey="id">
|
||||
{SortedColumn({
|
||||
id: "id",
|
||||
i18ncat: "filament",
|
||||
dataSource,
|
||||
tableState,
|
||||
width: 70,
|
||||
})}
|
||||
{FilteredQueryColumn({
|
||||
id: "vendor.name",
|
||||
i18nkey: "filament.fields.vendor_name",
|
||||
dataSource,
|
||||
tableState,
|
||||
filterValueQuery: useSpoolmanVendors(),
|
||||
})}
|
||||
{SpoolIconColumn({
|
||||
id: "name",
|
||||
i18ncat: "filament",
|
||||
color: (record: IFilamentCollapsed) => record.color_hex,
|
||||
dataSource,
|
||||
tableState,
|
||||
filterValueQuery: useSpoolmanFilamentNames(),
|
||||
})}
|
||||
{FilteredQueryColumn({
|
||||
id: "material",
|
||||
i18ncat: "filament",
|
||||
dataSource,
|
||||
tableState,
|
||||
filterValueQuery: useSpoolmanMaterials(),
|
||||
width: 110,
|
||||
})}
|
||||
{SortedColumn({
|
||||
id: "price",
|
||||
i18ncat: "filament",
|
||||
dataSource,
|
||||
tableState,
|
||||
width: 80,
|
||||
})}
|
||||
{NumberColumn({
|
||||
id: "density",
|
||||
i18ncat: "filament",
|
||||
unit: "g/cm³",
|
||||
decimals: 2,
|
||||
dataSource,
|
||||
tableState,
|
||||
width: 100,
|
||||
})}
|
||||
{NumberColumn({
|
||||
id: "diameter",
|
||||
i18ncat: "filament",
|
||||
unit: "mm",
|
||||
decimals: 2,
|
||||
dataSource,
|
||||
tableState,
|
||||
width: 100,
|
||||
})}
|
||||
{NumberColumn({
|
||||
id: "weight",
|
||||
i18ncat: "filament",
|
||||
unit: "g",
|
||||
decimals: 1,
|
||||
dataSource,
|
||||
tableState,
|
||||
width: 100,
|
||||
})}
|
||||
{NumberColumn({
|
||||
id: "spool_weight",
|
||||
i18ncat: "filament",
|
||||
unit: "g",
|
||||
decimals: 1,
|
||||
dataSource,
|
||||
tableState,
|
||||
width: 100,
|
||||
})}
|
||||
{FilteredQueryColumn({
|
||||
id: "article_number",
|
||||
i18ncat: "filament",
|
||||
dataSource,
|
||||
tableState,
|
||||
filterValueQuery: useSpoolmanArticleNumbers(),
|
||||
width: 130,
|
||||
})}
|
||||
{NumberColumn({
|
||||
id: "settings_extruder_temp",
|
||||
i18ncat: "filament",
|
||||
unit: "°C",
|
||||
decimals: 0,
|
||||
dataSource,
|
||||
tableState,
|
||||
width: 100,
|
||||
})}
|
||||
{NumberColumn({
|
||||
id: "settings_bed_temp",
|
||||
i18ncat: "filament",
|
||||
unit: "°C",
|
||||
decimals: 0,
|
||||
dataSource,
|
||||
tableState,
|
||||
width: 100,
|
||||
})}
|
||||
{DateColumn({
|
||||
id: "registered",
|
||||
i18ncat: "filament",
|
||||
dataSource,
|
||||
tableState,
|
||||
})}
|
||||
{RichColumn({
|
||||
id: "comment",
|
||||
i18ncat: "filament",
|
||||
dataSource,
|
||||
tableState,
|
||||
width: 150,
|
||||
})}
|
||||
<Table.Column
|
||||
title={t("table.actions")}
|
||||
render={(_, record: BaseRecord) => (
|
||||
<Space>
|
||||
<EditButton hideText title={t("buttons.edit")} size="small" recordItemId={record.id} />
|
||||
<ShowButton hideText title={t("buttons.show")} size="small" recordItemId={record.id} />
|
||||
<CloneButton hideText title={t("buttons.clone")} size="small" recordItemId={record.id} />
|
||||
</Space>
|
||||
)}
|
||||
/>
|
||||
</Table>
|
||||
<Table<IFilamentCollapsed>
|
||||
{...tableProps}
|
||||
sticky
|
||||
scroll={{ x: "max-content" }}
|
||||
dataSource={dataSource}
|
||||
rowKey="id"
|
||||
columns={removeUndefined([
|
||||
SortedColumn({
|
||||
id: "id",
|
||||
i18ncat: "filament",
|
||||
actions,
|
||||
dataSource,
|
||||
tableState,
|
||||
width: 70,
|
||||
}),
|
||||
FilteredQueryColumn({
|
||||
id: "vendor.name",
|
||||
i18nkey: "filament.fields.vendor_name",
|
||||
actions,
|
||||
dataSource,
|
||||
tableState,
|
||||
filterValueQuery: useSpoolmanVendors(),
|
||||
}),
|
||||
SpoolIconColumn({
|
||||
id: "name",
|
||||
i18ncat: "filament",
|
||||
color: (record: IFilamentCollapsed) => record.color_hex,
|
||||
actions,
|
||||
dataSource,
|
||||
tableState,
|
||||
filterValueQuery: useSpoolmanFilamentNames(),
|
||||
}),
|
||||
FilteredQueryColumn({
|
||||
id: "material",
|
||||
i18ncat: "filament",
|
||||
actions,
|
||||
dataSource,
|
||||
tableState,
|
||||
filterValueQuery: useSpoolmanMaterials(),
|
||||
width: 110,
|
||||
}),
|
||||
SortedColumn({
|
||||
id: "price",
|
||||
i18ncat: "filament",
|
||||
actions,
|
||||
dataSource,
|
||||
tableState,
|
||||
width: 80,
|
||||
}),
|
||||
NumberColumn({
|
||||
id: "density",
|
||||
i18ncat: "filament",
|
||||
unit: "g/cm³",
|
||||
decimals: 2,
|
||||
actions,
|
||||
dataSource,
|
||||
tableState,
|
||||
width: 100,
|
||||
}),
|
||||
NumberColumn({
|
||||
id: "diameter",
|
||||
i18ncat: "filament",
|
||||
unit: "mm",
|
||||
decimals: 2,
|
||||
actions,
|
||||
dataSource,
|
||||
tableState,
|
||||
width: 100,
|
||||
}),
|
||||
NumberColumn({
|
||||
id: "weight",
|
||||
i18ncat: "filament",
|
||||
unit: "g",
|
||||
decimals: 1,
|
||||
actions,
|
||||
dataSource,
|
||||
tableState,
|
||||
width: 100,
|
||||
}),
|
||||
NumberColumn({
|
||||
id: "spool_weight",
|
||||
i18ncat: "filament",
|
||||
unit: "g",
|
||||
decimals: 1,
|
||||
actions,
|
||||
dataSource,
|
||||
tableState,
|
||||
width: 100,
|
||||
}),
|
||||
FilteredQueryColumn({
|
||||
id: "article_number",
|
||||
i18ncat: "filament",
|
||||
actions,
|
||||
dataSource,
|
||||
tableState,
|
||||
filterValueQuery: useSpoolmanArticleNumbers(),
|
||||
width: 130,
|
||||
}),
|
||||
NumberColumn({
|
||||
id: "settings_extruder_temp",
|
||||
i18ncat: "filament",
|
||||
unit: "°C",
|
||||
decimals: 0,
|
||||
actions,
|
||||
dataSource,
|
||||
tableState,
|
||||
width: 100,
|
||||
}),
|
||||
NumberColumn({
|
||||
id: "settings_bed_temp",
|
||||
i18ncat: "filament",
|
||||
unit: "°C",
|
||||
decimals: 0,
|
||||
actions,
|
||||
dataSource,
|
||||
tableState,
|
||||
width: 100,
|
||||
}),
|
||||
DateColumn({
|
||||
id: "registered",
|
||||
i18ncat: "filament",
|
||||
actions,
|
||||
dataSource,
|
||||
tableState,
|
||||
}),
|
||||
RichColumn({
|
||||
id: "comment",
|
||||
i18ncat: "filament",
|
||||
actions,
|
||||
dataSource,
|
||||
tableState,
|
||||
width: 150,
|
||||
}),
|
||||
ActionsColumn(actions),
|
||||
])}
|
||||
/>
|
||||
</List>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
import React from "react";
|
||||
import { IResourceComponentsProps, useInvalidate, useTranslate } from "@refinedev/core";
|
||||
import { useTable, List, EditButton, ShowButton, CloneButton } from "@refinedev/antd";
|
||||
import { Table, Space, Button, Dropdown, Modal } from "antd";
|
||||
import { IResourceComponentsProps, useInvalidate, useNavigation, useTranslate } from "@refinedev/core";
|
||||
import { useTable, List } from "@refinedev/antd";
|
||||
import { Table, Button, Dropdown, Modal } from "antd";
|
||||
import dayjs from "dayjs";
|
||||
import utc from "dayjs/plugin/utc";
|
||||
import { ISpool } from "./model";
|
||||
import { TableState, useInitialTableState, useSavedState, useStoreInitialState } from "../../utils/saveload";
|
||||
import { EditOutlined, FilterOutlined, InboxOutlined, ToTopOutlined } from "@ant-design/icons";
|
||||
import {
|
||||
EditOutlined,
|
||||
EyeOutlined,
|
||||
FilterOutlined,
|
||||
InboxOutlined,
|
||||
PlusSquareOutlined,
|
||||
ToTopOutlined,
|
||||
} from "@ant-design/icons";
|
||||
import {
|
||||
DateColumn,
|
||||
FilteredQueryColumn,
|
||||
@@ -14,6 +21,8 @@ import {
|
||||
RichColumn,
|
||||
SortedColumn,
|
||||
SpoolIconColumn,
|
||||
Action,
|
||||
ActionsColumn,
|
||||
} from "../../components/column";
|
||||
import { setSpoolArchived } from "./functions";
|
||||
import SelectAndPrint from "../../components/selectAndPrintDialog";
|
||||
@@ -24,6 +33,7 @@ import {
|
||||
useSpoolmanMaterials,
|
||||
} from "../../components/otherModels";
|
||||
import { useLiveify } from "../../components/liveify";
|
||||
import { removeUndefined } from "../../utils/filtering";
|
||||
|
||||
dayjs.extend(utc);
|
||||
|
||||
@@ -59,6 +69,25 @@ function translateColumnI18nKey(columnName: string): string {
|
||||
|
||||
const namespace = "spoolList-v2";
|
||||
|
||||
const allColumns: (keyof ISpoolCollapsed & string)[] = [
|
||||
"id",
|
||||
"combined_name",
|
||||
"filament.material",
|
||||
"used_weight",
|
||||
"remaining_weight",
|
||||
"used_length",
|
||||
"remaining_length",
|
||||
"location",
|
||||
"lot_nr",
|
||||
"first_used",
|
||||
"last_used",
|
||||
"registered",
|
||||
"comment",
|
||||
];
|
||||
const defaultColumns = allColumns.filter(
|
||||
(column_id) => ["registered", "used_length", "remaining_length", "lot_nr"].indexOf(column_id) === -1
|
||||
);
|
||||
|
||||
export const SpoolList: React.FC<IResourceComponentsProps> = () => {
|
||||
const t = useTranslate();
|
||||
const invalidate = useInvalidate();
|
||||
@@ -73,57 +102,48 @@ export const SpoolList: React.FC<IResourceComponentsProps> = () => {
|
||||
// To provide the live updates, we use a custom solution (useLiveify) instead of the built-in refine "liveMode" feature.
|
||||
// This is because the built-in feature does not call the liveProvider subscriber with a list of IDs, but instead
|
||||
// calls it with a list of filters, sorters, etc. This means the server-side has to support this, which is quite hard.
|
||||
const { tableProps, sorters, setSorters, filters, setFilters, current, pageSize, setCurrent } = useTable<ISpool>({
|
||||
meta: {
|
||||
queryParams: {
|
||||
["allow_archived"]: showArchived,
|
||||
const { tableProps, sorters, setSorters, filters, setFilters, current, pageSize, setCurrent } =
|
||||
useTable<ISpoolCollapsed>({
|
||||
meta: {
|
||||
queryParams: {
|
||||
["allow_archived"]: showArchived,
|
||||
},
|
||||
},
|
||||
},
|
||||
syncWithLocation: false,
|
||||
pagination: {
|
||||
mode: "server",
|
||||
current: initialState.pagination.current,
|
||||
pageSize: initialState.pagination.pageSize,
|
||||
},
|
||||
sorters: {
|
||||
mode: "server",
|
||||
initial: initialState.sorters,
|
||||
},
|
||||
filters: {
|
||||
mode: "server",
|
||||
initial: initialState.filters,
|
||||
},
|
||||
liveMode: "manual",
|
||||
onLiveEvent(event) {
|
||||
if (event.type === "created" || event.type === "deleted") {
|
||||
// updated is handled by the liveify
|
||||
invalidate({
|
||||
resource: "spool",
|
||||
invalidates: ["list"],
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
syncWithLocation: false,
|
||||
pagination: {
|
||||
mode: "server",
|
||||
current: initialState.pagination.current,
|
||||
pageSize: initialState.pagination.pageSize,
|
||||
},
|
||||
sorters: {
|
||||
mode: "server",
|
||||
initial: initialState.sorters,
|
||||
},
|
||||
filters: {
|
||||
mode: "server",
|
||||
initial: initialState.filters,
|
||||
},
|
||||
liveMode: "manual",
|
||||
onLiveEvent(event) {
|
||||
if (event.type === "created" || event.type === "deleted") {
|
||||
// updated is handled by the liveify
|
||||
invalidate({
|
||||
resource: "spool",
|
||||
invalidates: ["list"],
|
||||
});
|
||||
}
|
||||
},
|
||||
queryOptions: {
|
||||
select(data) {
|
||||
return {
|
||||
total: data.total,
|
||||
data: data.data.map(collapseSpool),
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Create state for the columns to show
|
||||
const allColumns: (keyof ISpoolCollapsed & string)[] = [
|
||||
"id",
|
||||
"combined_name",
|
||||
"filament.material",
|
||||
"used_weight",
|
||||
"remaining_weight",
|
||||
"used_length",
|
||||
"remaining_length",
|
||||
"location",
|
||||
"lot_nr",
|
||||
"first_used",
|
||||
"last_used",
|
||||
"registered",
|
||||
"comment",
|
||||
];
|
||||
const defaultColumns = allColumns.filter(
|
||||
(column_id) => ["registered", "used_length", "remaining_length", "lot_nr"].indexOf(column_id) === -1
|
||||
);
|
||||
const [showColumns, setShowColumns] = React.useState<string[]>(initialState.showColumns ?? defaultColumns);
|
||||
|
||||
// Store state in local storage
|
||||
@@ -135,9 +155,9 @@ export const SpoolList: React.FC<IResourceComponentsProps> = () => {
|
||||
};
|
||||
useStoreInitialState(namespace, tableState);
|
||||
|
||||
// Collapse the dataSource to a mutable list and add a filament_name field
|
||||
const queryDataSource = React.useMemo(
|
||||
() => (tableProps.dataSource ?? []).map(collapseSpool),
|
||||
// Collapse the dataSource to a mutable list
|
||||
const queryDataSource: ISpoolCollapsed[] = React.useMemo(
|
||||
() => (tableProps.dataSource || []).map((record) => ({ ...record })),
|
||||
[tableProps.dataSource]
|
||||
);
|
||||
const dataSource = useLiveify("spool", queryDataSource, collapseSpool);
|
||||
@@ -174,6 +194,25 @@ export const SpoolList: React.FC<IResourceComponentsProps> = () => {
|
||||
tableProps.pagination.showSizeChanger = true;
|
||||
}
|
||||
|
||||
const { editUrl, showUrl, cloneUrl } = useNavigation();
|
||||
const actions = (record: ISpoolCollapsed) => {
|
||||
const actions: Action[] = [
|
||||
{ name: t("buttons.edit"), icon: <EditOutlined />, link: editUrl("spool", record.id) },
|
||||
{ name: t("buttons.show"), icon: <EyeOutlined />, link: showUrl("spool", record.id) },
|
||||
{ name: t("buttons.clone"), icon: <PlusSquareOutlined />, link: cloneUrl("spool", record.id) },
|
||||
];
|
||||
if (record.archived) {
|
||||
actions.push({
|
||||
name: t("buttons.unArchive"),
|
||||
icon: <ToTopOutlined />,
|
||||
onClick: () => archiveSpool(record, false),
|
||||
});
|
||||
} else {
|
||||
actions.push({ name: t("buttons.archive"), icon: <InboxOutlined />, onClick: () => archiveSpoolPopup(record) });
|
||||
}
|
||||
return actions;
|
||||
};
|
||||
|
||||
return (
|
||||
<List
|
||||
headerButtons={({ defaultButtons }) => (
|
||||
@@ -244,136 +283,126 @@ export const SpoolList: React.FC<IResourceComponentsProps> = () => {
|
||||
return {};
|
||||
}
|
||||
}}
|
||||
>
|
||||
{SortedColumn({
|
||||
id: "id",
|
||||
i18ncat: "spool",
|
||||
dataSource,
|
||||
tableState,
|
||||
width: 70,
|
||||
})}
|
||||
{SpoolIconColumn({
|
||||
id: "combined_name",
|
||||
i18nkey: "spool.fields.filament_name",
|
||||
color: (record: ISpoolCollapsed) => record.filament.color_hex,
|
||||
dataSource,
|
||||
tableState,
|
||||
dataId: "filament.id",
|
||||
filterValueQuery: useSpoolmanFilamentFilter(),
|
||||
})}
|
||||
{FilteredQueryColumn({
|
||||
id: "filament.material",
|
||||
i18nkey: "spool.fields.material",
|
||||
dataSource,
|
||||
tableState,
|
||||
filterValueQuery: useSpoolmanMaterials(),
|
||||
width: 120,
|
||||
})}
|
||||
{NumberColumn({
|
||||
id: "used_weight",
|
||||
i18ncat: "spool",
|
||||
unit: "g",
|
||||
decimals: 1,
|
||||
dataSource,
|
||||
tableState,
|
||||
width: 110,
|
||||
})}
|
||||
{NumberColumn({
|
||||
id: "remaining_weight",
|
||||
i18ncat: "spool",
|
||||
unit: "g",
|
||||
decimals: 1,
|
||||
defaultText: t("unknown"),
|
||||
dataSource,
|
||||
tableState,
|
||||
width: 110,
|
||||
})}
|
||||
{NumberColumn({
|
||||
id: "used_length",
|
||||
i18ncat: "spool",
|
||||
unit: "mm",
|
||||
decimals: 1,
|
||||
dataSource,
|
||||
tableState,
|
||||
width: 120,
|
||||
})}
|
||||
{NumberColumn({
|
||||
id: "remaining_length",
|
||||
i18ncat: "spool",
|
||||
unit: "mm",
|
||||
decimals: 1,
|
||||
defaultText: t("unknown"),
|
||||
dataSource,
|
||||
tableState,
|
||||
width: 120,
|
||||
})}
|
||||
{FilteredQueryColumn({
|
||||
id: "location",
|
||||
i18ncat: "spool",
|
||||
dataSource,
|
||||
tableState,
|
||||
filterValueQuery: useSpoolmanLocations(),
|
||||
width: 120,
|
||||
})}
|
||||
{FilteredQueryColumn({
|
||||
id: "lot_nr",
|
||||
i18ncat: "spool",
|
||||
dataSource,
|
||||
tableState,
|
||||
filterValueQuery: useSpoolmanLotNumbers(),
|
||||
width: 120,
|
||||
})}
|
||||
{DateColumn({
|
||||
id: "first_used",
|
||||
i18ncat: "spool",
|
||||
dataSource,
|
||||
tableState,
|
||||
})}
|
||||
{DateColumn({
|
||||
id: "last_used",
|
||||
i18ncat: "spool",
|
||||
dataSource,
|
||||
tableState,
|
||||
})}
|
||||
{DateColumn({
|
||||
id: "registered",
|
||||
i18ncat: "spool",
|
||||
dataSource,
|
||||
tableState,
|
||||
})}
|
||||
{RichColumn({
|
||||
id: "comment",
|
||||
i18ncat: "spool",
|
||||
dataSource,
|
||||
tableState,
|
||||
width: 150,
|
||||
})}
|
||||
<Table.Column
|
||||
title={t("table.actions")}
|
||||
render={(_, record: ISpoolCollapsed) => (
|
||||
<Space>
|
||||
<EditButton hideText title={t("buttons.edit")} size="small" recordItemId={record.id} />
|
||||
<ShowButton hideText title={t("buttons.show")} size="small" recordItemId={record.id} />
|
||||
<CloneButton hideText title={t("buttons.clone")} size="small" recordItemId={record.id} />
|
||||
{record.archived ? (
|
||||
<Button
|
||||
icon={<ToTopOutlined />}
|
||||
title={t("buttons.unArchive")}
|
||||
size="small"
|
||||
onClick={() => archiveSpool(record, false)}
|
||||
/>
|
||||
) : (
|
||||
<Button
|
||||
icon={<InboxOutlined />}
|
||||
title={t("buttons.archive")}
|
||||
size="small"
|
||||
onClick={() => archiveSpoolPopup(record)}
|
||||
/>
|
||||
)}
|
||||
</Space>
|
||||
)}
|
||||
/>
|
||||
</Table>
|
||||
columns={removeUndefined([
|
||||
SortedColumn({
|
||||
id: "id",
|
||||
i18ncat: "spool",
|
||||
actions,
|
||||
dataSource,
|
||||
tableState,
|
||||
width: 70,
|
||||
}),
|
||||
SpoolIconColumn({
|
||||
id: "combined_name",
|
||||
i18nkey: "spool.fields.filament_name",
|
||||
color: (record: ISpoolCollapsed) => record.filament.color_hex,
|
||||
actions,
|
||||
dataSource,
|
||||
tableState,
|
||||
dataId: "filament.id",
|
||||
filterValueQuery: useSpoolmanFilamentFilter(),
|
||||
}),
|
||||
FilteredQueryColumn({
|
||||
id: "filament.material",
|
||||
i18nkey: "spool.fields.material",
|
||||
actions,
|
||||
dataSource,
|
||||
tableState,
|
||||
filterValueQuery: useSpoolmanMaterials(),
|
||||
width: 120,
|
||||
}),
|
||||
NumberColumn({
|
||||
id: "used_weight",
|
||||
i18ncat: "spool",
|
||||
unit: "g",
|
||||
decimals: 1,
|
||||
actions,
|
||||
dataSource,
|
||||
tableState,
|
||||
width: 110,
|
||||
}),
|
||||
NumberColumn({
|
||||
id: "remaining_weight",
|
||||
i18ncat: "spool",
|
||||
unit: "g",
|
||||
decimals: 1,
|
||||
defaultText: t("unknown"),
|
||||
actions,
|
||||
dataSource,
|
||||
tableState,
|
||||
width: 110,
|
||||
}),
|
||||
NumberColumn({
|
||||
id: "used_length",
|
||||
i18ncat: "spool",
|
||||
unit: "mm",
|
||||
decimals: 1,
|
||||
actions,
|
||||
dataSource,
|
||||
tableState,
|
||||
width: 120,
|
||||
}),
|
||||
NumberColumn({
|
||||
id: "remaining_length",
|
||||
i18ncat: "spool",
|
||||
unit: "mm",
|
||||
decimals: 1,
|
||||
defaultText: t("unknown"),
|
||||
actions,
|
||||
dataSource,
|
||||
tableState,
|
||||
width: 120,
|
||||
}),
|
||||
FilteredQueryColumn({
|
||||
id: "location",
|
||||
i18ncat: "spool",
|
||||
actions,
|
||||
dataSource,
|
||||
tableState,
|
||||
filterValueQuery: useSpoolmanLocations(),
|
||||
width: 120,
|
||||
}),
|
||||
FilteredQueryColumn({
|
||||
id: "lot_nr",
|
||||
i18ncat: "spool",
|
||||
actions,
|
||||
dataSource,
|
||||
tableState,
|
||||
filterValueQuery: useSpoolmanLotNumbers(),
|
||||
width: 120,
|
||||
}),
|
||||
DateColumn({
|
||||
id: "first_used",
|
||||
i18ncat: "spool",
|
||||
actions,
|
||||
dataSource,
|
||||
tableState,
|
||||
}),
|
||||
DateColumn({
|
||||
id: "last_used",
|
||||
i18ncat: "spool",
|
||||
actions,
|
||||
dataSource,
|
||||
tableState,
|
||||
}),
|
||||
DateColumn({
|
||||
id: "registered",
|
||||
i18ncat: "spool",
|
||||
actions,
|
||||
dataSource,
|
||||
tableState,
|
||||
}),
|
||||
RichColumn({
|
||||
id: "comment",
|
||||
i18ncat: "spool",
|
||||
actions,
|
||||
dataSource,
|
||||
tableState,
|
||||
width: 150,
|
||||
}),
|
||||
ActionsColumn(actions),
|
||||
])}
|
||||
/>
|
||||
</List>
|
||||
);
|
||||
};
|
||||
|
||||
97
client/src/pages/vendors/list.tsx
vendored
97
client/src/pages/vendors/list.tsx
vendored
@@ -1,19 +1,22 @@
|
||||
import React from "react";
|
||||
import { IResourceComponentsProps, BaseRecord, useTranslate, useInvalidate } from "@refinedev/core";
|
||||
import { useTable, List, EditButton, ShowButton, CloneButton } from "@refinedev/antd";
|
||||
import { Table, Space, Button, Dropdown } from "antd";
|
||||
import { IResourceComponentsProps, useTranslate, useInvalidate, useNavigation } from "@refinedev/core";
|
||||
import { useTable, List } from "@refinedev/antd";
|
||||
import { Table, Button, Dropdown } from "antd";
|
||||
import dayjs from "dayjs";
|
||||
import utc from "dayjs/plugin/utc";
|
||||
import { IVendor } from "./model";
|
||||
import { TableState, useInitialTableState, useStoreInitialState } from "../../utils/saveload";
|
||||
import { EditOutlined, FilterOutlined } from "@ant-design/icons";
|
||||
import { DateColumn, RichColumn, SortedColumn } from "../../components/column";
|
||||
import { EditOutlined, EyeOutlined, FilterOutlined, PlusSquareOutlined } from "@ant-design/icons";
|
||||
import { DateColumn, RichColumn, SortedColumn, ActionsColumn } from "../../components/column";
|
||||
import { useLiveify } from "../../components/liveify";
|
||||
import { removeUndefined } from "../../utils/filtering";
|
||||
|
||||
dayjs.extend(utc);
|
||||
|
||||
const namespace = "vendorList-v2";
|
||||
|
||||
const allColumns: (keyof IVendor & string)[] = ["id", "name", "registered", "comment"];
|
||||
|
||||
export const VendorList: React.FC<IResourceComponentsProps> = () => {
|
||||
const t = useTranslate();
|
||||
const invalidate = useInvalidate();
|
||||
@@ -50,7 +53,6 @@ export const VendorList: React.FC<IResourceComponentsProps> = () => {
|
||||
});
|
||||
|
||||
// Create state for the columns to show
|
||||
const allColumns: (keyof IVendor & string)[] = ["id", "name", "registered", "comment"];
|
||||
const [showColumns, setShowColumns] = React.useState<string[]>(initialState.showColumns ?? allColumns);
|
||||
|
||||
// Store state in local storage
|
||||
@@ -73,6 +75,13 @@ export const VendorList: React.FC<IResourceComponentsProps> = () => {
|
||||
tableProps.pagination.showSizeChanger = true;
|
||||
}
|
||||
|
||||
const { editUrl, showUrl, cloneUrl } = useNavigation();
|
||||
const actions = (record: IVendor) => [
|
||||
{ name: t("buttons.edit"), icon: <EditOutlined />, link: editUrl("vendor", record.id) },
|
||||
{ name: t("buttons.show"), icon: <EyeOutlined />, link: showUrl("vendor", record.id) },
|
||||
{ name: t("buttons.clone"), icon: <PlusSquareOutlined />, link: cloneUrl("vendor", record.id) },
|
||||
];
|
||||
|
||||
return (
|
||||
<List
|
||||
headerButtons={({ defaultButtons }) => (
|
||||
@@ -114,43 +123,45 @@ export const VendorList: React.FC<IResourceComponentsProps> = () => {
|
||||
</>
|
||||
)}
|
||||
>
|
||||
<Table {...tableProps} sticky scroll={{ x: "max-content" }} dataSource={dataSource} rowKey="id">
|
||||
{SortedColumn({
|
||||
id: "id",
|
||||
i18ncat: "vendor",
|
||||
dataSource,
|
||||
tableState,
|
||||
width: 70,
|
||||
})}
|
||||
{SortedColumn({
|
||||
id: "name",
|
||||
i18ncat: "vendor",
|
||||
dataSource,
|
||||
tableState,
|
||||
})}
|
||||
{DateColumn({
|
||||
id: "registered",
|
||||
i18ncat: "vendor",
|
||||
dataSource,
|
||||
tableState,
|
||||
})}
|
||||
{RichColumn({
|
||||
id: "comment",
|
||||
i18ncat: "vendor",
|
||||
dataSource,
|
||||
tableState,
|
||||
})}
|
||||
<Table.Column
|
||||
title={t("table.actions")}
|
||||
render={(_, record: BaseRecord) => (
|
||||
<Space>
|
||||
<EditButton hideText title={t("buttons.edit")} size="small" recordItemId={record.id} />
|
||||
<ShowButton hideText title={t("buttons.show")} size="small" recordItemId={record.id} />
|
||||
<CloneButton hideText title={t("buttons.clone")} size="small" recordItemId={record.id} />
|
||||
</Space>
|
||||
)}
|
||||
/>
|
||||
</Table>
|
||||
<Table
|
||||
{...tableProps}
|
||||
sticky
|
||||
scroll={{ x: "max-content" }}
|
||||
dataSource={dataSource}
|
||||
rowKey="id"
|
||||
columns={removeUndefined([
|
||||
SortedColumn({
|
||||
id: "id",
|
||||
i18ncat: "vendor",
|
||||
actions,
|
||||
dataSource,
|
||||
tableState,
|
||||
width: 70,
|
||||
}),
|
||||
SortedColumn({
|
||||
id: "name",
|
||||
i18ncat: "vendor",
|
||||
actions,
|
||||
dataSource,
|
||||
tableState,
|
||||
}),
|
||||
DateColumn({
|
||||
id: "registered",
|
||||
i18ncat: "vendor",
|
||||
actions,
|
||||
dataSource,
|
||||
tableState,
|
||||
}),
|
||||
RichColumn({
|
||||
id: "comment",
|
||||
i18ncat: "vendor",
|
||||
actions,
|
||||
dataSource,
|
||||
tableState,
|
||||
}),
|
||||
ActionsColumn<IVendor>(actions),
|
||||
])}
|
||||
/>
|
||||
</List>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user