Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/components/table-data.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ interface TableDataHeader {
label: string
/** this property defines whether sort icon should be displayed next to the column header and whether the column header will emit sort event upon clicking on it */
sortable?: boolean
/** When provided, determines the intial arrow direction on the column header, if more than one header has this value only the first is applied */
initialSort?: 'asc' | 'desc'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's already a sortColumnOrder prop exposed via tablePreferences - shouldn't that be sufficient?

/** allow toggling column visibility */
hidable?: boolean
/** when provided, an info icon will be rendered next to the column label, upon hovering on which the tooltip will be revealed */
Expand Down
2 changes: 2 additions & 0 deletions docs/components/table-view.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ interface TableViewHeader {
label: string
/** this property defines whether sort icon should be displayed next to the column header and whether the column header will emit sort event upon clicking on it */
sortable?: boolean
/** When provided, determines the intial arrow direction on the column header, if more than one header has this value only the first is applied */
initialSort?: 'asc' | 'desc'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's already a sortColumnOrder prop exposed via tablePreferences - shouldn't that be sufficient?

/** allow toggling column visibility */
hidable?: boolean
/** when provided, an info icon will be rendered next to the column label, upon hovering on which the tooltip will be revealed */
Expand Down
79 changes: 46 additions & 33 deletions sandbox/pages/SandboxTableData.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<SandboxSectionComponent title="rowHover & maxHeight & clientSort & sortHandlerFunction & sortable">
<KComponent
v-slot="{ data }"
:data="{ tableKey: 0, tableRowHover: false, tableSortable: true }"
:data="{ tableKey: 0, tableRowHover: false, tableSortable: true, usernameSortable: true, initialSort: true }"
>
<div class="horizontal-container">
<KInputSwitch
Expand All @@ -22,7 +22,19 @@
/>
<KInputSwitch
v-model="data.tableSortable"
label="Sortable"
label="Table sortable"
@change="data.tableKey++"
/>
<KInputSwitch
v-model="data.usernameSortable"
:disabled="!data.tableSortable"
label="Username sortable"
@change="data.tableKey++"
/>
<KInputSwitch
v-model="data.initialSort"
:disabled="!data.tableSortable || !data.usernameSortable"
label="Username has initial sort"
@change="data.tableKey++"
/>
</div>
Expand All @@ -31,7 +43,10 @@
:key="data.tableKey"
client-sort
:fetcher="fetcher"
:headers="headers(false, true)"
:headers="headers(false, data.usernameSortable, false, data.initialSort)"
:initial-fetcher-params="data.tableSortable && data.usernameSortable && data.initialSort
? { sortColumnKey: 'username', sortColumnOrder: 'asc' }
: {}"
max-height="300"
:row-hover="data.tableRowHover"
:sort-handler-function="sortHandlerFunction"
Expand All @@ -49,7 +64,7 @@
>
<KComponent
v-slot="{ data }"
:data="{ tableKey: 0, tableLoadingState: false, tableErrorState: false }"
:data="{ tableKey: 0, tableLoadingState: false, tableErrorState: false, tableEmptyState: false }"
>
<div class="horizontal-container">
<KInputSwitch
Expand Down Expand Up @@ -438,33 +453,49 @@ import type { TableDataHeader, TableViewData, RowLink, RowBulkAction, RowActions
import SandboxTableViewActions from './SandboxTableView/SandboxTableViewActions.vue'
import { AddIcon } from '@kong/icons'

const headers = (hidable: boolean = false, sortable: boolean = false, bulkActions: boolean = false): TableDataHeader[] => {
const headers = (
hidable: boolean = false,
sortable: boolean = false,
bulkActions: boolean = false,
hasInitialSort: boolean = false,
): TableDataHeader[] => {
return [
{ key: 'actions', label: 'Row actions' },
{ key: 'name', label: 'Full Name' },
{
key: 'name',
label: 'Full Name',
sortable: true,
useSortHandlerFunction: true,
},
{
key: 'username',
label: 'Username',
tooltip: 'Columns with a tooltip.',
sortable,
...(sortable && { useSortHandlerFunction: true }),
...(hasInitialSort && { initialSort: 'asc' }),
},
{ key: 'email', label: 'Email', hidable },
...(bulkActions ? [{ key: 'bulkActions', label: 'Bulk actions' }] : []),
]
}

const fetcher = async (): Promise<any> => {
const fetcher = async ({ sortColumnKey, sortColumnOrder }): Promise<any> => {
// Fake delay
await new Promise((resolve) => setTimeout(resolve, 2000))

const response = await fetch('https://jsonplaceholder.typicode.com/users')
const responseData = await response.json()

return {
data: responseData,
total: responseData.length,
}
return sortColumnKey
? {
data: sortHandlerFunction({ key: sortColumnKey, sortColumnOrder, data: responseData }),
total: responseData.length,
}
: {
data: responseData,
total: responseData.length,
}
}

const emptyFetcher = async (): Promise<any> => {
Expand All @@ -478,29 +509,11 @@ const emptyFetcher = async (): Promise<any> => {
}

const sortHandlerFunction = ({ key, sortColumnOrder, data }: any) => {
return data.sort((a: any, b: any) => {
if (key === 'username') {
if (sortColumnOrder === 'asc') {
if (a.username > b.username) {
return 1
} else if (a.username < b.username) {
return -1
}

return 0
} else {
if (a.username > b.username) {
return -1
} else if (a.username < b.username) {
return 1
}

return 0
}
}
const ascending = sortColumnOrder === 'asc'

return data
})
return data.sort((a: any, b: any) => ascending
? (a[key] ?? '').localeCompare(b[key] ?? '')
: (b[key] ?? '').localeCompare(a[key] ?? ''))
}

const onRowClick = (row: any) => {
Expand Down
29 changes: 22 additions & 7 deletions src/components/KTableView/KTableView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -212,12 +212,20 @@
</template>
</KTooltip>

<ArrowDownIcon
v-if="!column.hideLabel && column.sortable && column.key !== TableViewHeaderKeys.BULK_ACTIONS && column.key !== TableViewHeaderKeys.ACTIONS"
class="sort-icon"
:color="`var(--kui-color-text-neutral, ${KUI_COLOR_TEXT_NEUTRAL})`"
:size="KUI_ICON_SIZE_30"
/>
<template v-if="!column.hideLabel && column.sortable && column.key !== TableViewHeaderKeys.BULK_ACTIONS && column.key !== TableViewHeaderKeys.ACTIONS">
<ArrowDownIcon
v-if="column.key === sortColumnKey"
class="sort-icon"
:color="`var(--kui-color-text-neutral, ${KUI_COLOR_TEXT_NEUTRAL})`"
:size="KUI_ICON_SIZE_30"
/>
<CodeIcon
v-else
class="sort-possible-icon"
:color="`var(--kui-color-text-neutral, ${KUI_COLOR_TEXT_NEUTRAL})`"
:size="KUI_ICON_SIZE_30"
/>
</template>
</div>

<div
Expand Down Expand Up @@ -419,7 +427,7 @@ import KButton from '@/components/KButton/KButton.vue'
import KEmptyState from '@/components/KEmptyState/KEmptyState.vue'
import KSkeleton from '@/components/KSkeleton/KSkeleton.vue'
import KTooltip from '@/components/KTooltip/KTooltip.vue'
import { InfoIcon, ArrowDownIcon, MoreIcon, ChevronRightIcon } from '@kong/icons'
import { InfoIcon, ArrowDownIcon, CodeIcon, MoreIcon, ChevronRightIcon } from '@kong/icons'
import type {
TablePreferences,
TableViewHeader,
Expand Down Expand Up @@ -935,6 +943,13 @@ watch(() => headers, (newVal: readonly Header[]) => {
headers.push(actionsHeader)
}
const firstInitialSort = newVal.find(({ initialSort }) => initialSort)
if (!sortColumnKey.value && firstInitialSort) {
sortColumnKey.value = firstInitialSort.key
// @ts-ignore - initialSort can't be undefined here because we filtered for it already
sortColumnOrder.value = firstInitialSort.initialSort
}
tableHeaders.value = headers
}
}, { deep: true, immediate: true })
Expand Down
9 changes: 9 additions & 0 deletions src/styles/mixins/_tables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,15 @@
&.sortable {
cursor: pointer;

.sort-possible-icon {
transform: rotate(90deg);
}

.sort-icon {
transform: rotate(0deg);
transition: transform $kongponentsTransitionDurTimingFunc;
}

&.asc .sort-icon {
transform: rotate(-180deg);
}
Expand Down
2 changes: 2 additions & 0 deletions src/types/table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ export interface TableViewHeader<Key extends string = string> {
label?: string
/** This property defines whether sort icon should be displayed next to the column header and whether the column header will emit sort event upon clicking on it */
sortable?: boolean
/** When provided, determines the intial arrow direction on the column */
initialSort?: SortColumnOrder
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's already a sortColumnOrder prop exposed via tablePreferences - shouldn't that be sufficient?

/** Allow toggling column visibility */
hidable?: boolean
/** When provided, an info icon will be rendered next to the column label, upon hovering on which the tooltip will be revealed */
Expand Down
Loading