mirror of
https://github.com/rustfs/console.git
synced 2026-09-24 16:30:56 +08:00
refactor: migrate all tables to DataTable component
- Migrate pages/events/index.vue to use DataTable - Migrate pages/license/index.vue feature permissions table to DataTable - Migrate components/user/* tables to DataTable (account, policies, groups) - Migrate components/user-group/* tables to DataTable (policies, members, set-policies-mutiple) - Replace native table elements and raw Table components with shared DataTable - Implement search functionality using DataTable filter capabilities - Ensure consistent table rendering across the application
This commit is contained in:
@@ -71,38 +71,22 @@
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Table class="overflow-hidden rounded-lg border">
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>{{ t('Name') }}</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody v-if="filteredMembers.length">
|
||||
<TableRow v-for="member in filteredMembers" :key="member">
|
||||
<TableCell class="font-medium">{{ member }}</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
<TableBody v-else>
|
||||
<TableRow>
|
||||
<TableCell class="text-center" colspan="1">
|
||||
<p class="py-6 text-sm text-muted-foreground">{{ t('No Data') }}</p>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
<DataTable :table="table" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Icon } from '#components'
|
||||
import DataTable from '@/components/data-table/data-table.vue'
|
||||
import { useDataTable } from '@/components/data-table/useDataTable'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent } from '@/components/ui/card'
|
||||
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from '@/components/ui/command'
|
||||
import { Field, FieldContent, FieldLabel } from '@/components/ui/field'
|
||||
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'
|
||||
import { computed, onMounted, ref, watch } from 'vue'
|
||||
import type { ColumnDef } from '@tanstack/vue-table'
|
||||
import { computed, h, onMounted, ref, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
interface UserOption {
|
||||
@@ -141,11 +125,28 @@ const userLabelMap = computed(() => {
|
||||
|
||||
const selectedUserLabels = computed(() => members.value.map(value => userLabelMap.value[value] ?? value))
|
||||
|
||||
const filteredMembers = computed(() => {
|
||||
const keyword = searchTerm.value.trim().toLowerCase()
|
||||
const source = props.group?.members ?? []
|
||||
if (!keyword) return source
|
||||
return source.filter(item => item.toLowerCase().includes(keyword))
|
||||
interface MemberItem {
|
||||
name: string
|
||||
}
|
||||
|
||||
const membersData = computed<MemberItem[]>(() => (props.group?.members ?? []).map(name => ({ name })))
|
||||
|
||||
const columns: ColumnDef<MemberItem>[] = [
|
||||
{
|
||||
id: 'name',
|
||||
header: () => t('Name'),
|
||||
cell: ({ row }) => h('span', { class: 'font-medium' }, row.original.name),
|
||||
},
|
||||
]
|
||||
|
||||
const { table } = useDataTable<MemberItem>({
|
||||
data: membersData,
|
||||
columns,
|
||||
getRowId: row => row.name,
|
||||
})
|
||||
|
||||
watch(searchTerm, value => {
|
||||
table.getColumn('name')?.setFilterValue(value || undefined)
|
||||
})
|
||||
|
||||
watch(
|
||||
|
||||
@@ -67,37 +67,21 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Table class="overflow-hidden rounded-lg border">
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>{{ t('Name') }}</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody v-if="filteredPolicies.length">
|
||||
<TableRow v-for="policy in filteredPolicies" :key="policy">
|
||||
<TableCell class="font-medium">{{ policy }}</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
<TableBody v-else>
|
||||
<TableRow>
|
||||
<TableCell class="text-center" colspan="1">
|
||||
<p class="py-6 text-sm text-muted-foreground">{{ t('No Data') }}</p>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
<DataTable :table="table" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Icon } from '#components'
|
||||
import DataTable from '@/components/data-table/data-table.vue'
|
||||
import { useDataTable } from '@/components/data-table/useDataTable'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from '@/components/ui/command'
|
||||
import { Field, FieldContent, FieldLabel } from '@/components/ui/field'
|
||||
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'
|
||||
import { computed, onMounted, ref, watch } from 'vue'
|
||||
import type { ColumnDef } from '@tanstack/vue-table'
|
||||
import { computed, h, onMounted, ref, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const { listPolicies, setUserOrGroupPolicy } = usePolicies()
|
||||
@@ -124,11 +108,28 @@ const currentPolicies = computed(() => {
|
||||
return props.group.policy.split(',').map(item => item.trim()).filter(Boolean)
|
||||
})
|
||||
|
||||
const filteredPolicies = computed(() => {
|
||||
const keyword = searchTerm.value.trim().toLowerCase()
|
||||
const source = currentPolicies.value
|
||||
if (!keyword) return source
|
||||
return source.filter(policy => policy.toLowerCase().includes(keyword))
|
||||
interface PolicyItem {
|
||||
name: string
|
||||
}
|
||||
|
||||
const policiesData = computed<PolicyItem[]>(() => currentPolicies.value.map(name => ({ name })))
|
||||
|
||||
const columns: ColumnDef<PolicyItem>[] = [
|
||||
{
|
||||
id: 'name',
|
||||
header: () => t('Name'),
|
||||
cell: ({ row }) => h('span', { class: 'font-medium' }, row.original.name),
|
||||
},
|
||||
]
|
||||
|
||||
const { table } = useDataTable<PolicyItem>({
|
||||
data: policiesData,
|
||||
columns,
|
||||
getRowId: row => row.name,
|
||||
})
|
||||
|
||||
watch(searchTerm, value => {
|
||||
table.getColumn('name')?.setFilterValue(value || undefined)
|
||||
})
|
||||
|
||||
const policyLabelMap = computed(() => {
|
||||
|
||||
@@ -10,42 +10,18 @@
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<Table class="overflow-hidden rounded-lg border">
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead class="w-12">
|
||||
<Checkbox :checked="allVisibleSelected" :indeterminate="checkedKeys.length > 0 && !allVisibleSelected"
|
||||
@update:checked="(value: boolean | 'indeterminate') => toggleSelectAll(value === true)" />
|
||||
</TableHead>
|
||||
<TableHead>{{ t('Name') }}</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody v-if="filteredPolicies.length">
|
||||
<TableRow v-for="policy in filteredPolicies" :key="policy.name">
|
||||
<TableCell>
|
||||
<Checkbox :checked="isSelected(policy.name)" @update:checked="(value: boolean | 'indeterminate') => toggleSelection(policy.name, value === true)" />
|
||||
</TableCell>
|
||||
<TableCell class="font-medium">{{ policy.name }}</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
<TableBody v-else>
|
||||
<TableRow>
|
||||
<TableCell class="text-center" colspan="2">
|
||||
<p class="py-6 text-sm text-muted-foreground">{{ t('No Data') }}</p>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
<DataTable :table="table" />
|
||||
</div>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import DataTable from '@/components/data-table/data-table.vue'
|
||||
import { useDataTable } from '@/components/data-table/useDataTable'
|
||||
import { Button } from '@/components/ui/button'
|
||||
|
||||
import { Checkbox } from '@/components/ui/checkbox'
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'
|
||||
import { computed, ref } from 'vue'
|
||||
import type { ColumnDef } from '@tanstack/vue-table'
|
||||
import { computed, h, ref, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import Modal from '~/components/modal.vue'
|
||||
|
||||
@@ -102,6 +78,44 @@ const toggleSelectAll = (checked: boolean) => {
|
||||
}
|
||||
}
|
||||
|
||||
const columns: ColumnDef<{ name: string; content: unknown }>[] = [
|
||||
{
|
||||
id: 'select',
|
||||
header: () =>
|
||||
h(Checkbox, {
|
||||
checked: allVisibleSelected.value,
|
||||
indeterminate: checkedKeys.value.length > 0 && !allVisibleSelected.value,
|
||||
onUpdateChecked: (value: boolean | 'indeterminate') => toggleSelectAll(value === true),
|
||||
}),
|
||||
enableSorting: false,
|
||||
cell: ({ row }) =>
|
||||
h(Checkbox, {
|
||||
checked: isSelected(row.original.name),
|
||||
onUpdateChecked: (value: boolean | 'indeterminate') => toggleSelection(row.original.name, value === true),
|
||||
}),
|
||||
meta: { maxWidth: '3rem' },
|
||||
},
|
||||
{
|
||||
id: 'name',
|
||||
header: () => t('Name'),
|
||||
cell: ({ row }) => h('span', { class: 'font-medium' }, row.original.name),
|
||||
filterFn: (row, _columnId, filterValue) => {
|
||||
if (!filterValue) return true
|
||||
return row.original.name.toLowerCase().includes(String(filterValue).toLowerCase())
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
const { table } = useDataTable<{ name: string; content: unknown }>({
|
||||
data: filteredPolicies,
|
||||
columns,
|
||||
getRowId: row => row.name,
|
||||
})
|
||||
|
||||
watch(searchTerm, value => {
|
||||
table.getColumn('name')?.setFilterValue(value || undefined)
|
||||
})
|
||||
|
||||
const loadPolicies = async () => {
|
||||
try {
|
||||
const res = await listPolicies()
|
||||
|
||||
+77
-51
@@ -12,51 +12,7 @@
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<Table class="overflow-hidden rounded-lg border">
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead class="text-center">{{ t('Access Key') }}</TableHead>
|
||||
<TableHead class="text-center">{{ t('Expiration') }}</TableHead>
|
||||
<TableHead class="text-center">{{ t('Status') }}</TableHead>
|
||||
<TableHead class="text-center">{{ t('Name') }}</TableHead>
|
||||
<TableHead class="w-32 text-center">{{ t('Actions') }}</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody v-if="filteredAccounts.length">
|
||||
<TableRow v-for="account in filteredAccounts" :key="account.accessKey">
|
||||
<TableCell class="text-center font-medium">{{ account.accessKey }}</TableCell>
|
||||
<TableCell class="text-center">{{ formatExpiration(account.expiration) }}</TableCell>
|
||||
<TableCell class="text-center">
|
||||
<span class="text-sm">
|
||||
{{ account.accountStatus === 'on' ? t('Available') : t('Disabled') }}
|
||||
</span>
|
||||
</TableCell>
|
||||
<TableCell class="text-center">{{ account.name || '-' }}</TableCell>
|
||||
<TableCell>
|
||||
<div class="flex justify-center gap-2">
|
||||
<Button variant="outline" size="sm" class="h-8 w-8 p-0" @click="openEditItem(account)">
|
||||
<Icon class="size-4" name="ri:edit-2-line" />
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
class="h-8 w-8 p-0 text-destructive border-destructive"
|
||||
@click="confirmDelete(account)"
|
||||
>
|
||||
<Icon class="size-4" name="ri:delete-bin-5-line" />
|
||||
</Button>
|
||||
</div>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
<TableBody v-else>
|
||||
<TableRow>
|
||||
<TableCell class="text-center" colspan="5">
|
||||
<p class="py-6 text-sm text-muted-foreground">{{ t('No Data') }}</p>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
<DataTable :table="table" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -134,13 +90,15 @@ import { Button } from '@/components/ui/button'
|
||||
import { Input } from '@/components/ui/input'
|
||||
|
||||
import { Icon } from '#components'
|
||||
import DataTable from '@/components/data-table/data-table.vue'
|
||||
import { useDataTable } from '@/components/data-table/useDataTable'
|
||||
import DateTimePicker from '@/components/datetime-picker.vue'
|
||||
import { Field, FieldContent, FieldLabel } from '@/components/ui/field'
|
||||
import { Switch } from '@/components/ui/switch'
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'
|
||||
import { Textarea } from '@/components/ui/textarea'
|
||||
import type { ColumnDef } from '@tanstack/vue-table'
|
||||
import dayjs from 'dayjs'
|
||||
import { computed, reactive, ref, watch } from 'vue'
|
||||
import { computed, h, reactive, ref, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useDialog, useMessage } from '~/composables/ui'
|
||||
import { makeRandomString } from '~/utils/functions'
|
||||
@@ -183,10 +141,78 @@ const parentPolicy = ref('')
|
||||
|
||||
const minExpiry = computed(() => new Date().toISOString())
|
||||
|
||||
const filteredAccounts = computed(() => {
|
||||
const keyword = searchTerm.value.trim().toLowerCase()
|
||||
if (!keyword) return listData.value
|
||||
return listData.value.filter((item: any) => item.accessKey.toLowerCase().includes(keyword))
|
||||
interface AccountItem {
|
||||
accessKey: string
|
||||
expiration?: string
|
||||
accountStatus?: string
|
||||
name?: string
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
const columns: ColumnDef<AccountItem>[] = [
|
||||
{
|
||||
id: 'accessKey',
|
||||
header: () => t('Access Key'),
|
||||
cell: ({ row }) => h('span', { class: 'text-center font-medium' }, row.original.accessKey),
|
||||
},
|
||||
{
|
||||
id: 'expiration',
|
||||
header: () => t('Expiration'),
|
||||
cell: ({ row }) => h('span', { class: 'text-center' }, formatExpiration(row.original.expiration)),
|
||||
},
|
||||
{
|
||||
id: 'status',
|
||||
header: () => t('Status'),
|
||||
cell: ({ row }) =>
|
||||
h(
|
||||
'span',
|
||||
{ class: 'text-sm text-center' },
|
||||
row.original.accountStatus === 'on' ? t('Available') : t('Disabled')
|
||||
),
|
||||
},
|
||||
{
|
||||
id: 'name',
|
||||
header: () => t('Name'),
|
||||
cell: ({ row }) => h('span', { class: 'text-center' }, row.original.name || '-'),
|
||||
},
|
||||
{
|
||||
id: 'actions',
|
||||
header: () => t('Actions'),
|
||||
enableSorting: false,
|
||||
cell: ({ row }) =>
|
||||
h('div', { class: 'flex justify-center gap-2' }, [
|
||||
h(
|
||||
Button,
|
||||
{
|
||||
variant: 'outline',
|
||||
size: 'sm',
|
||||
class: 'h-8 w-8 p-0',
|
||||
onClick: () => openEditItem(row.original),
|
||||
},
|
||||
() => h(Icon, { class: 'size-4', name: 'ri:edit-2-line' })
|
||||
),
|
||||
h(
|
||||
Button,
|
||||
{
|
||||
variant: 'outline',
|
||||
size: 'sm',
|
||||
class: 'h-8 w-8 p-0 text-destructive border-destructive',
|
||||
onClick: () => confirmDelete(row.original),
|
||||
},
|
||||
() => h(Icon, { class: 'size-4', name: 'ri:delete-bin-5-line' })
|
||||
),
|
||||
]),
|
||||
},
|
||||
]
|
||||
|
||||
const { table } = useDataTable<AccountItem>({
|
||||
data: listData as any,
|
||||
columns,
|
||||
getRowId: row => row.accessKey,
|
||||
})
|
||||
|
||||
watch(searchTerm, value => {
|
||||
table.getColumn('accessKey')?.setFilterValue(value || undefined)
|
||||
})
|
||||
|
||||
const formatExpiration = (value?: string) => {
|
||||
|
||||
+27
-26
@@ -53,37 +53,21 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Table class="overflow-hidden rounded-lg border">
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>{{ t('Name') }}</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody v-if="filteredGroups.length">
|
||||
<TableRow v-for="item in filteredGroups" :key="item">
|
||||
<TableCell class="font-medium">{{ item }}</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
<TableBody v-else>
|
||||
<TableRow>
|
||||
<TableCell class="text-center" colspan="1">
|
||||
<p class="py-6 text-sm text-muted-foreground">{{ t('No Data') }}</p>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
<DataTable :table="table" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Icon } from '#components'
|
||||
import DataTable from '@/components/data-table/data-table.vue'
|
||||
import { useDataTable } from '@/components/data-table/useDataTable'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from '@/components/ui/command'
|
||||
import { Field, FieldContent, FieldLabel } from '@/components/ui/field'
|
||||
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'
|
||||
import { computed, onMounted, ref, watch } from 'vue'
|
||||
import type { ColumnDef } from '@tanstack/vue-table'
|
||||
import { computed, h, onMounted, ref, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const { t } = useI18n()
|
||||
@@ -108,11 +92,28 @@ const submitting = ref(false)
|
||||
|
||||
const currentGroups = computed(() => props.user.memberOf ?? [])
|
||||
|
||||
const filteredGroups = computed(() => {
|
||||
const keyword = searchTerm.value.trim().toLowerCase()
|
||||
const source = currentGroups.value
|
||||
if (!keyword) return source
|
||||
return source.filter(item => item.toLowerCase().includes(keyword))
|
||||
interface GroupItem {
|
||||
name: string
|
||||
}
|
||||
|
||||
const groupsData = computed<GroupItem[]>(() => currentGroups.value.map(name => ({ name })))
|
||||
|
||||
const columns: ColumnDef<GroupItem>[] = [
|
||||
{
|
||||
id: 'name',
|
||||
header: () => t('Name'),
|
||||
cell: ({ row }) => h('span', { class: 'font-medium' }, row.original.name),
|
||||
},
|
||||
]
|
||||
|
||||
const { table } = useDataTable<GroupItem>({
|
||||
data: groupsData,
|
||||
columns,
|
||||
getRowId: row => row.name,
|
||||
})
|
||||
|
||||
watch(searchTerm, value => {
|
||||
table.getColumn('name')?.setFilterValue(value || undefined)
|
||||
})
|
||||
|
||||
const groupLabelMap = computed(() => {
|
||||
|
||||
@@ -53,37 +53,21 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Table class="overflow-hidden rounded-lg border">
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>{{ t('Name') }}</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody v-if="filteredPolicies.length">
|
||||
<TableRow v-for="policy in filteredPolicies" :key="policy">
|
||||
<TableCell class="font-medium">{{ policy }}</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
<TableBody v-else>
|
||||
<TableRow>
|
||||
<TableCell class="text-center" colspan="1">
|
||||
<p class="py-6 text-sm text-muted-foreground">{{ t('No Data') }}</p>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
<DataTable :table="table" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Icon } from '#components'
|
||||
import DataTable from '@/components/data-table/data-table.vue'
|
||||
import { useDataTable } from '@/components/data-table/useDataTable'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from '@/components/ui/command'
|
||||
import { Field, FieldContent, FieldLabel } from '@/components/ui/field'
|
||||
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'
|
||||
import { computed, onMounted, ref, watch } from 'vue'
|
||||
import type { ColumnDef } from '@tanstack/vue-table'
|
||||
import { computed, h, onMounted, ref, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const { listPolicies, setUserOrGroupPolicy } = usePolicies()
|
||||
@@ -108,11 +92,28 @@ const submitting = ref(false)
|
||||
|
||||
const currentPolicies = computed(() => props.user.policy ?? [])
|
||||
|
||||
const filteredPolicies = computed(() => {
|
||||
const keyword = searchTerm.value.trim().toLowerCase()
|
||||
const source = currentPolicies.value
|
||||
if (!keyword) return source
|
||||
return source.filter(item => item.toLowerCase().includes(keyword))
|
||||
interface PolicyItem {
|
||||
name: string
|
||||
}
|
||||
|
||||
const policiesData = computed<PolicyItem[]>(() => currentPolicies.value.map(name => ({ name })))
|
||||
|
||||
const columns: ColumnDef<PolicyItem>[] = [
|
||||
{
|
||||
id: 'name',
|
||||
header: () => t('Name'),
|
||||
cell: ({ row }) => h('span', { class: 'font-medium' }, row.original.name),
|
||||
},
|
||||
]
|
||||
|
||||
const { table } = useDataTable<PolicyItem>({
|
||||
data: policiesData,
|
||||
columns,
|
||||
getRowId: row => row.name,
|
||||
})
|
||||
|
||||
watch(searchTerm, value => {
|
||||
table.getColumn('name')?.setFilterValue(value || undefined)
|
||||
})
|
||||
|
||||
const policyLabelMap = computed(() => {
|
||||
|
||||
Reference in New Issue
Block a user