Skip to content

Commit 7bb38fd

Browse files
committed
fix: column sort indications reflect truth ma-4062
1 parent fc25b31 commit 7bb38fd

File tree

6 files changed

+83
-40
lines changed

6 files changed

+83
-40
lines changed

docs/components/table-data.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ interface TableDataHeader {
3838
label: string
3939
/** 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 */
4040
sortable?: boolean
41+
/** When provided, determines the intial arrow direction on the column header, if more than one header has this value only the first is applied */
42+
initialSort?: 'asc' | 'desc'
4143
/** allow toggling column visibility */
4244
hidable?: boolean
4345
/** when provided, an info icon will be rendered next to the column label, upon hovering on which the tooltip will be revealed */

docs/components/table-view.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ interface TableViewHeader {
3434
label: string
3535
/** 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 */
3636
sortable?: boolean
37+
/** When provided, determines the intial arrow direction on the column header, if more than one header has this value only the first is applied */
38+
initialSort?: 'asc' | 'desc'
3739
/** allow toggling column visibility */
3840
hidable?: boolean
3941
/** when provided, an info icon will be rendered next to the column label, upon hovering on which the tooltip will be revealed */

sandbox/pages/SandboxTableData.vue

Lines changed: 46 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
<SandboxSectionComponent title="rowHover & maxHeight & clientSort & sortHandlerFunction & sortable">
1313
<KComponent
1414
v-slot="{ data }"
15-
:data="{ tableKey: 0, tableRowHover: false, tableSortable: true }"
15+
:data="{ tableKey: 0, tableRowHover: false, tableSortable: true, usernameSortable: true, initialSort: true }"
1616
>
1717
<div class="horizontal-container">
1818
<KInputSwitch
@@ -22,7 +22,19 @@
2222
/>
2323
<KInputSwitch
2424
v-model="data.tableSortable"
25-
label="Sortable"
25+
label="Table sortable"
26+
@change="data.tableKey++"
27+
/>
28+
<KInputSwitch
29+
v-model="data.usernameSortable"
30+
:disabled="!data.tableSortable"
31+
label="Username sortable"
32+
@change="data.tableKey++"
33+
/>
34+
<KInputSwitch
35+
v-model="data.initialSort"
36+
:disabled="!data.tableSortable || !data.usernameSortable"
37+
label="Username has initial sort"
2638
@change="data.tableKey++"
2739
/>
2840
</div>
@@ -31,7 +43,10 @@
3143
:key="data.tableKey"
3244
client-sort
3345
:fetcher="fetcher"
34-
:headers="headers(false, true)"
46+
:headers="headers(false, data.usernameSortable, false, data.initialSort)"
47+
:initial-fetcher-params="data.tableSortable && data.usernameSortable && data.initialSort
48+
? { sortColumnKey: 'username', sortColumnOrder: 'asc' }
49+
: {}"
3550
max-height="300"
3651
:row-hover="data.tableRowHover"
3752
:sort-handler-function="sortHandlerFunction"
@@ -49,7 +64,7 @@
4964
>
5065
<KComponent
5166
v-slot="{ data }"
52-
:data="{ tableKey: 0, tableLoadingState: false, tableErrorState: false }"
67+
:data="{ tableKey: 0, tableLoadingState: false, tableErrorState: false, tableEmptyState: false }"
5368
>
5469
<div class="horizontal-container">
5570
<KInputSwitch
@@ -438,33 +453,49 @@ import type { TableDataHeader, TableViewData, RowLink, RowBulkAction, RowActions
438453
import SandboxTableViewActions from './SandboxTableView/SandboxTableViewActions.vue'
439454
import { AddIcon } from '@kong/icons'
440455
441-
const headers = (hidable: boolean = false, sortable: boolean = false, bulkActions: boolean = false): TableDataHeader[] => {
456+
const headers = (
457+
hidable: boolean = false,
458+
sortable: boolean = false,
459+
bulkActions: boolean = false,
460+
hasInitialSort: boolean = false,
461+
): TableDataHeader[] => {
442462
return [
443463
{ key: 'actions', label: 'Row actions' },
444-
{ key: 'name', label: 'Full Name' },
464+
{
465+
key: 'name',
466+
label: 'Full Name',
467+
sortable: true,
468+
useSortHandlerFunction: true,
469+
},
445470
{
446471
key: 'username',
447472
label: 'Username',
448473
tooltip: 'Columns with a tooltip.',
449474
sortable,
450475
...(sortable && { useSortHandlerFunction: true }),
476+
...(hasInitialSort && { initialSort: 'asc' }),
451477
},
452478
{ key: 'email', label: 'Email', hidable },
453479
...(bulkActions ? [{ key: 'bulkActions', label: 'Bulk actions' }] : []),
454480
]
455481
}
456482
457-
const fetcher = async (): Promise<any> => {
483+
const fetcher = async ({ sortColumnKey, sortColumnOrder }): Promise<any> => {
458484
// Fake delay
459485
await new Promise((resolve) => setTimeout(resolve, 2000))
460486
461487
const response = await fetch('https://jsonplaceholder.typicode.com/users')
462488
const responseData = await response.json()
463489
464-
return {
465-
data: responseData,
466-
total: responseData.length,
467-
}
490+
return sortColumnKey
491+
? {
492+
data: sortHandlerFunction({ key: sortColumnKey, sortColumnOrder, data: responseData }),
493+
total: responseData.length,
494+
}
495+
: {
496+
data: responseData,
497+
total: responseData.length,
498+
}
468499
}
469500
470501
const emptyFetcher = async (): Promise<any> => {
@@ -478,29 +509,11 @@ const emptyFetcher = async (): Promise<any> => {
478509
}
479510
480511
const sortHandlerFunction = ({ key, sortColumnOrder, data }: any) => {
481-
return data.sort((a: any, b: any) => {
482-
if (key === 'username') {
483-
if (sortColumnOrder === 'asc') {
484-
if (a.username > b.username) {
485-
return 1
486-
} else if (a.username < b.username) {
487-
return -1
488-
}
489-
490-
return 0
491-
} else {
492-
if (a.username > b.username) {
493-
return -1
494-
} else if (a.username < b.username) {
495-
return 1
496-
}
497-
498-
return 0
499-
}
500-
}
512+
const ascending = sortColumnOrder === 'asc'
501513
502-
return data
503-
})
514+
return data.sort((a: any, b: any) => ascending
515+
? (a[key] ?? '').localeCompare(b[key] ?? '')
516+
: (b[key] ?? '').localeCompare(a[key] ?? ''))
504517
}
505518
506519
const onRowClick = (row: any) => {

src/components/KTableView/KTableView.vue

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -212,12 +212,20 @@
212212
</template>
213213
</KTooltip>
214214

215-
<ArrowDownIcon
216-
v-if="!column.hideLabel && column.sortable && column.key !== TableViewHeaderKeys.BULK_ACTIONS && column.key !== TableViewHeaderKeys.ACTIONS"
217-
class="sort-icon"
218-
:color="`var(--kui-color-text-neutral, ${KUI_COLOR_TEXT_NEUTRAL})`"
219-
:size="KUI_ICON_SIZE_30"
220-
/>
215+
<template v-if="!column.hideLabel && column.sortable && column.key !== TableViewHeaderKeys.BULK_ACTIONS && column.key !== TableViewHeaderKeys.ACTIONS">
216+
<ArrowDownIcon
217+
v-if="column.key === sortColumnKey"
218+
class="sort-icon"
219+
:color="`var(--kui-color-text-neutral, ${KUI_COLOR_TEXT_NEUTRAL})`"
220+
:size="KUI_ICON_SIZE_30"
221+
/>
222+
<CodeIcon
223+
v-else
224+
class="sort-possible-icon"
225+
:color="`var(--kui-color-text-neutral, ${KUI_COLOR_TEXT_NEUTRAL})`"
226+
:size="KUI_ICON_SIZE_30"
227+
/>
228+
</template>
221229
</div>
222230

223231
<div
@@ -419,7 +427,7 @@ import KButton from '@/components/KButton/KButton.vue'
419427
import KEmptyState from '@/components/KEmptyState/KEmptyState.vue'
420428
import KSkeleton from '@/components/KSkeleton/KSkeleton.vue'
421429
import KTooltip from '@/components/KTooltip/KTooltip.vue'
422-
import { InfoIcon, ArrowDownIcon, MoreIcon, ChevronRightIcon } from '@kong/icons'
430+
import { InfoIcon, ArrowDownIcon, CodeIcon, MoreIcon, ChevronRightIcon } from '@kong/icons'
423431
import type {
424432
TablePreferences,
425433
TableViewHeader,
@@ -935,6 +943,13 @@ watch(() => headers, (newVal: readonly Header[]) => {
935943
headers.push(actionsHeader)
936944
}
937945
946+
const firstInitialSort = newVal.find(({ initialSort }) => initialSort)
947+
if (!sortColumnKey.value && firstInitialSort) {
948+
sortColumnKey.value = firstInitialSort.key
949+
// @ts-ignore - initialSort can't be undefined here because we filtered for it already
950+
sortColumnOrder.value = firstInitialSort.initialSort
951+
}
952+
938953
tableHeaders.value = headers
939954
}
940955
}, { deep: true, immediate: true })

src/styles/mixins/_tables.scss

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,15 @@
161161
&.sortable {
162162
cursor: pointer;
163163

164+
.sort-possible-icon {
165+
transform: rotate(90deg);
166+
}
167+
168+
.sort-icon {
169+
transform: rotate(0deg);
170+
transition: transform $kongponentsTransitionDurTimingFunc;
171+
}
172+
164173
&.asc .sort-icon {
165174
transform: rotate(-180deg);
166175
}

src/types/table.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ export interface TableViewHeader<Key extends string = string> {
7979
label?: string
8080
/** 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 */
8181
sortable?: boolean
82+
/** When provided, determines the intial arrow direction on the column */
83+
initialSort?: SortColumnOrder
8284
/** Allow toggling column visibility */
8385
hidable?: boolean
8486
/** When provided, an info icon will be rendered next to the column label, upon hovering on which the tooltip will be revealed */

0 commit comments

Comments
 (0)