feat(dashboard,types): Translate all OrderBy filters (#9691)

Resolves CC-616

**Note**
- I have added some missing fields to a couple of types, to resolve TS errors in the dashboard.
- For the ApiKey types I have left the created_at, updated_at, etc. as type Date, as changing them to string, caused @medusajs/medusa to fail building. We need to clean up the types at a later time.
This commit is contained in:
Kasper Fabricius Kristensen
2024-10-21 18:09:55 +00:00
committed by GitHub
parent e81dbc754c
commit 9f53683508
66 changed files with 474 additions and 188 deletions
@@ -4,8 +4,13 @@ import { useState } from "react"
import { useTranslation } from "react-i18next"
import { useSearchParams } from "react-router-dom"
export type DataTableOrderByKey<TData> = {
key: keyof TData
label: string
}
type DataTableOrderByProps<TData> = {
keys: (keyof TData)[]
keys: DataTableOrderByKey<TData>[]
prefix?: string
}
@@ -38,18 +43,6 @@ const initState = (params: URLSearchParams, prefix?: string): SortState => {
}
}
const formatKey = (key: string) => {
const words = key.split("_")
const formattedWords = words.map((word, index) => {
if (index === 0) {
return word.charAt(0).toUpperCase() + word.slice(1)
} else {
return word
}
})
return formattedWords.join(" ")
}
export const DataTableOrderBy = <TData,>({
keys,
prefix,
@@ -116,7 +109,7 @@ export const DataTableOrderBy = <TData,>({
onValueChange={handleKeyChange}
>
{keys.map((key) => {
const stringKey = String(key)
const stringKey = String(key.key)
return (
<DropdownMenu.RadioItem
@@ -124,7 +117,7 @@ export const DataTableOrderBy = <TData,>({
value={stringKey}
onSelect={(event) => event.preventDefault()}
>
{formatKey(stringKey)}
{key.label}
</DropdownMenu.RadioItem>
)
})}
@@ -1,21 +1,21 @@
import { Filter } from ".."
import { DataTableFilter } from "../data-table-filter"
import { DataTableOrderBy } from "../data-table-order-by"
import { DataTableOrderBy, DataTableOrderByKey } from "../data-table-order-by"
import { DataTableSearch } from "../data-table-search"
export interface DataTableQueryProps {
export interface DataTableQueryProps<TData> {
search?: boolean | "autofocus"
orderBy?: (string | number)[]
orderBy?: DataTableOrderByKey<TData>[]
filters?: Filter[]
prefix?: string
}
export const DataTableQuery = ({
export const DataTableQuery = <TData,>({
search,
orderBy,
filters,
prefix,
}: DataTableQueryProps) => {
}: DataTableQueryProps<TData>) => {
return (
(search || orderBy || filters || prefix) && (
<div className="flex items-start justify-between gap-x-4 px-6 py-4">
@@ -7,7 +7,7 @@ import { DataTableRoot, DataTableRootProps } from "./data-table-root"
interface DataTableProps<TData>
extends Omit<DataTableRootProps<TData>, "noResults">,
DataTableQueryProps {
DataTableQueryProps<TData> {
isLoading?: boolean
pageSize: number
queryObject?: Record<string, any>
@@ -16,7 +16,7 @@ interface DataTableProps<TData>
// Maybe we should use the memoized version of DataTableRoot
// const MemoizedDataTableRoot = memo(DataTableRoot) as typeof DataTableRoot
const MemoizedDataTableQuery = memo(DataTableQuery)
const MemoizedDataTableQuery = memo(DataTableQuery) as typeof DataTableQuery
export const DataTable = <TData,>({
table,
@@ -1,4 +1,4 @@
import { PromotionDTO } from "@medusajs/types"
import { HttpTypes } from "@medusajs/types"
import { useTranslation } from "react-i18next"
import {
getPromotionStatus,
@@ -7,7 +7,7 @@ import {
import { StatusCell as StatusCell_ } from "../../common/status-cell"
type PromotionCellProps = {
promotion: PromotionDTO
promotion: HttpTypes.AdminPromotion
}
type StatusColors = "grey" | "orange" | "green" | "red"
type StatusMap = Record<string, [StatusColors, string]>
@@ -1,5 +1,5 @@
import { PromotionDTO } from "@medusajs/types"
import { ColumnDef, createColumnHelper } from "@tanstack/react-table"
import { HttpTypes } from "@medusajs/types"
import { createColumnHelper } from "@tanstack/react-table"
import { useMemo } from "react"
import { useTranslation } from "react-i18next"
@@ -13,7 +13,7 @@ import {
} from "../../../components/table/table-cells/common/text-cell"
import { StatusCell } from "../../../components/table/table-cells/promotion/status-cell"
const columnHelper = createColumnHelper<PromotionDTO>()
const columnHelper = createColumnHelper<HttpTypes.AdminPromotion>()
export const usePromotionTableColumns = () => {
const { t } = useTranslation()
@@ -44,6 +44,6 @@ export const usePromotionTableColumns = () => {
cell: ({ row }) => <StatusCell promotion={row.original} />,
}),
],
[]
) as ColumnDef<PromotionDTO>[]
[t]
)
}
@@ -847,7 +847,8 @@
"groups": "Groups"
},
"registered": "Registered",
"guest": "Guest"
"guest": "Guest",
"hasAccount": "Has account"
},
"customerGroups": {
"domain": "Customer Groups",
@@ -1268,6 +1269,11 @@
"confirmed": "Order edit #{{editId}} confirmed"
}
}
},
"fields": {
"displayId": "Display ID",
"refundableAmount": "Refundable amount",
"returnableQuantity": "Returnable quantity"
}
},
"draftOrders": {
@@ -117,7 +117,20 @@ export const ApiKeySalesChannelSection = ({
isLoading={isLoading}
queryObject={raw}
navigateTo={(row) => `/settings/sales-channels/${row.id}`}
orderBy={["name", "created_at", "updated_at"]}
orderBy={[
{
key: "name",
label: t("fields.name"),
},
{
key: "created_at",
label: t("fields.createdAt"),
},
{
key: "updated_at",
label: t("fields.updatedAt"),
},
]}
commands={[
{
action: handleRemove,
@@ -76,7 +76,12 @@ export const ApiKeyManagementListTable = ({
columns={columns}
count={count}
pageSize={PAGE_SIZE}
orderBy={["title", "created_at", "updated_at", "revoked_at"]}
orderBy={[
{ key: "title", label: t("fields.title") },
{ key: "created_at", label: t("fields.createdAt") },
{ key: "updated_at", label: t("fields.updatedAt") },
{ key: "revoked_at", label: t("fields.revokedAt") },
]}
navigateTo={(row) => row.id}
pagination
search
@@ -149,7 +149,11 @@ export const ApiKeySalesChannelsForm = ({
search="autofocus"
isLoading={isLoading}
queryObject={raw}
orderBy={["name", "created_at", "updated_at"]}
orderBy={[
{ key: "name", label: t("fields.name") },
{ key: "created_at", label: t("fields.createdAt") },
{ key: "updated_at", label: t("fields.updatedAt") },
]}
layout="fill"
noRecords={{
message: t(
@@ -1,5 +1,5 @@
import { zodResolver } from "@hookform/resolvers/zod"
import { AdminCampaign, PromotionDTO } from "@medusajs/types"
import { AdminCampaign, HttpTypes } from "@medusajs/types"
import { Button, Checkbox, Hint, Tooltip, toast } from "@medusajs/ui"
import { keepPreviousData } from "@tanstack/react-query"
import {
@@ -131,7 +131,12 @@ export const AddCampaignPromotionsForm = ({
pageSize={PAGE_SIZE}
isLoading={isLoading}
filters={filters}
orderBy={["title", "status", "created_at", "updated_at"]}
orderBy={[
{ key: "code", label: t("fields.code") },
{ key: "type", label: t("fields.type") },
{ key: "created_at", label: t("fields.createdAt") },
{ key: "updated_at", label: t("fields.updatedAt") },
]}
queryObject={raw}
layout="fill"
pagination
@@ -158,7 +163,7 @@ export const AddCampaignPromotionsForm = ({
)
}
const columnHelper = createColumnHelper<PromotionDTO>()
const columnHelper = createColumnHelper<HttpTypes.AdminPromotion>()
const useColumns = () => {
const base = usePromotionTableColumns()
@@ -100,12 +100,10 @@ export const CampaignPromotionSection = ({
search
pagination
orderBy={[
"email",
"first_name",
"last_name",
"has_account",
"created_at",
"updated_at",
{ key: "code", label: t("fields.code") },
{ key: "type", label: t("fields.type") },
{ key: "created_at", label: t("fields.createdAt") },
{ key: "updated_at", label: t("fields.updatedAt") },
]}
queryObject={raw}
commands={[
@@ -68,7 +68,11 @@ export const CampaignListTable = () => {
navigateTo={(row) => row.id}
isLoading={isLoading}
queryObject={raw}
orderBy={["name", "created_at", "updated_at"]}
orderBy={[
{ key: "name", label: t("fields.name") },
{ key: "created_at", label: t("fields.createdAt") },
{ key: "updated_at", label: t("fields.updatedAt") },
]}
/>
</Container>
)
@@ -97,7 +101,9 @@ const CampaignActions = ({ campaign }: { campaign: AdminCampaign }) => {
await mutateAsync(undefined, {
onSuccess: () => {
toast.success(t("campaigns.toast.delete"))
toast.success(
t("campaigns.delete.successToast", { name: campaign.name })
)
},
onError: (e) => {
toast.error(e.message)
@@ -129,7 +129,11 @@ export const CategoryProductSection = ({
table={table}
filters={filters}
columns={columns}
orderBy={["title", "created_at", "updated_at"]}
orderBy={[
{ key: "title", label: t("fields.title") },
{ key: "created_at", label: t("fields.createdAt") },
{ key: "updated_at", label: t("fields.updatedAt") },
]}
pageSize={PAGE_SIZE}
count={count}
navigateTo={(row) => `/products/${row.id}`}
@@ -166,7 +166,11 @@ export const EditCategoryProductsForm = ({
count={count}
queryObject={raw}
filters={filters}
orderBy={["title", "created_at", "updated_at"]}
orderBy={[
{ key: "title", label: t("fields.title") },
{ key: "created_at", label: t("fields.createdAt") },
{ key: "updated_at", label: t("fields.updatedAt") },
]}
prefix={PREFIX}
isLoading={isPending}
layout="fill"
@@ -175,7 +175,11 @@ export const AddProductsToCollectionForm = ({
count={count}
queryObject={raw}
filters={filters}
orderBy={["title", "created_at", "updated_at"]}
orderBy={[
{ key: "title", label: t("fields.title") },
{ key: "created_at", label: t("fields.createdAt") },
{ key: "updated_at", label: t("fields.updatedAt") },
]}
prefix={PREFIX}
isLoading={isLoading}
layout="fill"
@@ -124,7 +124,11 @@ export const CollectionProductSection = ({
count={count}
filters={filters}
isLoading={isLoading}
orderBy={["title", "created_at", "updated_at"]}
orderBy={[
{ key: "title", label: t("fields.title") },
{ key: "created_at", label: t("fields.createdAt") },
{ key: "updated_at", label: t("fields.updatedAt") },
]}
queryObject={raw}
commands={[
{
@@ -66,7 +66,12 @@ export const CollectionListTable = () => {
pageSize={PAGE_SIZE}
count={count}
filters={filters}
orderBy={["title", "handle", "created_at", "updated_at"]}
orderBy={[
{ key: "title", label: t("fields.title") },
{ key: "handle", label: t("fields.handle") },
{ key: "created_at", label: t("fields.createdAt") },
{ key: "updated_at", label: t("fields.updatedAt") },
]}
search
navigateTo={(row) => `/collections/${row.original.id}`}
queryObject={raw}
@@ -160,12 +160,12 @@ export const AddCustomersForm = ({
count={count}
filters={filters}
orderBy={[
"email",
"first_name",
"last_name",
"has_account",
"created_at",
"updated_at",
{ key: "email", label: t("fields.email") },
{ key: "first_name", label: t("fields.firstName") },
{ key: "last_name", label: t("fields.lastName") },
{ key: "has_account", label: t("customers.hasAccount") },
{ key: "created_at", label: t("fields.createdAt") },
{ key: "updated_at", label: t("fields.updatedAt") },
]}
isLoading={isLoading}
layout="fill"
@@ -106,12 +106,12 @@ export const CustomerGroupCustomerSection = ({
search
pagination
orderBy={[
"email",
"first_name",
"last_name",
"has_account",
"created_at",
"updated_at",
{ key: "email", label: t("fields.email") },
{ key: "first_name", label: t("fields.firstName") },
{ key: "last_name", label: t("fields.lastName") },
{ key: "has_account", label: t("customers.hasAccount") },
{ key: "created_at", label: t("fields.createdAt") },
{ key: "updated_at", label: t("fields.updatedAt") },
]}
queryObject={raw}
commands={[
@@ -78,7 +78,11 @@ export const CustomerGroupListTable = () => {
search
pagination
navigateTo={(row) => `/customer-groups/${row.original.id}`}
orderBy={["name", "created_at", "updated_at"]}
orderBy={[
{ key: "name", label: t("fields.name") },
{ key: "created_at", label: t("fields.createdAt") },
{ key: "updated_at", label: t("fields.updatedAt") },
]}
queryObject={raw}
isLoading={isLoading}
/>
@@ -137,7 +137,11 @@ export const CustomerGroupSection = ({
filters={filters}
search
pagination
orderBy={["name", "created_at", "updated_at"]}
orderBy={[
{ key: "name", label: t("fields.name") },
{ key: "created_at", label: t("fields.createdAt") },
{ key: "updated_at", label: t("fields.updatedAt") },
]}
commands={[
{
action: handleRemove,
@@ -1,4 +1,5 @@
import { ArrowPath } from "@medusajs/icons"
import { HttpTypes } from "@medusajs/types"
import { Button, Container, Heading } from "@medusajs/ui"
import { keepPreviousData } from "@tanstack/react-query"
import { createColumnHelper } from "@tanstack/react-table"
@@ -11,7 +12,6 @@ import { useOrderTableColumns } from "../../../../../hooks/table/columns/use-ord
import { useOrderTableFilters } from "../../../../../hooks/table/filters/use-order-table-filters"
import { useOrderTableQuery } from "../../../../../hooks/table/query/use-order-table-query"
import { useDataTable } from "../../../../../hooks/use-data-table"
import { HttpTypes } from "@medusajs/types"
type CustomerGeneralSectionProps = {
customer: HttpTypes.AdminCustomer
@@ -75,7 +75,11 @@ export const CustomerOrderSection = ({
count={count}
isLoading={isLoading}
pageSize={PAGE_SIZE}
orderBy={["display_id", "created_at", "updated_at"]}
orderBy={[
{ key: "display_id", label: t("orders.fields.displayId") },
{ key: "created_at", label: t("fields.createdAt") },
{ key: "updated_at", label: t("fields.updatedAt") },
]}
search={true}
queryObject={raw}
/>
@@ -6,6 +6,7 @@ import { useMemo } from "react"
import { useTranslation } from "react-i18next"
import { Link } from "react-router-dom"
import { HttpTypes } from "@medusajs/types"
import { ActionMenu } from "../../../../../components/common/action-menu"
import { DataTable } from "../../../../../components/table/data-table"
import { useCustomers } from "../../../../../hooks/api/customers"
@@ -13,7 +14,6 @@ import { useCustomerTableColumns } from "../../../../../hooks/table/columns/use-
import { useCustomerTableFilters } from "../../../../../hooks/table/filters/use-customer-table-filters"
import { useCustomerTableQuery } from "../../../../../hooks/table/query/use-customer-table-query"
import { useDataTable } from "../../../../../hooks/use-data-table"
import { HttpTypes } from "@medusajs/types"
const PAGE_SIZE = 20
@@ -63,12 +63,12 @@ export const CustomerListTable = () => {
count={count}
filters={filters}
orderBy={[
"email",
"first_name",
"last_name",
"has_account",
"created_at",
"updated_at",
{ key: "email", label: t("fields.email") },
{ key: "first_name", label: t("fields.firstName") },
{ key: "last_name", label: t("fields.lastName") },
{ key: "has_account", label: t("customers.hasAccount") },
{ key: "created_at", label: t("fields.createdAt") },
{ key: "updated_at", label: t("fields.updatedAt") },
]}
isLoading={isLoading}
navigateTo={(row) => row.original.id}
@@ -175,7 +175,11 @@ export const AddCustomerGroupsForm = ({
pageSize={PAGE_SIZE}
count={count}
filters={filters}
orderBy={["name", "created_at", "updated_at"]}
orderBy={[
{ key: "name", label: t("fields.name") },
{ key: "created_at", label: t("fields.createdAt") },
{ key: "updated_at", label: t("fields.updatedAt") },
]}
isLoading={isLoading}
layout="fill"
search="autofocus"
@@ -1,14 +1,14 @@
import { Button, Container, Heading, Text } from "@medusajs/ui"
import { InventoryTypes } from "@medusajs/types"
import { Button, Container, Heading, Text } from "@medusajs/ui"
import { useTranslation } from "react-i18next"
import { Link } from "react-router-dom"
import { DataTable } from "../../../../components/table/data-table"
import { useDataTable } from "../../../../hooks/use-data-table"
import { useInventoryItems } from "../../../../hooks/api/inventory"
import { useDataTable } from "../../../../hooks/use-data-table"
import { useInventoryTableColumns } from "./use-inventory-table-columns"
import { useInventoryTableFilters } from "./use-inventory-table-filters"
import { useInventoryTableQuery } from "./use-inventory-table-query"
import { useTranslation } from "react-i18next"
import { Link } from "react-router-dom"
const PAGE_SIZE = 20
@@ -68,7 +68,12 @@ export const InventoryListTable = () => {
search
filters={filters}
queryObject={raw}
orderBy={["title", "sku", "stocked_quantity", "reserved_quantity"]}
orderBy={[
{ key: "title", label: t("fields.title") },
{ key: "sku", label: t("fields.sku") },
{ key: "stocked_quantity", label: t("fields.inStock") },
{ key: "reserved_quantity", label: t("inventory.reserved") },
]}
navigateTo={(row) => `${row.id}`}
/>
</Container>
@@ -246,7 +246,10 @@ const AreaStackedModal = <TForm extends UseFormReturn<any>>({
search
pagination
layout="fill"
orderBy={["name", "code"]}
orderBy={[
{ key: "display_name", label: t("fields.name") },
{ key: "iso_2", label: t("fields.code") },
]}
queryObject={raw}
prefix={PREFIX}
/>
@@ -132,7 +132,7 @@ export const LocationEditFulfillmentProvidersForm = ({
filters={filters}
search="autofocus"
pagination
orderBy={["id", "created_at", "updated_at"]}
orderBy={[{ key: "id", label: t("fields.id") }]}
queryObject={raw}
layout="fill"
/>
@@ -146,7 +146,11 @@ export const LocationEditSalesChannelsForm = ({
filters={filters}
search="autofocus"
pagination
orderBy={["name", "created_at", "updated_at"]}
orderBy={[
{ key: "name", label: t("fields.name") },
{ key: "created_at", label: t("fields.createdAt") },
{ key: "updated_at", label: t("fields.updatedAt") },
]}
queryObject={raw}
layout="fill"
/>
@@ -6,6 +6,7 @@ import {
import { OnChangeFn, RowSelectionState } from "@tanstack/react-table"
import { useMemo, useState } from "react"
import { useTranslation } from "react-i18next"
import { DataTable } from "../../../../../components/table/data-table"
import { useDataTable } from "../../../../../hooks/use-data-table"
import { getStylizedAmount } from "../../../../../lib/money-amount-helpers"
@@ -30,6 +31,8 @@ export const AddClaimItemsTable = ({
items,
currencyCode,
}: AddReturnItemsTableProps) => {
const { t } = useTranslation()
const [rowSelection, setRowSelection] = useState<RowSelectionState>(
selectedItems.reduce((acc, id) => {
acc[id] = true
@@ -141,11 +144,17 @@ export const AddClaimItemsTable = ({
layout="fill"
search
orderBy={[
"product_title",
"variant_title",
"sku",
"returnable_quantity",
"refundable_amount",
{ key: "product_title", label: t("fields.product") },
{ key: "variant_title", label: t("fields.variant") },
{ key: "sku", label: t("fields.sku") },
{
key: "returnable_quantity",
label: t("orders.fields.returnableQuantity"),
},
{
key: "refundable_amount",
label: t("orders.fields.refundableAmount"),
},
]}
prefix={PREFIX}
queryObject={raw}
@@ -1,6 +1,7 @@
import { OnChangeFn, RowSelectionState } from "@tanstack/react-table"
import { useState } from "react"
import { useTranslation } from "react-i18next"
import { DataTable } from "../../../../../components/table/data-table"
import { useVariants } from "../../../../../hooks/api"
import { useDataTable } from "../../../../../hooks/use-data-table"
@@ -22,6 +23,8 @@ export const AddClaimOutboundItemsTable = ({
selectedItems,
currencyCode,
}: AddClaimOutboundItemsTableProps) => {
const { t } = useTranslation()
const [rowSelection, setRowSelection] = useState<RowSelectionState>(
selectedItems.reduce((acc, id) => {
acc[id] = true
@@ -78,7 +81,11 @@ export const AddClaimOutboundItemsTable = ({
pagination
layout="fill"
search
orderBy={["product_id", "title", "sku"]}
orderBy={[
{ key: "product_id", label: t("fields.product") },
{ key: "title", label: t("fields.title") },
{ key: "sku", label: t("fields.sku") },
]}
prefix={PREFIX}
queryObject={raw}
/>
@@ -1,12 +1,13 @@
import { OnChangeFn, RowSelectionState } from "@tanstack/react-table"
import { useState } from "react"
import { useTranslation } from "react-i18next"
import { DataTable } from "../../../../../components/table/data-table"
import { useVariants } from "../../../../../hooks/api"
import { useDataTable } from "../../../../../hooks/use-data-table"
import { useOrderEditItemsTableColumns } from "./use-order-edit-item-table-columns"
import { useOrderEditItemTableFilters } from "./use-order-edit-item-table-filters"
import { useOrderEditItemTableQuery } from "./use-order-edit-item-table-query"
import { useOrderEditItemsTableColumns } from "./use-order-edit-item-table-columns"
const PAGE_SIZE = 50
const PREFIX = "rit"
@@ -20,6 +21,8 @@ export const AddOrderEditItemsTable = ({
onSelectionChange,
currencyCode,
}: AddExchangeOutboundItemsTableProps) => {
const { t } = useTranslation()
const [rowSelection, setRowSelection] = useState<RowSelectionState>({})
const updater: OnChangeFn<RowSelectionState> = (fn) => {
@@ -71,7 +74,11 @@ export const AddOrderEditItemsTable = ({
pagination
layout="fill"
search
orderBy={["product_id", "title", "sku"]}
orderBy={[
{ key: "product_id", label: t("fields.product") },
{ key: "title", label: t("fields.title") },
{ key: "sku", label: t("fields.sku") },
]}
prefix={PREFIX}
queryObject={raw}
/>
@@ -2,6 +2,7 @@ import { AdminOrderLineItem, DateComparisonOperator } from "@medusajs/types"
import { OnChangeFn, RowSelectionState } from "@tanstack/react-table"
import { useMemo, useState } from "react"
import { useTranslation } from "react-i18next"
import { DataTable } from "../../../../../components/table/data-table"
import { useDataTable } from "../../../../../hooks/use-data-table"
import { getReturnableQuantity } from "../../../../../lib/rma"
@@ -25,6 +26,8 @@ export const AddExchangeInboundItemsTable = ({
items,
currencyCode,
}: AddExchangeInboundItemsTableProps) => {
const { t } = useTranslation()
const [rowSelection, setRowSelection] = useState<RowSelectionState>(
selectedItems.reduce((acc, id) => {
acc[id] = true
@@ -108,7 +111,11 @@ export const AddExchangeInboundItemsTable = ({
pagination
layout="fill"
search
orderBy={["product_title", "variant_title", "sku"]}
orderBy={[
{ key: "product_title", label: t("fields.product") },
{ key: "variant_title", label: t("fields.variant") },
{ key: "sku", label: t("fields.sku") },
]}
prefix={PREFIX}
queryObject={raw}
/>
@@ -1,6 +1,7 @@
import { OnChangeFn, RowSelectionState } from "@tanstack/react-table"
import { useState } from "react"
import { useTranslation } from "react-i18next"
import { DataTable } from "../../../../../components/table/data-table"
import { useVariants } from "../../../../../hooks/api"
import { useDataTable } from "../../../../../hooks/use-data-table"
@@ -22,6 +23,8 @@ export const AddExchangeOutboundItemsTable = ({
selectedItems,
currencyCode,
}: AddExchangeOutboundItemsTableProps) => {
const { t } = useTranslation()
const [rowSelection, setRowSelection] = useState<RowSelectionState>(
selectedItems.reduce((acc, id) => {
acc[id] = true
@@ -78,7 +81,11 @@ export const AddExchangeOutboundItemsTable = ({
pagination
layout="fill"
search
orderBy={["product_id", "title", "sku"]}
orderBy={[
{ key: "product_id", label: t("fields.product") },
{ key: "title", label: t("fields.title") },
{ key: "sku", label: t("fields.sku") },
]}
prefix={PREFIX}
queryObject={raw}
/>
@@ -2,18 +2,19 @@ import { OnChangeFn, RowSelectionState } from "@tanstack/react-table"
import { useMemo, useState } from "react"
import {
AdminOrderLineItem,
DateComparisonOperator,
NumericalComparisonOperator,
} from "@medusajs/types"
import { AdminOrderLineItem } from "@medusajs/types"
import { useTranslation } from "react-i18next"
import { DataTable } from "../../../../../components/table/data-table"
import { useDataTable } from "../../../../../hooks/use-data-table"
import { getStylizedAmount } from "../../../../../lib/money-amount-helpers"
import { getReturnableQuantity } from "../../../../../lib/rma"
import { useReturnItemTableColumns } from "./use-return-item-table-columns"
import { useReturnItemTableFilters } from "./use-return-item-table-filters"
import { useReturnItemTableQuery } from "./use-return-item-table-query"
import { useDataTable } from "../../../../../hooks/use-data-table"
import { DataTable } from "../../../../../components/table/data-table"
import { getStylizedAmount } from "../../../../../lib/money-amount-helpers"
import { getReturnableQuantity } from "../../../../../lib/rma"
const PAGE_SIZE = 50
const PREFIX = "rit"
@@ -31,6 +32,8 @@ export const AddReturnItemsTable = ({
items,
currencyCode,
}: AddReturnItemsTableProps) => {
const { t } = useTranslation()
const [rowSelection, setRowSelection] = useState<RowSelectionState>(
selectedItems.reduce((acc, id) => {
acc[id] = true
@@ -142,11 +145,17 @@ export const AddReturnItemsTable = ({
layout="fill"
search
orderBy={[
"product_title",
"variant_title",
"sku",
"returnable_quantity",
"refundable_amount",
{ key: "product_title", label: t("fields.product") },
{ key: "variant_title", label: t("fields.variant") },
{ key: "sku", label: t("fields.sku") },
{
key: "returnable_quantity",
label: t("orders.fields.returnableQuantity"),
},
{
key: "refundable_amount",
label: t("orders.fields.refundableAmount"),
},
]}
prefix={PREFIX}
queryObject={raw}
@@ -1,13 +1,13 @@
import { keepPreviousData } from "@tanstack/react-query"
import { Container, Heading } from "@medusajs/ui"
import { keepPreviousData } from "@tanstack/react-query"
import { useTranslation } from "react-i18next"
import { DataTable } from "../../../../../components/table/data-table/data-table"
import { useOrders } from "../../../../../hooks/api/orders"
import { useOrderTableColumns } from "../../../../../hooks/table/columns/use-order-table-columns"
import { useOrderTableFilters } from "../../../../../hooks/table/filters/use-order-table-filters"
import { useOrderTableQuery } from "../../../../../hooks/table/query/use-order-table-query"
import { useDataTable } from "../../../../../hooks/use-data-table"
import { useOrders } from "../../../../../hooks/api/orders"
import { DEFAULT_FIELDS } from "../../const"
@@ -59,7 +59,11 @@ export const OrderListTable = () => {
search
isLoading={isLoading}
pageSize={PAGE_SIZE}
orderBy={["display_id", "created_at", "updated_at"]}
orderBy={[
{ key: "display_id", label: t("orders.fields.displayId") },
{ key: "created_at", label: t("fields.createdAt") },
{ key: "updated_at", label: t("fields.updatedAt") },
]}
queryObject={raw}
noRecords={{
message: t("orders.list.noRecordsMessage"),
@@ -126,7 +126,11 @@ export const PriceListCustomerGroupRuleForm = ({
count={count}
isLoading={isLoading}
filters={filters}
orderBy={["name", "created_at", "updated_at"]}
orderBy={[
{ key: "name", label: t("fields.name") },
{ key: "created_at", label: t("fields.createdAt") },
{ key: "updated_at", label: t("fields.updatedAt") },
]}
layout="fill"
pagination
search
@@ -9,6 +9,7 @@ import {
import { useMemo, useState } from "react"
import { UseFormReturn, useWatch } from "react-hook-form"
import { useTranslation } from "react-i18next"
import { DataTable } from "../../../../../components/table/data-table"
import { useProducts } from "../../../../../hooks/api/products"
import { useProductTableColumns } from "../../../../../hooks/table/columns/use-product-table-columns"
@@ -17,7 +18,6 @@ import { useProductTableQuery } from "../../../../../hooks/table/query/use-produ
import { useDataTable } from "../../../../../hooks/use-data-table"
import { PriceListCreateProductsSchema } from "../../../common/schemas"
import { PricingCreateSchemaType } from "./schema"
import { useTranslation } from "react-i18next"
type PriceListProductsFormProps = {
form: UseFormReturn<PricingCreateSchemaType>
@@ -126,7 +126,12 @@ export const PriceListProductsForm = ({ form }: PriceListProductsFormProps) => {
count={count}
isLoading={isLoading}
layout="fill"
orderBy={["title", "status", "created_at", "updated_at"]}
orderBy={[
{ key: "title", label: t("fields.title") },
{ key: "status", label: t("fields.status") },
{ key: "created_at", label: t("fields.createdAt") },
{ key: "updated_at", label: t("fields.updatedAt") },
]}
pagination
search
queryObject={raw}
@@ -141,7 +141,11 @@ export const PriceListProductSection = ({
pageSize={PAGE_SIZE}
isLoading={isLoading}
navigateTo={(row) => `/products/${row.original.id}`}
orderBy={["title", "created_at", "updated_at"]}
orderBy={[
{ key: "title", label: t("fields.title") },
{ key: "created_at", label: t("fields.createdAt") },
{ key: "updated_at", label: t("fields.updatedAt") },
]}
commands={[
{
action: handleEdit,
@@ -58,7 +58,12 @@ export const PriceListListTable = () => {
columns={columns}
count={count}
filters={filters}
orderBy={["title", "status", "created_at", "updated_at"]}
orderBy={[
{ key: "title", label: t("fields.title") },
{ key: "status", label: t("fields.status") },
{ key: "created_at", label: t("fields.createdAt") },
{ key: "updated_at", label: t("fields.updatedAt") },
]}
queryObject={raw}
pageSize={PAGE_SIZE}
navigateTo={(row) => row.original.id}
@@ -8,6 +8,7 @@ import {
} from "@tanstack/react-table"
import { useMemo, useState } from "react"
import { UseFormReturn, useWatch } from "react-hook-form"
import { useTranslation } from "react-i18next"
import { DataTable } from "../../../../../components/table/data-table"
import { useProducts } from "../../../../../hooks/api/products"
import { useProductTableColumns } from "../../../../../hooks/table/columns/use-product-table-columns"
@@ -36,13 +37,17 @@ export const PriceListPricesAddProductIdsForm = ({
priceList,
form,
}: PriceListPricesAddProductIdsFormProps) => {
const { t } = useTranslation()
const { control, setValue } = form
const variantIdMap = useMemo(() => {
return priceList.prices.reduce((acc, curr) => {
acc[curr.variant_id] = true
return acc
}, {} as Record<string, boolean>)
return priceList.prices.reduce(
(acc, curr) => {
acc[curr.variant_id] = true
return acc
},
{} as Record<string, boolean>
)
}, [priceList.prices])
const selectedIds = useWatch({
@@ -140,7 +145,12 @@ export const PriceListPricesAddProductIdsForm = ({
count={count}
isLoading={isLoading}
layout="fill"
orderBy={["title", "status", "created_at", "updated_at"]}
orderBy={[
{ key: "title", label: t("fields.title") },
{ key: "status", label: t("fields.status") },
{ key: "created_at", label: t("fields.createdAt") },
{ key: "updated_at", label: t("fields.updatedAt") },
]}
pagination
search
queryObject={raw}
@@ -62,7 +62,12 @@ export const ProductTagProductSection = ({
navigateTo={(row) => row.original.id}
search
pagination
orderBy={["title", "status", "created_at", "updated_at"]}
orderBy={[
{ key: "title", label: t("fields.title") },
{ key: "status", label: t("fields.status") },
{ key: "created_at", label: t("fields.createdAt") },
{ key: "updated_at", label: t("fields.updatedAt") },
]}
/>
</Container>
)
@@ -71,7 +71,11 @@ export const ProductTagListTable = () => {
navigateTo={(row) => row.original.id}
search
pagination
orderBy={["value", "created_at", "updated_at"]}
orderBy={[
{ key: "value", label: t("fields.value") },
{ key: "created_at", label: t("fields.createdAt") },
{ key: "updated_at", label: t("fields.updatedAt") },
]}
/>
</Container>
)
@@ -56,7 +56,11 @@ export const ProductTypeProductSection = ({
count={count}
pageSize={PAGE_SIZE}
navigateTo={({ original }) => `/products/${original.id}`}
orderBy={["title", "created_at", "updated_at"]}
orderBy={[
{ key: "title", label: t("fields.title") },
{ key: "created_at", label: t("fields.createdAt") },
{ key: "updated_at", label: t("fields.updatedAt") },
]}
queryObject={raw}
search
pagination
@@ -64,7 +64,11 @@ export const ProductTypeListTable = () => {
columns={columns}
pageSize={PAGE_SIZE}
count={count}
orderBy={["value", "created_at", "updated_at"]}
orderBy={[
{ key: "value", label: t("fields.value") },
{ key: "created_at", label: t("fields.createdAt") },
{ key: "updated_at", label: t("fields.updatedAt") },
]}
navigateTo={({ original }) => original.id}
queryObject={raw}
pagination
@@ -138,7 +138,11 @@ export const ProductCreateSalesChannelStackedModal = ({
filters={filters}
isLoading={isLoading}
layout="fill"
orderBy={["name", "created_at", "updated_at"]}
orderBy={[
{ key: "name", label: t("fields.name") },
{ key: "created_at", label: t("fields.createdAt") },
{ key: "updated_at", label: t("fields.updatedAt") },
]}
queryObject={raw}
search
pagination
@@ -1,16 +1,16 @@
import { PencilSquare, Plus } from "@medusajs/icons"
import { Container, Heading } from "@medusajs/ui"
import { useTranslation } from "react-i18next"
import { keepPreviousData } from "@tanstack/react-query"
import { HttpTypes } from "@medusajs/types"
import { Container, Heading } from "@medusajs/ui"
import { keepPreviousData } from "@tanstack/react-query"
import { useTranslation } from "react-i18next"
import { ActionMenu } from "../../../../../components/common/action-menu"
import { DataTable } from "../../../../../components/table/data-table"
import { useProductVariants } from "../../../../../hooks/api/products"
import { useDataTable } from "../../../../../hooks/use-data-table"
import { useProductVariantTableColumns } from "./use-variant-table-columns"
import { useProductVariantTableFilters } from "./use-variant-table-filters"
import { useProductVariantTableQuery } from "./use-variant-table-query"
import { useProductVariants } from "../../../../../hooks/api/products"
type ProductVariantSectionProps = {
product: HttpTypes.AdminProduct
@@ -86,7 +86,11 @@ export const ProductVariantSection = ({
count={count}
pageSize={PAGE_SIZE}
isLoading={isLoading}
orderBy={["title", "created_at", "updated_at"]}
orderBy={[
{ key: "title", label: t("fields.title") },
{ key: "created_at", label: t("fields.createdAt") },
{ key: "updated_at", label: t("fields.updatedAt") },
]}
navigateTo={(row) =>
`/products/${row.original.product_id}/variants/${row.id}`
}
@@ -83,7 +83,11 @@ export const ProductListTable = () => {
isLoading={isLoading}
queryObject={raw}
navigateTo={(row) => `${row.original.id}`}
orderBy={["title", "created_at", "updated_at"]}
orderBy={[
{ key: "title", label: t("fields.title") },
{ key: "created_at", label: t("fields.createdAt") },
{ key: "updated_at", label: t("fields.updatedAt") },
]}
noRecords={{
message: t("products.list.noRecordsMessage"),
}}
@@ -132,7 +132,11 @@ export const EditSalesChannelsForm = ({
filters={filters}
search="autofocus"
pagination
orderBy={["name", "created_at", "updated_at"]}
orderBy={[
{ key: "name", label: t("fields.name") },
{ key: "created_at", label: t("fields.createdAt") },
{ key: "updated_at", label: t("fields.updatedAt") },
]}
queryObject={raw}
layout="fill"
/>
@@ -73,7 +73,10 @@ export const PromotionListTable = () => {
isLoading={isLoading}
queryObject={raw}
navigateTo={(row) => `${row.original.id}`}
orderBy={["created_at", "updated_at"]}
orderBy={[
{ key: "created_at", label: t("fields.createdAt") },
{ key: "updated_at", label: t("fields.updatedAt") },
]}
/>
<Outlet />
</Container>
@@ -150,7 +150,10 @@ export const AddCountriesForm = ({ region }: AddCountriesFormProps) => {
search="autofocus"
pagination
layout="fill"
orderBy={["name", "code"]}
orderBy={[
{ key: "display_name", label: t("fields.name") },
{ key: "iso_2", label: t("fields.code") },
]}
queryObject={raw}
prefix={PREFIX}
/>
@@ -364,7 +364,10 @@ export const CreateRegionForm = ({
columns={columns}
count={count}
pageSize={PAGE_SIZE}
orderBy={["name", "code"]}
orderBy={[
{ key: "display_name", label: t("fields.name") },
{ key: "iso_2", label: t("fields.code") },
]}
pagination
search="autofocus"
layout="fill"
@@ -120,7 +120,10 @@ export const RegionCountrySection = ({ region }: RegionCountrySectionProps) => {
columns={columns}
pageSize={PAGE_SIZE}
count={count}
orderBy={["name", "code"]}
orderBy={[
{ key: "display_name", label: t("fields.name") },
{ key: "iso_2", label: t("fields.code") },
]}
search
pagination
queryObject={raw}
@@ -4,9 +4,9 @@ import {
Button,
Container,
Heading,
Text,
toast,
usePrompt,
Text,
} from "@medusajs/ui"
import { keepPreviousData } from "@tanstack/react-query"
import { createColumnHelper } from "@tanstack/react-table"
@@ -83,7 +83,11 @@ export const RegionListTable = () => {
pageSize={PAGE_SIZE}
isLoading={isLoading}
filters={filters}
orderBy={["name", "created_at", "updated_at"]}
orderBy={[
{ key: "name", label: t("fields.name") },
{ key: "created_at", label: t("fields.createdAt") },
{ key: "updated_at", label: t("fields.updatedAt") },
]}
navigateTo={(row) => `${row.original.id}`}
pagination
search
@@ -118,18 +122,14 @@ const RegionActions = ({ region }: { region: HttpTypes.AdminRegion }) => {
return
}
try {
await mutateAsync(undefined)
toast.success(t("general.success"), {
description: t("regions.toast.delete"),
dismissLabel: t("actions.close"),
})
} catch (e) {
toast.error(t("general.error"), {
description: e.message,
dismissLabel: t("actions.close"),
})
}
await mutateAsync(undefined, {
onSuccess: () => {
toast.success(t("regions.toast.delete"))
},
onError: (e) => {
toast.error(e.message)
},
})
}
return (
@@ -141,7 +141,12 @@ export const AddProductsToSalesChannelForm = ({
pageSize={PAGE_SIZE}
isLoading={isLoading}
filters={filters}
orderBy={["title", "status", "created_at", "updated_at"]}
orderBy={[
{ key: "title", label: t("fields.title") },
{ key: "status", label: t("fields.status") },
{ key: "created_at", label: t("fields.createdAt") },
{ key: "updated_at", label: t("fields.updatedAt") },
]}
queryObject={raw}
layout="fill"
pagination
@@ -135,7 +135,12 @@ export const SalesChannelProductSection = ({
filters={filters}
navigateTo={(row) => `/products/${row.id}`}
isLoading={isLoading}
orderBy={["title", "variants", "status", "created_at", "updated_at"]}
orderBy={[
{ key: "title", label: t("fields.title") },
{ key: "status", label: t("fields.status") },
{ key: "created_at", label: t("fields.createdAt") },
{ key: "updated_at", label: t("fields.updatedAt") },
]}
queryObject={raw}
noRecords={{
message: t("salesChannels.products.list.noRecordsMessage"),
@@ -84,7 +84,11 @@ export const SalesChannelListTable = () => {
navigateTo={(row) => row.id}
isLoading={isLoading}
queryObject={raw}
orderBy={["name", "created_at", "updated_at"]}
orderBy={[
{ key: "name", label: t("fields.name") },
{ key: "created_at", label: t("fields.createdAt") },
{ key: "updated_at", label: t("fields.updatedAt") },
]}
/>
</Container>
)
@@ -61,7 +61,12 @@ export const ShippingProfileListTable = () => {
count={count}
columns={columns}
filters={filters}
orderBy={["name", "type", "created_at", "updated_at"]}
orderBy={[
{ key: "name", label: t("fields.name") },
{ key: "type", label: t("fields.type") },
{ key: "created_at", label: t("fields.createdAt") },
{ key: "updated_at", label: t("fields.updatedAt") },
]}
isLoading={isLoading}
navigateTo={(row) => row.id}
queryObject={raw}
@@ -64,13 +64,16 @@ export const AddCurrenciesForm = ({
const form = useForm<zod.infer<typeof AddCurrenciesSchema>>({
defaultValues: {
currencies: [],
pricePreferences: pricePreferences?.reduce((acc, curr) => {
if (curr.value) {
acc[curr.value] = curr.is_tax_inclusive
}
pricePreferences: pricePreferences?.reduce(
(acc, curr) => {
if (curr.value) {
acc[curr.value] = curr.is_tax_inclusive
}
return acc
}, {} as Record<string, boolean>),
return acc
},
{} as Record<string, boolean>
),
},
resolver: zodResolver(AddCurrenciesSchema),
})
@@ -192,7 +195,10 @@ export const AddCurrenciesForm = ({
pagination
search="autofocus"
prefix={PREFIX}
orderBy={["code", "name"]}
orderBy={[
{ key: "name", label: t("fields.name") },
{ key: "code", label: t("fields.code") },
]}
isLoading={isLoading}
queryObject={raw}
/>
@@ -165,7 +165,10 @@ export const StoreCurrencySection = ({ store }: StoreCurrencySectionProps) => {
/>
</div>
<DataTable
orderBy={["code", "name"]}
orderBy={[
{ key: "name", label: t("fields.name") },
{ key: "code", label: t("fields.code") },
]}
search
pagination
table={table}
@@ -2,46 +2,46 @@ import { HttpTypes } from "@medusajs/types"
import { Button, Checkbox } from "@medusajs/ui"
import { keepPreviousData } from "@tanstack/react-query"
import {
OnChangeFn,
RowSelectionState,
createColumnHelper,
OnChangeFn,
RowSelectionState,
createColumnHelper,
} from "@tanstack/react-table"
import { useEffect, useMemo, useState } from "react"
import { useTranslation } from "react-i18next"
import { useSearchParams } from "react-router-dom"
import {
StackedDrawer,
StackedFocusModal,
StackedDrawer,
StackedFocusModal,
} from "../../../../../components/modals"
import { DataTable } from "../../../../../components/table/data-table"
import {
useCollections,
useCustomerGroups,
useProductTags,
useProductTypes,
useProducts,
useCollections,
useCustomerGroups,
useProductTags,
useProductTypes,
useProducts,
} from "../../../../../hooks/api"
import {
useCollectionTableColumns,
useCustomerGroupTableColumns,
useProductTableColumns,
useProductTagTableColumns,
useProductTypeTableColumns,
useCollectionTableColumns,
useCustomerGroupTableColumns,
useProductTableColumns,
useProductTagTableColumns,
useProductTypeTableColumns,
} from "../../../../../hooks/table/columns"
import {
useCollectionTableFilters,
useCustomerGroupTableFilters,
useProductTableFilters,
useProductTagTableFilters,
useProductTypeTableFilters,
useCollectionTableFilters,
useCustomerGroupTableFilters,
useProductTableFilters,
useProductTagTableFilters,
useProductTypeTableFilters,
} from "../../../../../hooks/table/filters"
import {
useCollectionTableQuery,
useCustomerGroupTableQuery,
useProductTableQuery,
useProductTagTableQuery,
useProductTypeTableQuery,
useCollectionTableQuery,
useCustomerGroupTableQuery,
useProductTableQuery,
useProductTagTableQuery,
useProductTypeTableQuery,
} from "../../../../../hooks/table/query"
import { useDataTable } from "../../../../../hooks/use-data-table"
import { TaxRateRuleReferenceType } from "../../constants"
@@ -140,6 +140,8 @@ const CustomerGroupTable = ({
intermediate,
setIntermediate,
}: TableImplementationProps) => {
const { t } = useTranslation()
const [rowSelection, setRowSelection] =
useState<RowSelectionState>(initialRowState)
@@ -206,7 +208,11 @@ const CustomerGroupTable = ({
count={count}
isLoading={isLoading}
filters={filters}
orderBy={["name", "created_at", "updated_at"]}
orderBy={[
{ key: "name", label: t("fields.name") },
{ key: "created_at", label: t("fields.createdAt") },
{ key: "updated_at", label: t("fields.updatedAt") },
]}
layout="fill"
pagination
search
@@ -264,6 +270,8 @@ const ProductTable = ({
intermediate,
setIntermediate,
}: TableImplementationProps) => {
const { t } = useTranslation()
const [rowSelection, setRowSelection] =
useState<RowSelectionState>(initialRowState)
@@ -336,7 +344,11 @@ const ProductTable = ({
count={count}
isLoading={isLoading}
filters={filters}
orderBy={["title", "created_at", "updated_at"]}
orderBy={[
{ key: "title", label: t("fields.title") },
{ key: "created_at", label: t("fields.createdAt") },
{ key: "updated_at", label: t("fields.updatedAt") },
]}
layout="fill"
pagination
search
@@ -394,6 +406,8 @@ const ProductCollectionTable = ({
intermediate,
setIntermediate,
}: TableImplementationProps) => {
const { t } = useTranslation()
const [rowSelection, setRowSelection] =
useState<RowSelectionState>(initialRowState)
@@ -466,7 +480,11 @@ const ProductCollectionTable = ({
count={count}
isLoading={isLoading}
filters={filters}
orderBy={["title", "created_at", "updated_at"]}
orderBy={[
{ key: "title", label: t("fields.title") },
{ key: "created_at", label: t("fields.createdAt") },
{ key: "updated_at", label: t("fields.updatedAt") },
]}
layout="fill"
pagination
search
@@ -524,6 +542,8 @@ const ProductTypeTable = ({
intermediate,
setIntermediate,
}: TableImplementationProps) => {
const { t } = useTranslation()
const [rowSelection, setRowSelection] =
useState<RowSelectionState>(initialRowState)
@@ -596,7 +616,11 @@ const ProductTypeTable = ({
count={count}
isLoading={isLoading}
filters={filters}
orderBy={["value", "created_at", "updated_at"]}
orderBy={[
{ key: "value", label: t("fields.value") },
{ key: "created_at", label: t("fields.createdAt") },
{ key: "updated_at", label: t("fields.updatedAt") },
]}
layout="fill"
pagination
search
@@ -654,6 +678,8 @@ const ProductTagTable = ({
intermediate,
setIntermediate,
}: TableImplementationProps) => {
const { t } = useTranslation()
const [rowSelection, setRowSelection] =
useState<RowSelectionState>(initialRowState)
@@ -726,7 +752,11 @@ const ProductTagTable = ({
count={count}
isLoading={isLoading}
filters={filters}
orderBy={["value", "created_at", "updated_at"]}
orderBy={[
{ key: "value", label: t("fields.value") },
{ key: "created_at", label: t("fields.createdAt") },
{ key: "updated_at", label: t("fields.updatedAt") },
]}
layout="fill"
pagination
search
@@ -168,7 +168,11 @@ export const InviteUserForm = () => {
search="autofocus"
isLoading={isLoading}
queryObject={raw}
orderBy={["email", "created_at", "updated_at"]}
orderBy={[
{ key: "email", label: t("fields.email") },
{ key: "created_at", label: t("fields.createdAt") },
{ key: "updated_at", label: t("fields.updatedAt") },
]}
/>
</Container>
</div>
@@ -55,7 +55,11 @@ export const UserListTable = () => {
count={count}
pageSize={PAGE_SIZE}
isLoading={isLoading}
orderBy={["email", "first_name", "last_name"]}
orderBy={[
{ key: "email", label: t("fields.email") },
{ key: "first_name", label: t("fields.firstName") },
{ key: "last_name", label: t("fields.lastName") },
]}
navigateTo={(row) => `${row.id}`}
search
pagination