Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(ktableview): row-expanded prop and event [KHCP-14243] #2527

Merged
merged 6 commits into from
Nov 26, 2024
Merged
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
47 changes: 45 additions & 2 deletions docs/components/table-view.md
Original file line number Diff line number Diff line change
Expand Up @@ -754,6 +754,42 @@ Function for making a row expandable. The function receives row value object as
</KTableView>
```

### rowExpanded

Use this prop to specify initial expanded / collapsed state for each data row. The function receives row value object as an argument and should return a boolean value. Default value is `() => false`. When returned value is `true`, a row is rendered expanded.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
Use this prop to specify initial expanded / collapsed state for each data row. The function receives row value object as an argument and should return a boolean value. Default value is `() => false`. When returned value is `true`, a row is rendered expanded.
Use this prop to specifythe initial expanded / collapsed state for each data row. The function receives the row value object as an argument and should return a boolean value. Default value is `() => false`. When returned value is `true`, a row is rendered expanded.


<KTableView
:data="userTypeData"
:row-expanded="(row) => row.id === userTypeData.find((dataRow) => dataRow.type.toLowerCase() === 'external')?.id"
:row-expandable="(row) => row.type.toLowerCase() === 'external'"
:headers="userTypeHeaders"
:pagination-attributes="{ totalCount: userTypeData.length }"
>
<template #row-expanded>
Lorem ipsum odor amet, consectetuer adipiscing elit. Vitae rutrum interdum dis elementum; consequat maximus potenti felis. Faucibus eget vel, efficitur vitae ullamcorper velit. Aliquam aliquam fusce sollicitudin dolor lorem aenean. Rutrum ligula diam mollis felis egestas arcu. Odio urna leo pharetra luctus urna adipiscing suscipit nisl. Eleifend natoque lacus scelerisque suspendisse libero pulvinar ut lectus. Ac parturient fringilla lacinia fusce natoque semper.
Turpis pellentesque eu ad risus proin hendrerit litora. Sollicitudin facilisi per diam netus; at commodo ornare. Justo efficitur hendrerit augue blandit himenaeos suspendisse; mattis habitasse. Aliquet iaculis nibh ante et rutrum sollicitudin tincidunt enim. Suspendisse orci ac proin metus consectetur vel primis. Dictumst imperdiet nulla habitant donec gravida vel nulla in. Eleifend augue ligula convallis eros odio. Erat integer nibh mattis varius senectus.
Sodales nisl sem aliquet neque scelerisque. Dapibus mauris leo commodo; nulla adipiscing purus ultricies porttitor laoreet. Dignissim sociosqu cras sollicitudin iaculis magna ex. Elit lacus tincidunt dapibus adipiscing tortor eros dui felis. Orci hendrerit senectus himenaeos ligula cursus in. Turpis dignissim duis nunc neque ornare congue primis aenean natoque. Himenaeos mollis dui dolor laoreet mauris aliquam hendrerit scelerisque.
Sagittis lectus fringilla iaculis semper egestas mattis venenatis. Mollis parturient primis; pharetra leo neque faucibus nibh. Porttitor scelerisque magnis pellentesque nec vel etiam fames quisque. Senectus dictumst nisl enim sagittis primis magnis habitasse finibus torquent. Efficitur turpis hendrerit posuere dictum fusce nostra taciti donec. Parturient ut blandit ligula euismod taciti velit. Mollis urna nunc tellus; cras consequat volutpat turpis. Maximus egestas platea mauris mollis mollis conubia. Euismod scelerisque quam mauris parturient eleifend nostra. Mollis tempor hendrerit hendrerit praesent aliquet himenaeos dignissim.
Dignissim penatibus velit sapien vehicula sodales suspendisse iaculis massa. Cubilia aenean morbi scelerisque eu imperdiet odio primis. Mollis netus natoque, euismod felis tempor nibh. In nostra nulla eros ac orci suspendisse luctus porta. Parturient cras turpis faucibus ut sed nunc lacus. At et fermentum sapien tristique ac primis. Interdum vivamus orci velit sed arcu in. Eros aptent primis suscipit parturient curae enim.
Rutrum aliquam phasellus duis pellentesque torquent fermentum. Feugiat odio consequat cursus blandit tristique erat amet. Ornare scelerisque id erat lectus at erat. Dui nostra interdum tortor, turpis arcu dis. Netus fermentum lobortis primis fermentum velit ultrices nam condimentum? Dictum montes maximus senectus; quis varius scelerisque non ridiculus. Curae malesuada porttitor finibus venenatis mi faucibus. Velit blandit dis mauris laoreet ornare molestie.
Ante torquent faucibus nascetur ultricies eros varius odio. Cubilia sodales maximus tellus leo cubilia lorem facilisis. Blandit egestas suspendisse torquent dolor; torquent commodo id nullam. Etiam facilisi faucibus litora quisque aptent vestibulum dapibus. Maecenas risus fermentum facilisis suspendisse imperdiet nascetur porta. Vehicula malesuada sollicitudin viverra in ac habitasse ligula. Adipiscing porta neque nullam pharetra est luctus pharetra. Consequat sapien parturient nisl augue ultricies placerat maximus convallis. Consectetur metus lacinia; euismod mollis class tortor.
</template>
</KTableView>

```html
<KTableView
:data="tableData"
:row-expanded="(row) => row.id === tableData.find((dataRow) => dataRow.type.toLowerCase() === 'external')?.id"
:row-expandable="(row) => row.type.toLowerCase() === 'external'"
:headers="headers"
:pagination-attributes="{ totalCount: tableData.length }"
>
<template #row-expanded>
Lorem ipsum odor amet...
</template>
</KTableView>
```

### hideHeaders

A boolean to hide table headers. Only recomended when used in nested table. Refer to [Expandable Rows](#expandable-rows) section documentation for more details. Defaults to `false`.
Expand Down Expand Up @@ -1511,9 +1547,16 @@ Emitted when the user performs sorting, resizes columns or toggles column visibi

Emitted when user interacts with checkboxes in bulk actions column. Payload is array of selected table row objects.

### row-expand
### update:row-expanded

Emitted when row is expanded (when [`rowExpandable` prop](#rowexpandable) is `true`). Payload is expanded row data.
Emitted when row is expanded or collapsed (when [`rowExpandable` prop](#rowexpandable) is `true`). Payload is object of type `RowExpandPayload`.

```ts
interface RowExpandPayload {
row: Record<string, any>
expanded: boolean
}
```

<script setup lang="ts">
import { ref } from 'vue'
Expand Down
5 changes: 4 additions & 1 deletion sandbox/pages/SandboxTableData.vue
Original file line number Diff line number Diff line change
Expand Up @@ -138,11 +138,12 @@
</template>
</KTableData>
</SandboxSectionComponent>
<SandboxSectionComponent title="rowExpandable">
<SandboxSectionComponent title="rowExpandable & rowExpanded">
<KTableData
:fetcher="fetcher"
:headers="headers()"
:row-expandable="getRowExpandable"
:row-expanded="getRowExpanded"
>
<template #action-items>
<SandboxTableViewActions />
Expand Down Expand Up @@ -546,6 +547,8 @@ const getRowBulkAction = (data: Record<string, any>): RowBulkAction => {

const getRowExpandable = (row: Record<string, any>): boolean => row.id % 2 === 0

const getRowExpanded = (row: Record<string, any>): boolean => row.id % 4 === 0

const getRowOneTwoLink = (row: Record<string, any>): RowLink => {
if (row.id === 1) {
return getRowLinksRouter(row)
Expand Down
5 changes: 4 additions & 1 deletion sandbox/pages/SandboxTableView/SandboxTableView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -129,12 +129,13 @@
</template>
</KTableView>
</SandboxSectionComponent>
<SandboxSectionComponent title="rowExpandable">
<SandboxSectionComponent title="rowExpandable & rowExpanded">
<KTableView
:data="tableData"
:headers="headers()"
:pagination-attributes="{ totalCount: tableData.length }"
:row-expandable="getRowExpandable"
:row-expanded="getRowExpanded"
>
<template #action-items>
<SandboxTableViewActions />
Expand Down Expand Up @@ -628,6 +629,8 @@ const getRowBulkAction = (data: Record<string, any>): RowBulkAction => {

const getRowExpandable = (row: Record<string, any>): boolean => row.id % 2 === 0

const getRowExpanded = (row: Record<string, any>): boolean => row.id % 4 === 0

const getRowOneTwoLink = (row: Record<string, any>): RowLink => {
if (row.id === 1) {
return getRowLinksRouter(row)
Expand Down
7 changes: 5 additions & 2 deletions src/components/KTableData/KTableData.vue
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
:row-attrs="rowAttrs"
:row-bulk-action-enabled="rowBulkActionEnabled"
:row-expandable="rowExpandable"
:row-expanded="rowExpanded"
:row-hover="rowHover"
:row-key="rowKey"
:row-link="rowLink"
Expand All @@ -37,9 +38,9 @@
@get-previous-offset="getPreviousOffsetHandler"
@page-change="pageChangeHandler"
@page-size-change="pageSizeChangeHandler"
@row-expand="($event: Record<string, any>) => emit('row-expand', $event)"
@row-select="($event: Record<string, any>[]) => emit('row-select', $event)"
@sort="sortHandler"
@update:row-expanded="($event: RowExpandPayload) => emit('update:row-expanded', $event)"
@update:table-preferences="tablePreferencesUpdateHandler"
>
<template
Expand Down Expand Up @@ -174,6 +175,7 @@ import type {
SwrvState,
SwrvStateData,
TableDataProps,
RowExpandPayload,
} from '@/types'
import { EmptyStateIconVariants } from '@/types'
import useUniqueId from '@/composables/useUniqueId'
Expand Down Expand Up @@ -201,6 +203,7 @@ const props = withDefaults(defineProps<TableDataProps>(), {
hidePagination: false,
paginationAttributes: () => ({}),
rowExpandable: () => false,
rowExpanded: () => false,
hideHeaders: false,
nested: false,
hidePaginationWhenOptional: false,
Expand Down Expand Up @@ -230,7 +233,7 @@ const emit = defineEmits<{
(e: 'sort', value: TableSortPayload): void
(e: 'state', value: TableStatePayload): void
(e: 'row-select', data: Record<string, any>[]): void
(e: 'row-expand', data: any): void
(e: 'update:row-expanded', data: RowExpandPayload): void
}>()

const tableId = useUniqueId()
Expand Down
31 changes: 29 additions & 2 deletions src/components/KTableView/KTableView.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ const options = {
id: '517526354743085',
enabled: 'true',
expandable: true,
expanded: true,
},
{
name: 'Website Desktop',
Expand Down Expand Up @@ -560,17 +561,43 @@ describe('KTableView', () => {
})
})

it('emits row-expand event when row is expanded', () => {
it('renders a row expanded when rowExpanded prop returns true', () => {
cy.mount(KTableView, {
props: {
headers: options.headers,
data: options.data,
rowExpandable: () => true,
rowExpanded: (row: any) => row.expanded,
},
slots: {
'row-expanded': '<span data-testid="slotted-expandable-content">Expandable content</span>',
},
})

cy.getTestId('expandable-row-control').should('have.length', options.data.length).should('be.visible')
cy.getTestId('expandable-content-row').should('have.length', options.data.length)

cy.getTestId('expandable-content-row').findTestId('slotted-expandable-content').should('be.visible')
cy.getTestId('expandable-row-control').eq(0).click().then(() => {
cy.wrap(Cypress.vueWrapper.emitted()).should('have.property', 'row-expand').and('have.length', 1)
cy.getTestId('expandable-content-row').eq(0).findTestId('slotted-expandable-content').should('not.be.visible')
})
})

it('emits update:row-expanded event when row is expanded and collapsed', () => {
cy.mount(KTableView, {
props: {
headers: options.headers,
data: options.data,
rowExpandable: () => true,
},
})

cy.getTestId('expandable-row-control').eq(0).click().then(() => {
cy.wrap(Cypress.vueWrapper.emitted()).should('have.property', 'update:row-expanded').and('have.length', 1)

cy.getTestId('expandable-row-control').eq(0).click().then(() => {
cy.wrap(Cypress.vueWrapper.emitted()).should('have.property', 'update:row-expanded').and('have.length', 2)
})
})
})

Expand Down
29 changes: 23 additions & 6 deletions src/components/KTableView/KTableView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,7 @@ import type {
PageSizeChangeData,
TableViewProps,
TableViewSelectState,
RowExpandPayload,
} from '@/types'
import { EmptyStateIconVariants, TableViewHeaderKeys } from '@/types'
import { KUI_COLOR_TEXT_NEUTRAL, KUI_ICON_SIZE_30, KUI_SPACE_60 } from '@kong/design-tokens'
Expand Down Expand Up @@ -422,12 +423,13 @@ const props = withDefaults(defineProps<TableViewProps>(), {
hidePagination: false,
paginationAttributes: () => ({}),
rowExpandable: () => false,
rowExpanded: () => false,
hideHeaders: false,
nested: false,
hidePaginationWhenOptional: false,
hideToolbar: false,
/**
* KTableData props defaults
* KTableView props defaults
*/
data: () => ([]),
headers: () => ([]),
Expand All @@ -445,7 +447,7 @@ const emit = defineEmits<{
(e: 'get-next-offset'): void
(e: 'get-previous-offset'): void
(e: 'row-select', data: TableViewData): void
(e: 'row-expand', data: any): void
(e: 'update:row-expanded', data: RowExpandPayload): void
}>()

const attrs = useAttrs()
Expand Down Expand Up @@ -974,20 +976,35 @@ const emitTablePreferences = (): void => {
}

const hasExpandableRows = computed((): boolean => !props.nested && props.data.some((row: Record<string, any>) => props.rowExpandable(row)))
const expandableRowHeader = { key: TableViewHeaderKeys.EXPANDABLE, label: 'Expandable rows controls', hideLabel: true }
/**
* Get the expanded rows from the prop
*/
const getExpandedRows = (): number[] => {
const initialExpandedRows: number[] = []

props.data.forEach((row, index) => {
if (props.rowExpanded(row)) {
initialExpandedRows.push(index)
}
})

return initialExpandedRows
}
const expandedRows = ref<number[]>(getExpandedRows())
/**
* Toggle visibility of expendable row content
*/
const expandableRowHeader = { key: TableViewHeaderKeys.EXPANDABLE, label: 'Expandable rows controls', hideLabel: true }
const expandedRows = ref<number[]>([])
const toggleRow = async (rowIndex: number, row: any): Promise<void> => {
setActualColumnWidths()
await nextTick()

if (expandedRows.value.includes(rowIndex)) {
expandedRows.value = expandedRows.value.filter((row) => row !== rowIndex)
emit('update:row-expanded', { row, expanded: false })
} else {
expandedRows.value = [...expandedRows.value, rowIndex]
emit('row-expand', row)
emit('update:row-expanded', { row, expanded: true })
}
}

Expand Down Expand Up @@ -1157,7 +1174,7 @@ watch([() => props.data, dataSelectState], (newVals) => {
bulkActionsSelectedRows.value = [...oldSelectedRows, ...newSelectedRows]
}

expandedRows.value = []
expandedRows.value = getExpandedRows()
}, { deep: true, immediate: true })

watch(bulkActionsSelectedRows, (newVal) => {
Expand Down
9 changes: 9 additions & 0 deletions src/types/table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,10 @@ interface TablePropsShared {
* Enable expandable rows
*/
rowExpandable?: (row: Record<string, any>) => boolean
/**
* A function that conditionally specifies whether a row is expanded or not
*/
rowExpanded?: (row: Record<string, any>) => boolean
/**
* Hide the table header
*/
Expand Down Expand Up @@ -283,3 +287,8 @@ export enum TableViewHeaderKeys {
ACTIONS = 'actions',
BULK_ACTIONS = 'bulkActions',
}

export interface RowExpandPayload {
row: Record<string, any>
expanded: boolean
}