docs: expanding table in data-table component
This commit is contained in:
parent
7a03a4caab
commit
9ddbd5c0d2
|
|
@ -866,11 +866,237 @@ This adds a checkbox to each row and a checkbox in the header to select all rows
|
||||||
|
|
||||||
You can show the number of selected rows using the `table.getFilteredSelectedRowModel()` API.
|
You can show the number of selected rows using the `table.getFilteredSelectedRowModel()` API.
|
||||||
|
|
||||||
```vue
|
```vue:line-numbers {8-11}
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="border rounded-md">
|
||||||
|
<Table />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex items-center justify-end space-x-2 py-4">
|
||||||
<div class="flex-1 text-sm text-muted-foreground">
|
<div class="flex-1 text-sm text-muted-foreground">
|
||||||
{{ table.getFilteredSelectedRowModel().rows.length }} of
|
{{ table.getFilteredSelectedRowModel().rows.length }} of
|
||||||
{{ table.getFilteredRowModel().rows.length }} row(s) selected.
|
{{ table.getFilteredRowModel().rows.length }} row(s) selected.
|
||||||
</div>
|
</div>
|
||||||
|
<div class="space-x-2">
|
||||||
|
<PaginationButtons />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
</Steps>
|
||||||
|
|
||||||
|
<Steps>
|
||||||
|
|
||||||
|
## Expanding
|
||||||
|
|
||||||
|
Let's make rows expandable.
|
||||||
|
|
||||||
|
### Update `<DataTable>`
|
||||||
|
|
||||||
|
```vue:line-numbers {7,30,43,52,57,63,103-116}
|
||||||
|
<script setup lang="ts" generic="TData, TValue">
|
||||||
|
import type {
|
||||||
|
ColumnDef,
|
||||||
|
ColumnFiltersState,
|
||||||
|
SortingState,
|
||||||
|
VisibilityState,
|
||||||
|
ExpandedState,
|
||||||
|
} from '@tanstack/vue-table'
|
||||||
|
|
||||||
|
import {
|
||||||
|
DropdownMenu,
|
||||||
|
DropdownMenuCheckboxItem,
|
||||||
|
DropdownMenuContent,
|
||||||
|
DropdownMenuTrigger,
|
||||||
|
} from '@/components/ui/dropdown-menu'
|
||||||
|
|
||||||
|
import { valueUpdater } from '@/lib/utils'
|
||||||
|
|
||||||
|
import { ArrowUpDown, ChevronDown } from 'lucide-vue-next'
|
||||||
|
import { Input } from '@/components/ui/input'
|
||||||
|
import { Button } from '@/components/ui/button'
|
||||||
|
import { h, ref } from 'vue'
|
||||||
|
|
||||||
|
import {
|
||||||
|
FlexRender,
|
||||||
|
getCoreRowModel,
|
||||||
|
getPaginationRowModel,
|
||||||
|
getFilteredRowModel,
|
||||||
|
getSortedRowModel,
|
||||||
|
getExpandedRowModel,
|
||||||
|
useVueTable,
|
||||||
|
} from "@tanstack/vue-table"
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
columns: ColumnDef<TData, TValue>[]
|
||||||
|
data: TData[]
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const sorting = ref<SortingState>([])
|
||||||
|
const columnFilters = ref<ColumnFiltersState>([])
|
||||||
|
const columnVisibility = ref<VisibilityState>({})
|
||||||
|
const rowSelection = ref({})
|
||||||
|
const expanded = ref<ExpandedState>({})
|
||||||
|
|
||||||
|
const table = useVueTable({
|
||||||
|
get data() { return props.data },
|
||||||
|
get columns() { return props.columns },
|
||||||
|
getCoreRowModel: getCoreRowModel(),
|
||||||
|
getPaginationRowModel: getPaginationRowModel(),
|
||||||
|
getSortedRowModel: getSortedRowModel(),
|
||||||
|
getFilteredRowModel: getFilteredRowModel(),
|
||||||
|
getExpandedRowModel: getExpandedRowModel(),
|
||||||
|
onSortingChange: updaterOrValue => valueUpdater(updaterOrValue, sorting),
|
||||||
|
onColumnFiltersChange: updaterOrValue => valueUpdater(updaterOrValue, columnFilters),
|
||||||
|
onColumnVisibilityChange: updaterOrValue => valueUpdater(updaterOrValue, columnVisibility),
|
||||||
|
onRowSelectionChange: updaterOrValue => valueUpdater(updaterOrValue, rowSelection),
|
||||||
|
onExpandedChange: updaterOrValue => valueUpdater(updaterOrValue, expanded),
|
||||||
|
state: {
|
||||||
|
get sorting() { return sorting.value },
|
||||||
|
get columnFilters() { return columnFilters.value },
|
||||||
|
get columnVisibility() { return columnVisibility.value },
|
||||||
|
get rowSelection() { return rowSelection.value },
|
||||||
|
get expanded() { return expanded.value },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="flex items-center py-4">
|
||||||
|
<Input class="max-w-sm" placeholder="Filter emails..."
|
||||||
|
:model-value="table.getColumn('email')?.getFilterValue() as string"
|
||||||
|
@update:model-value=" table.getColumn('email')?.setFilterValue($event)" />
|
||||||
|
<DropdownMenu>
|
||||||
|
<DropdownMenuTrigger as-child>
|
||||||
|
<Button variant="outline" class="ml-auto">
|
||||||
|
Columns
|
||||||
|
<ChevronDown class="w-4 h-4 ml-2" />
|
||||||
|
</Button>
|
||||||
|
</DropdownMenuTrigger>
|
||||||
|
<DropdownMenuContent align="end">
|
||||||
|
<DropdownMenuCheckboxItem
|
||||||
|
v-for="column in table.getAllColumns().filter((column) => column.getCanHide())" :key="column.id"
|
||||||
|
class="capitalize" :checked="column.getIsVisible()" @update:checked="(value) => {
|
||||||
|
column.toggleVisibility(!!value)
|
||||||
|
}">
|
||||||
|
{{ column.id }}
|
||||||
|
</DropdownMenuCheckboxItem>
|
||||||
|
</DropdownMenuContent>
|
||||||
|
</DropdownMenu>
|
||||||
|
</div>
|
||||||
|
<div class="border rounded-md">
|
||||||
|
<Table>
|
||||||
|
<TableHeader>
|
||||||
|
<TableRow v-for="headerGroup in table.getHeaderGroups()" :key="headerGroup.id">
|
||||||
|
<TableHead v-for="header in headerGroup.headers" :key="header.id">
|
||||||
|
<FlexRender v-if="!header.isPlaceholder" :render="header.column.columnDef.header"
|
||||||
|
:props="header.getContext()" />
|
||||||
|
</TableHead>
|
||||||
|
</TableRow>
|
||||||
|
</TableHeader>
|
||||||
|
<TableBody>
|
||||||
|
<template v-if="table.getRowModel().rows?.length">
|
||||||
|
<template v-for="row in table.getRowModel().rows" :key="row.id">
|
||||||
|
<TableRow :data-state="row.getIsSelected() ? 'selected' : undefined">
|
||||||
|
<TableCell v-for="cell in row.getVisibleCells()" :key="cell.id">
|
||||||
|
<FlexRender :render="cell.column.columnDef.cell" :props="cell.getContext()" />
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
<TableRow v-if="row.getIsExpanded()">
|
||||||
|
<TableCell :colspan="row.getAllCells().length">
|
||||||
|
{{ JSON.stringify(row.original) }}
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell :colSpan="columns.length" class="h-24 text-center">
|
||||||
|
No results.
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</template>
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Add the expand action to the `DataTableDropDown.vue` component
|
||||||
|
|
||||||
|
```vue:line-numbers {12-14,34-36}
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { MoreHorizontal } from 'lucide-vue-next'
|
||||||
|
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger } from '@/components/ui/dropdown-menu'
|
||||||
|
import { Button } from '@/components/ui/button'
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
payment: {
|
||||||
|
id: string
|
||||||
|
}
|
||||||
|
}>()
|
||||||
|
|
||||||
|
defineEmits<{
|
||||||
|
(e: 'expand'): void
|
||||||
|
}>()
|
||||||
|
|
||||||
|
function copy(id: string) {
|
||||||
|
navigator.clipboard.writeText(id)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<DropdownMenu>
|
||||||
|
<DropdownMenuTrigger as-child>
|
||||||
|
<Button variant="ghost" class="w-8 h-8 p-0">
|
||||||
|
<span class="sr-only">Open menu</span>
|
||||||
|
<MoreHorizontal class="w-4 h-4" />
|
||||||
|
</Button>
|
||||||
|
</DropdownMenuTrigger>
|
||||||
|
<DropdownMenuContent align="end">
|
||||||
|
<DropdownMenuLabel>Actions</DropdownMenuLabel>
|
||||||
|
<DropdownMenuItem @click="copy(payment.id)">
|
||||||
|
Copy payment ID
|
||||||
|
</DropdownMenuItem>
|
||||||
|
<DropdownMenuItem @click="$emit('expand')">
|
||||||
|
Expand
|
||||||
|
</DropdownMenuItem>
|
||||||
|
<DropdownMenuSeparator />
|
||||||
|
<DropdownMenuItem>View customer</DropdownMenuItem>
|
||||||
|
<DropdownMenuItem>View payment details</DropdownMenuItem>
|
||||||
|
</DropdownMenuContent>
|
||||||
|
</DropdownMenu>
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Make rows expandable
|
||||||
|
|
||||||
|
Now we can update the action cell to add the expand control.
|
||||||
|
|
||||||
|
```vue:line-numbers {11}
|
||||||
|
<script setup lang="ts">
|
||||||
|
export const columns: ColumnDef<Payment>[] = [
|
||||||
|
{
|
||||||
|
id: 'actions',
|
||||||
|
enableHiding: false,
|
||||||
|
cell: ({ row }) => {
|
||||||
|
const payment = row.original
|
||||||
|
|
||||||
|
return h('div', { class: 'relative' }, h(DropdownAction, {
|
||||||
|
payment,
|
||||||
|
onExpand: row.toggleExpanded,
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
</script>
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
</Steps>
|
</Steps>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type {
|
import type {
|
||||||
ColumnFiltersState,
|
ColumnFiltersState,
|
||||||
|
ExpandedState,
|
||||||
SortingState,
|
SortingState,
|
||||||
VisibilityState,
|
VisibilityState,
|
||||||
} from '@tanstack/vue-table'
|
} from '@tanstack/vue-table'
|
||||||
|
|
@ -8,10 +9,10 @@ import {
|
||||||
FlexRender,
|
FlexRender,
|
||||||
createColumnHelper,
|
createColumnHelper,
|
||||||
getCoreRowModel,
|
getCoreRowModel,
|
||||||
|
getExpandedRowModel,
|
||||||
getFilteredRowModel,
|
getFilteredRowModel,
|
||||||
getPaginationRowModel,
|
getPaginationRowModel,
|
||||||
getSortedRowModel,
|
getSortedRowModel,
|
||||||
|
|
||||||
useVueTable,
|
useVueTable,
|
||||||
} from '@tanstack/vue-table'
|
} from '@tanstack/vue-table'
|
||||||
import { ArrowUpDown, ChevronDown } from 'lucide-vue-next'
|
import { ArrowUpDown, ChevronDown } from 'lucide-vue-next'
|
||||||
|
|
@ -133,6 +134,7 @@ const columns = [
|
||||||
|
|
||||||
return h('div', { class: 'relative' }, h(DropdownAction, {
|
return h('div', { class: 'relative' }, h(DropdownAction, {
|
||||||
payment,
|
payment,
|
||||||
|
onExpand: row.toggleExpanded,
|
||||||
}))
|
}))
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|
@ -142,6 +144,7 @@ const sorting = ref<SortingState>([])
|
||||||
const columnFilters = ref<ColumnFiltersState>([])
|
const columnFilters = ref<ColumnFiltersState>([])
|
||||||
const columnVisibility = ref<VisibilityState>({})
|
const columnVisibility = ref<VisibilityState>({})
|
||||||
const rowSelection = ref({})
|
const rowSelection = ref({})
|
||||||
|
const expanded = ref<ExpandedState>({})
|
||||||
|
|
||||||
const table = useVueTable({
|
const table = useVueTable({
|
||||||
data,
|
data,
|
||||||
|
|
@ -150,15 +153,18 @@ const table = useVueTable({
|
||||||
getPaginationRowModel: getPaginationRowModel(),
|
getPaginationRowModel: getPaginationRowModel(),
|
||||||
getSortedRowModel: getSortedRowModel(),
|
getSortedRowModel: getSortedRowModel(),
|
||||||
getFilteredRowModel: getFilteredRowModel(),
|
getFilteredRowModel: getFilteredRowModel(),
|
||||||
|
getExpandedRowModel: getExpandedRowModel(),
|
||||||
onSortingChange: updaterOrValue => valueUpdater(updaterOrValue, sorting),
|
onSortingChange: updaterOrValue => valueUpdater(updaterOrValue, sorting),
|
||||||
onColumnFiltersChange: updaterOrValue => valueUpdater(updaterOrValue, columnFilters),
|
onColumnFiltersChange: updaterOrValue => valueUpdater(updaterOrValue, columnFilters),
|
||||||
onColumnVisibilityChange: updaterOrValue => valueUpdater(updaterOrValue, columnVisibility),
|
onColumnVisibilityChange: updaterOrValue => valueUpdater(updaterOrValue, columnVisibility),
|
||||||
onRowSelectionChange: updaterOrValue => valueUpdater(updaterOrValue, rowSelection),
|
onRowSelectionChange: updaterOrValue => valueUpdater(updaterOrValue, rowSelection),
|
||||||
|
onExpandedChange: updaterOrValue => valueUpdater(updaterOrValue, expanded),
|
||||||
state: {
|
state: {
|
||||||
get sorting() { return sorting.value },
|
get sorting() { return sorting.value },
|
||||||
get columnFilters() { return columnFilters.value },
|
get columnFilters() { return columnFilters.value },
|
||||||
get columnVisibility() { return columnVisibility.value },
|
get columnVisibility() { return columnVisibility.value },
|
||||||
get rowSelection() { return rowSelection.value },
|
get rowSelection() { return rowSelection.value },
|
||||||
|
get expanded() { return expanded.value },
|
||||||
columnPinning: {
|
columnPinning: {
|
||||||
left: ['status'],
|
left: ['status'],
|
||||||
},
|
},
|
||||||
|
|
@ -213,11 +219,8 @@ const table = useVueTable({
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
<template v-if="table.getRowModel().rows?.length">
|
<template v-if="table.getRowModel().rows?.length">
|
||||||
<TableRow
|
<template v-for="row in table.getRowModel().rows" :key="row.id">
|
||||||
v-for="row in table.getRowModel().rows"
|
<TableRow :data-state="row.getIsSelected() && 'selected'">
|
||||||
:key="row.id"
|
|
||||||
:data-state="row.getIsSelected() && 'selected'"
|
|
||||||
>
|
|
||||||
<TableCell
|
<TableCell
|
||||||
v-for="cell in row.getVisibleCells()" :key="cell.id" :data-pinned="cell.column.getIsPinned()"
|
v-for="cell in row.getVisibleCells()" :key="cell.id" :data-pinned="cell.column.getIsPinned()"
|
||||||
:class="cn(
|
:class="cn(
|
||||||
|
|
@ -228,6 +231,12 @@ const table = useVueTable({
|
||||||
<FlexRender :render="cell.column.columnDef.cell" :props="cell.getContext()" />
|
<FlexRender :render="cell.column.columnDef.cell" :props="cell.getContext()" />
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
|
<TableRow v-if="row.getIsExpanded()">
|
||||||
|
<TableCell :colspan="row.getAllCells().length">
|
||||||
|
{{ row.original }}
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</template>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<TableRow v-else>
|
<TableRow v-else>
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,14 @@
|
||||||
import type {
|
import type {
|
||||||
ColumnDef,
|
ColumnDef,
|
||||||
ColumnFiltersState,
|
ColumnFiltersState,
|
||||||
|
ExpandedState,
|
||||||
SortingState,
|
SortingState,
|
||||||
VisibilityState,
|
VisibilityState,
|
||||||
} from '@tanstack/vue-table'
|
} from '@tanstack/vue-table'
|
||||||
import {
|
import {
|
||||||
FlexRender,
|
FlexRender,
|
||||||
getCoreRowModel,
|
getCoreRowModel,
|
||||||
|
getExpandedRowModel,
|
||||||
getFilteredRowModel,
|
getFilteredRowModel,
|
||||||
getPaginationRowModel,
|
getPaginationRowModel,
|
||||||
getSortedRowModel,
|
getSortedRowModel,
|
||||||
|
|
@ -130,6 +132,7 @@ const columns: ColumnDef<Payment>[] = [
|
||||||
|
|
||||||
return h('div', { class: 'relative' }, h(DropdownAction, {
|
return h('div', { class: 'relative' }, h(DropdownAction, {
|
||||||
payment,
|
payment,
|
||||||
|
onExpand: row.toggleExpanded,
|
||||||
}))
|
}))
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -139,6 +142,7 @@ const sorting = ref<SortingState>([])
|
||||||
const columnFilters = ref<ColumnFiltersState>([])
|
const columnFilters = ref<ColumnFiltersState>([])
|
||||||
const columnVisibility = ref<VisibilityState>({})
|
const columnVisibility = ref<VisibilityState>({})
|
||||||
const rowSelection = ref({})
|
const rowSelection = ref({})
|
||||||
|
const expanded = ref<ExpandedState>({})
|
||||||
|
|
||||||
const table = useVueTable({
|
const table = useVueTable({
|
||||||
data,
|
data,
|
||||||
|
|
@ -147,15 +151,18 @@ const table = useVueTable({
|
||||||
getPaginationRowModel: getPaginationRowModel(),
|
getPaginationRowModel: getPaginationRowModel(),
|
||||||
getSortedRowModel: getSortedRowModel(),
|
getSortedRowModel: getSortedRowModel(),
|
||||||
getFilteredRowModel: getFilteredRowModel(),
|
getFilteredRowModel: getFilteredRowModel(),
|
||||||
|
getExpandedRowModel: getExpandedRowModel(),
|
||||||
onSortingChange: updaterOrValue => valueUpdater(updaterOrValue, sorting),
|
onSortingChange: updaterOrValue => valueUpdater(updaterOrValue, sorting),
|
||||||
onColumnFiltersChange: updaterOrValue => valueUpdater(updaterOrValue, columnFilters),
|
onColumnFiltersChange: updaterOrValue => valueUpdater(updaterOrValue, columnFilters),
|
||||||
onColumnVisibilityChange: updaterOrValue => valueUpdater(updaterOrValue, columnVisibility),
|
onColumnVisibilityChange: updaterOrValue => valueUpdater(updaterOrValue, columnVisibility),
|
||||||
onRowSelectionChange: updaterOrValue => valueUpdater(updaterOrValue, rowSelection),
|
onRowSelectionChange: updaterOrValue => valueUpdater(updaterOrValue, rowSelection),
|
||||||
|
onExpandedChange: updaterOrValue => valueUpdater(updaterOrValue, expanded),
|
||||||
state: {
|
state: {
|
||||||
get sorting() { return sorting.value },
|
get sorting() { return sorting.value },
|
||||||
get columnFilters() { return columnFilters.value },
|
get columnFilters() { return columnFilters.value },
|
||||||
get columnVisibility() { return columnVisibility.value },
|
get columnVisibility() { return columnVisibility.value },
|
||||||
get rowSelection() { return rowSelection.value },
|
get rowSelection() { return rowSelection.value },
|
||||||
|
get expanded() { return expanded.value },
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
@ -201,15 +208,18 @@ const table = useVueTable({
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
<template v-if="table.getRowModel().rows?.length">
|
<template v-if="table.getRowModel().rows?.length">
|
||||||
<TableRow
|
<template v-for="row in table.getRowModel().rows" :key="row.id">
|
||||||
v-for="row in table.getRowModel().rows"
|
<TableRow :data-state="row.getIsSelected() && 'selected'">
|
||||||
:key="row.id"
|
|
||||||
:data-state="row.getIsSelected() && 'selected'"
|
|
||||||
>
|
|
||||||
<TableCell v-for="cell in row.getVisibleCells()" :key="cell.id">
|
<TableCell v-for="cell in row.getVisibleCells()" :key="cell.id">
|
||||||
<FlexRender :render="cell.column.columnDef.cell" :props="cell.getContext()" />
|
<FlexRender :render="cell.column.columnDef.cell" :props="cell.getContext()" />
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
|
<TableRow v-if="row.getIsExpanded()">
|
||||||
|
<TableCell :colspan="row.getAllCells().length">
|
||||||
|
{{ JSON.stringify(row.original) }}
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</template>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<TableRow v-else>
|
<TableRow v-else>
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,10 @@ defineProps<{
|
||||||
}
|
}
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
defineEmits<{
|
||||||
|
(e: 'expand'): void
|
||||||
|
}>()
|
||||||
|
|
||||||
function copy(id: string) {
|
function copy(id: string) {
|
||||||
navigator.clipboard.writeText(id)
|
navigator.clipboard.writeText(id)
|
||||||
}
|
}
|
||||||
|
|
@ -27,6 +31,9 @@ function copy(id: string) {
|
||||||
<DropdownMenuItem @click="copy(payment.id)">
|
<DropdownMenuItem @click="copy(payment.id)">
|
||||||
Copy payment ID
|
Copy payment ID
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
|
<DropdownMenuItem @click="$emit('expand')">
|
||||||
|
Expand
|
||||||
|
</DropdownMenuItem>
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
<DropdownMenuItem>View customer</DropdownMenuItem>
|
<DropdownMenuItem>View customer</DropdownMenuItem>
|
||||||
<DropdownMenuItem>View payment details</DropdownMenuItem>
|
<DropdownMenuItem>View payment details</DropdownMenuItem>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type {
|
import type {
|
||||||
ColumnFiltersState,
|
ColumnFiltersState,
|
||||||
|
ExpandedState,
|
||||||
SortingState,
|
SortingState,
|
||||||
VisibilityState,
|
VisibilityState,
|
||||||
} from '@tanstack/vue-table'
|
} from '@tanstack/vue-table'
|
||||||
|
|
@ -8,10 +9,10 @@ import {
|
||||||
FlexRender,
|
FlexRender,
|
||||||
createColumnHelper,
|
createColumnHelper,
|
||||||
getCoreRowModel,
|
getCoreRowModel,
|
||||||
|
getExpandedRowModel,
|
||||||
getFilteredRowModel,
|
getFilteredRowModel,
|
||||||
getPaginationRowModel,
|
getPaginationRowModel,
|
||||||
getSortedRowModel,
|
getSortedRowModel,
|
||||||
|
|
||||||
useVueTable,
|
useVueTable,
|
||||||
} from '@tanstack/vue-table'
|
} from '@tanstack/vue-table'
|
||||||
import { CaretSortIcon, ChevronDownIcon } from '@radix-icons/vue'
|
import { CaretSortIcon, ChevronDownIcon } from '@radix-icons/vue'
|
||||||
|
|
@ -133,6 +134,7 @@ const columns = [
|
||||||
|
|
||||||
return h('div', { class: 'relative' }, h(DropdownAction, {
|
return h('div', { class: 'relative' }, h(DropdownAction, {
|
||||||
payment,
|
payment,
|
||||||
|
onExpand: row.toggleExpanded,
|
||||||
}))
|
}))
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|
@ -142,6 +144,7 @@ const sorting = ref<SortingState>([])
|
||||||
const columnFilters = ref<ColumnFiltersState>([])
|
const columnFilters = ref<ColumnFiltersState>([])
|
||||||
const columnVisibility = ref<VisibilityState>({})
|
const columnVisibility = ref<VisibilityState>({})
|
||||||
const rowSelection = ref({})
|
const rowSelection = ref({})
|
||||||
|
const expanded = ref<ExpandedState>({})
|
||||||
|
|
||||||
const table = useVueTable({
|
const table = useVueTable({
|
||||||
data,
|
data,
|
||||||
|
|
@ -150,15 +153,18 @@ const table = useVueTable({
|
||||||
getPaginationRowModel: getPaginationRowModel(),
|
getPaginationRowModel: getPaginationRowModel(),
|
||||||
getSortedRowModel: getSortedRowModel(),
|
getSortedRowModel: getSortedRowModel(),
|
||||||
getFilteredRowModel: getFilteredRowModel(),
|
getFilteredRowModel: getFilteredRowModel(),
|
||||||
|
getExpandedRowModel: getExpandedRowModel(),
|
||||||
onSortingChange: updaterOrValue => valueUpdater(updaterOrValue, sorting),
|
onSortingChange: updaterOrValue => valueUpdater(updaterOrValue, sorting),
|
||||||
onColumnFiltersChange: updaterOrValue => valueUpdater(updaterOrValue, columnFilters),
|
onColumnFiltersChange: updaterOrValue => valueUpdater(updaterOrValue, columnFilters),
|
||||||
onColumnVisibilityChange: updaterOrValue => valueUpdater(updaterOrValue, columnVisibility),
|
onColumnVisibilityChange: updaterOrValue => valueUpdater(updaterOrValue, columnVisibility),
|
||||||
onRowSelectionChange: updaterOrValue => valueUpdater(updaterOrValue, rowSelection),
|
onRowSelectionChange: updaterOrValue => valueUpdater(updaterOrValue, rowSelection),
|
||||||
|
onExpandedChange: updaterOrValue => valueUpdater(updaterOrValue, expanded),
|
||||||
state: {
|
state: {
|
||||||
get sorting() { return sorting.value },
|
get sorting() { return sorting.value },
|
||||||
get columnFilters() { return columnFilters.value },
|
get columnFilters() { return columnFilters.value },
|
||||||
get columnVisibility() { return columnVisibility.value },
|
get columnVisibility() { return columnVisibility.value },
|
||||||
get rowSelection() { return rowSelection.value },
|
get rowSelection() { return rowSelection.value },
|
||||||
|
get expanded() { return expanded.value },
|
||||||
columnPinning: {
|
columnPinning: {
|
||||||
left: ['status'],
|
left: ['status'],
|
||||||
},
|
},
|
||||||
|
|
@ -213,11 +219,8 @@ const table = useVueTable({
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
<template v-if="table.getRowModel().rows?.length">
|
<template v-if="table.getRowModel().rows?.length">
|
||||||
<TableRow
|
<template v-for="row in table.getRowModel().rows" :key="row.id">
|
||||||
v-for="row in table.getRowModel().rows"
|
<TableRow :data-state="row.getIsSelected() && 'selected'">
|
||||||
:key="row.id"
|
|
||||||
:data-state="row.getIsSelected() && 'selected'"
|
|
||||||
>
|
|
||||||
<TableCell
|
<TableCell
|
||||||
v-for="cell in row.getVisibleCells()" :key="cell.id" :data-pinned="cell.column.getIsPinned()"
|
v-for="cell in row.getVisibleCells()" :key="cell.id" :data-pinned="cell.column.getIsPinned()"
|
||||||
:class="cn(
|
:class="cn(
|
||||||
|
|
@ -228,6 +231,12 @@ const table = useVueTable({
|
||||||
<FlexRender :render="cell.column.columnDef.cell" :props="cell.getContext()" />
|
<FlexRender :render="cell.column.columnDef.cell" :props="cell.getContext()" />
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
|
<TableRow v-if="row.getIsExpanded()">
|
||||||
|
<TableCell :colspan="row.getAllCells().length">
|
||||||
|
{{ JSON.stringify(row.original) }}
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</template>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<TableRow v-else>
|
<TableRow v-else>
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,14 @@
|
||||||
import type {
|
import type {
|
||||||
ColumnDef,
|
ColumnDef,
|
||||||
ColumnFiltersState,
|
ColumnFiltersState,
|
||||||
|
ExpandedState,
|
||||||
SortingState,
|
SortingState,
|
||||||
VisibilityState,
|
VisibilityState,
|
||||||
} from '@tanstack/vue-table'
|
} from '@tanstack/vue-table'
|
||||||
import {
|
import {
|
||||||
FlexRender,
|
FlexRender,
|
||||||
getCoreRowModel,
|
getCoreRowModel,
|
||||||
|
getExpandedRowModel,
|
||||||
getFilteredRowModel,
|
getFilteredRowModel,
|
||||||
getPaginationRowModel,
|
getPaginationRowModel,
|
||||||
getSortedRowModel,
|
getSortedRowModel,
|
||||||
|
|
@ -130,6 +132,7 @@ const columns: ColumnDef<Payment>[] = [
|
||||||
|
|
||||||
return h(DropdownAction, {
|
return h(DropdownAction, {
|
||||||
payment,
|
payment,
|
||||||
|
onExpand: row.toggleExpanded,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -139,6 +142,7 @@ const sorting = ref<SortingState>([])
|
||||||
const columnFilters = ref<ColumnFiltersState>([])
|
const columnFilters = ref<ColumnFiltersState>([])
|
||||||
const columnVisibility = ref<VisibilityState>({})
|
const columnVisibility = ref<VisibilityState>({})
|
||||||
const rowSelection = ref({})
|
const rowSelection = ref({})
|
||||||
|
const expanded = ref<ExpandedState>({})
|
||||||
|
|
||||||
const table = useVueTable({
|
const table = useVueTable({
|
||||||
data,
|
data,
|
||||||
|
|
@ -147,15 +151,18 @@ const table = useVueTable({
|
||||||
getPaginationRowModel: getPaginationRowModel(),
|
getPaginationRowModel: getPaginationRowModel(),
|
||||||
getSortedRowModel: getSortedRowModel(),
|
getSortedRowModel: getSortedRowModel(),
|
||||||
getFilteredRowModel: getFilteredRowModel(),
|
getFilteredRowModel: getFilteredRowModel(),
|
||||||
|
getExpandedRowModel: getExpandedRowModel(),
|
||||||
onSortingChange: updaterOrValue => valueUpdater(updaterOrValue, sorting),
|
onSortingChange: updaterOrValue => valueUpdater(updaterOrValue, sorting),
|
||||||
onColumnFiltersChange: updaterOrValue => valueUpdater(updaterOrValue, columnFilters),
|
onColumnFiltersChange: updaterOrValue => valueUpdater(updaterOrValue, columnFilters),
|
||||||
onColumnVisibilityChange: updaterOrValue => valueUpdater(updaterOrValue, columnVisibility),
|
onColumnVisibilityChange: updaterOrValue => valueUpdater(updaterOrValue, columnVisibility),
|
||||||
onRowSelectionChange: updaterOrValue => valueUpdater(updaterOrValue, rowSelection),
|
onRowSelectionChange: updaterOrValue => valueUpdater(updaterOrValue, rowSelection),
|
||||||
|
onExpandedChange: updaterOrValue => valueUpdater(updaterOrValue, expanded),
|
||||||
state: {
|
state: {
|
||||||
get sorting() { return sorting.value },
|
get sorting() { return sorting.value },
|
||||||
get columnFilters() { return columnFilters.value },
|
get columnFilters() { return columnFilters.value },
|
||||||
get columnVisibility() { return columnVisibility.value },
|
get columnVisibility() { return columnVisibility.value },
|
||||||
get rowSelection() { return rowSelection.value },
|
get rowSelection() { return rowSelection.value },
|
||||||
|
get expanded() { return expanded.value },
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
@ -201,15 +208,18 @@ const table = useVueTable({
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
<template v-if="table.getRowModel().rows?.length">
|
<template v-if="table.getRowModel().rows?.length">
|
||||||
<TableRow
|
<template v-for="row in table.getRowModel().rows" :key="row.id">
|
||||||
v-for="row in table.getRowModel().rows"
|
<TableRow :data-state="row.getIsSelected() && 'selected'">
|
||||||
:key="row.id"
|
|
||||||
:data-state="row.getIsSelected() && 'selected'"
|
|
||||||
>
|
|
||||||
<TableCell v-for="cell in row.getVisibleCells()" :key="cell.id">
|
<TableCell v-for="cell in row.getVisibleCells()" :key="cell.id">
|
||||||
<FlexRender :render="cell.column.columnDef.cell" :props="cell.getContext()" />
|
<FlexRender :render="cell.column.columnDef.cell" :props="cell.getContext()" />
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
|
<TableRow v-if="row.getIsExpanded()">
|
||||||
|
<TableCell :colspan="row.getAllCells().length">
|
||||||
|
{{ JSON.stringify(row.original) }}
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</template>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<TableRow v-else>
|
<TableRow v-else>
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,10 @@ defineProps<{
|
||||||
}
|
}
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
defineEmits<{
|
||||||
|
(e: 'expand'): void
|
||||||
|
}>()
|
||||||
|
|
||||||
function copy(id: string) {
|
function copy(id: string) {
|
||||||
navigator.clipboard.writeText(id)
|
navigator.clipboard.writeText(id)
|
||||||
}
|
}
|
||||||
|
|
@ -27,6 +31,9 @@ function copy(id: string) {
|
||||||
<DropdownMenuItem @click="copy(payment.id)">
|
<DropdownMenuItem @click="copy(payment.id)">
|
||||||
Copy payment ID
|
Copy payment ID
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
|
<DropdownMenuItem @click="$emit('expand')">
|
||||||
|
Expand
|
||||||
|
</DropdownMenuItem>
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
<DropdownMenuItem>View customer</DropdownMenuItem>
|
<DropdownMenuItem>View customer</DropdownMenuItem>
|
||||||
<DropdownMenuItem>View payment details</DropdownMenuItem>
|
<DropdownMenuItem>View payment details</DropdownMenuItem>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user