Skip to content

Commit 1a837fc

Browse files
committed
refactor: f-table column reactive enabled prop (refs SFKUI-7622)
1 parent c61c44d commit 1a837fc

File tree

15 files changed

+135
-68
lines changed

15 files changed

+135
-68
lines changed

etc/vue-labs.api.md

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { DefineComponent } from 'vue';
1212
import { ExtractPropTypes } from 'vue';
1313
import { FormatFunction } from '@fkui/vue';
1414
import { IPopupErrorData } from '@fkui/vue';
15+
import { MaybeRef } from 'vue';
1516
import { ParseFunction } from '@fkui/vue';
1617
import { PropType } from 'vue';
1718
import { PublicProps } from 'vue';
@@ -118,8 +119,6 @@ export type TableColumn<T, K extends keyof T = keyof T> = TableColumnSimple<T, K
118119

119120
// @public (undocumented)
120121
export interface TableColumnAnchor<T, K extends keyof T> extends TableColumnBase {
121-
// (undocumented)
122-
enabled?: boolean | ((this: void, row: T) => boolean);
123122
// (undocumented)
124123
href: string;
125124
// (undocumented)
@@ -135,15 +134,15 @@ export interface TableColumnBase {
135134
// (undocumented)
136135
description?: string | Readonly<Ref<string | null>>;
137136
// (undocumented)
137+
enabled?: MaybeRef<boolean>;
138+
// (undocumented)
138139
header: string | Readonly<Ref<string>>;
139140
// (undocumented)
140141
size?: TableColumnSize | Readonly<Ref<TableColumnSize | null>>;
141142
}
142143

143144
// @public (undocumented)
144145
export interface TableColumnButton<T, K extends keyof T> extends TableColumnBase {
145-
// (undocumented)
146-
enabled?: boolean | ((this: void, row: T) => boolean);
147146
// (undocumented)
148147
icon?: string;
149148
iconLibrary?: string;
@@ -182,8 +181,6 @@ export interface TableColumnMenu<T> extends TableColumnBase {
182181
onClick?(this: void, row: T): void;
183182
}>;
184183
// (undocumented)
185-
enabled?: boolean | ((row: T) => boolean);
186-
// (undocumented)
187184
text(this: void, row: T): string | null;
188185
// (undocumented)
189186
type: "menu";

packages/vue-labs/src/components/FTable/FTable.cy.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2148,3 +2148,39 @@ describe("13 Cell interaction states", () => {
21482148
});
21492149
}
21502150
});
2151+
2152+
describe("columns", () => {
2153+
it("should not render column when toggling enabled to false", () => {
2154+
const rows = ref([{ foo: "1", bar: "alpha" }]);
2155+
const fooEnabled = ref(true);
2156+
const columns = defineTableColumns<{ foo: string; bar: string }>([
2157+
{
2158+
type: "text",
2159+
header: "foo",
2160+
key: "foo",
2161+
enabled: fooEnabled,
2162+
},
2163+
{
2164+
type: "text",
2165+
header: "bar",
2166+
key: "bar",
2167+
},
2168+
]);
2169+
2170+
cy.mount(() =>
2171+
h("div", [
2172+
renderButton("Toggle first column enabled", {
2173+
onClick: () => (fooEnabled.value = !fooEnabled.value),
2174+
}),
2175+
h(FTable<{ foo: string; bar: string }>, {
2176+
rows: rows.value,
2177+
columns,
2178+
}),
2179+
]),
2180+
);
2181+
2182+
table.header(1).should("contain.text", "foo");
2183+
cy.get("button").click();
2184+
table.header(1).should("contain.text", "bar");
2185+
});
2186+
});

packages/vue-labs/src/components/FTable/FTable.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ const columnCount = computed((): number => {
121121
const hasFooter = computed((): boolean => {
122122
return hasSlot("footer");
123123
});
124-
const columns = computed(() => normalizeTableColumns(rawColumns));
124+
const columns = computed(() => normalizeTableColumns(rawColumns).filter((col) => toValue(col.enabled)));
125125
126126
const tableClasses = computed(() => {
127127
return [
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import { type ComponentPublicInstance } from "vue";
2+
import { shallowMount } from "@vue/test-utils";
3+
import ITableAnchor from "./ITableAnchor.vue";
4+
import { normalizeTableColumn } from "./table-column";
5+
6+
describe("text", () => {
7+
interface Row {
8+
foo?: string | null;
9+
}
10+
11+
it("should render empty text when `text` is null", () => {
12+
expect.assertions(2);
13+
const row: Row = { foo: undefined };
14+
const column = normalizeTableColumn<Row, keyof Row>({
15+
type: "anchor",
16+
header: "header",
17+
text: () => null,
18+
href: "",
19+
});
20+
const wrapper = shallowMount(
21+
ITableAnchor as unknown as ComponentPublicInstance,
22+
{
23+
props: { column, row },
24+
},
25+
);
26+
27+
expect(wrapper.find("a").exists()).toBeFalsy();
28+
expect(wrapper.find("td").text()).toBe("");
29+
});
30+
31+
it("should render empty text when `text` is empty string", () => {
32+
expect.assertions(2);
33+
const row: Row = { foo: undefined };
34+
const column = normalizeTableColumn<Row, keyof Row>({
35+
type: "anchor",
36+
header: "header",
37+
text: () => "",
38+
href: "",
39+
});
40+
const wrapper = shallowMount(
41+
ITableAnchor as unknown as ComponentPublicInstance,
42+
{
43+
props: { column, row },
44+
},
45+
);
46+
47+
expect(wrapper.find("a").exists()).toBeFalsy();
48+
expect(wrapper.find("td").text()).toBe("");
49+
});
50+
51+
it("should render anchor with text when `text` is set", () => {
52+
expect.assertions(2);
53+
const row: Row = { foo: undefined };
54+
const column = normalizeTableColumn<Row, keyof Row>({
55+
type: "anchor",
56+
header: "header",
57+
text: () => "my awesome anchor",
58+
href: "",
59+
});
60+
const wrapper = shallowMount(
61+
ITableAnchor as unknown as ComponentPublicInstance,
62+
{
63+
props: { column, row },
64+
},
65+
);
66+
67+
expect(wrapper.find("a").exists()).toBeTruthy();
68+
expect(wrapper.find("td").text()).toBe("my awesome anchor");
69+
});
70+
});

packages/vue-labs/src/components/FTable/ITableAnchor.vue

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<script setup lang="ts" generic="T, K extends keyof T">
2-
import { computed, useTemplateRef } from "vue";
2+
import { useTemplateRef } from "vue";
33
import { type FTableCellApi } from "./f-table-api";
44
import { type NormalizedTableColumnAnchor } from "./table-column";
55
@@ -10,16 +10,12 @@ const { column, row } = defineProps<{
1010
1111
const targetElement = useTemplateRef("target");
1212
13-
const renderAnchor = computed(() => {
14-
return column.enabled(row) && column.text(row) !== null;
15-
});
16-
1713
const expose: FTableCellApi = { tabstopEl: targetElement };
1814
defineExpose(expose);
1915
</script>
2016

2117
<template>
22-
<td v-if="renderAnchor" class="table-ng__cell table-ng__cell--anchor">
18+
<td v-if="column.text(row)" class="table-ng__cell table-ng__cell--anchor">
2319
<a ref="target" class="anchor anchor--block" target="_blank" :href="column.href" tabindex="-1">
2420
{{ column.text(row) }}
2521
</a>
Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<script setup lang="ts" generic="T, K extends keyof T">
2-
import { computed, useTemplateRef } from "vue";
2+
import { useTemplateRef } from "vue";
33
import { assertRef } from "@fkui/logic";
44
import { FIcon } from "@fkui/vue";
55
import { type FTableCellApi } from "./f-table-api";
@@ -11,7 +11,6 @@ const { column, row } = defineProps<{
1111
}>();
1212
1313
const buttonElement = useTemplateRef("button");
14-
const tdElement = useTemplateRef("td");
1514
1615
function onClickButton(): void {
1716
assertRef(buttonElement);
@@ -22,20 +21,15 @@ function onClickButton(): void {
2221
}
2322
}
2423
25-
const renderButton = computed(() => {
26-
return column.enabled(row) && column.text(row) !== null;
27-
});
28-
29-
const expose: FTableCellApi = { tabstopEl: renderButton.value ? buttonElement : tdElement };
24+
const expose: FTableCellApi = { tabstopEl: buttonElement };
3025
defineExpose(expose);
3126
</script>
3227

3328
<template>
34-
<td v-if="renderButton" class="table-ng__cell table-ng__cell--button">
29+
<td class="table-ng__cell table-ng__cell--button">
3530
<button ref="button" class="icon-button" type="button" tabindex="-1" @click="onClickButton">
3631
<f-icon v-if="column.icon" :library="column.iconLibrary" :name="column.icon"></f-icon>
3732
<span class="sr-only">{{ column.text(row) }}</span>
3833
</button>
3934
</td>
40-
<td v-else ref="td" tabindex="-1" class="table-ng__cell"></td>
4135
</template>

packages/vue-labs/src/components/FTable/ITableMenu.spec.ts

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,21 +18,6 @@ describe("ITableMenu", () => {
1818
expect(wrapper.find("button").exists()).toBeTruthy();
1919
});
2020

21-
it("should render empty cell when disabled", () => {
22-
expect.assertions(1);
23-
const row = {};
24-
const column = normalizeTableColumn<typeof row>({
25-
type: "menu",
26-
header: "Actions",
27-
enabled: false,
28-
text: () => "Actions",
29-
});
30-
const wrapper = shallowMount(ITableMenu<typeof row>, {
31-
props: { column, row },
32-
});
33-
expect(wrapper.find("button").exists()).toBeFalsy();
34-
});
35-
3621
it("should render button text", () => {
3722
expect.assertions(1);
3823
const row = { text: "Kalle Anka" };

packages/vue-labs/src/components/FTable/ITableMenu.vue

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,6 @@ const menuitems = computed((): ContextMenuItem[] => {
2727
});
2828
});
2929
30-
const renderButton = computed(() => {
31-
return column.enabled(row);
32-
});
33-
3430
function onOpen(event: MouseEvent): void {
3531
/* prevent FTable from activating the cell (which moves the focus back to
3632
* the cell instead of the context menu) */
@@ -61,11 +57,7 @@ defineExpose(expose);
6157
</script>
6258

6359
<template>
64-
<td
65-
v-if="renderButton"
66-
class="table-ng__cell table-ng__cell--button"
67-
:class="{ 'table-ng__cell--menu-open': isOpen }"
68-
>
60+
<td class="table-ng__cell table-ng__cell--button" :class="{ 'table-ng__cell--menu-open': isOpen }">
6961
<button ref="button" class="icon-button" type="button" tabindex="-1" aria-haspopup="menu" @click="onOpen">
7062
<f-icon name="bars"></f-icon>
7163
<span class="sr-only">{{ column.text(row) }}</span>
@@ -79,5 +71,4 @@ defineExpose(expose);
7971
@focusout="onFocusout"
8072
></f-context-menu>
8173
</td>
82-
<td v-else tabindex="-1" class="table-ng__cell"></td>
8374
</template>

packages/vue-labs/src/components/FTable/ITableSelectable.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ const multiSelectColumn: NormalizedTableColumnCheckbox<T, K> = {
5050
update() {
5151
emit("toggle", row);
5252
},
53+
enabled: true,
5354
};
5455
5556
const singleSelectColumn: NormalizedTableColumnRadio<T, K> = {
@@ -70,6 +71,7 @@ const singleSelectColumn: NormalizedTableColumnRadio<T, K> = {
7071
update() {
7172
emit("toggle", row);
7273
},
74+
enabled: true,
7375
};
7476
</script>
7577

packages/vue-labs/src/components/FTable/columns/anchor.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ export interface TableColumnAnchor<
1616
type: "anchor";
1717
key?: K;
1818
text(this: void, row: T): string | null;
19-
enabled?: boolean | ((this: void, row: T) => boolean);
2019
href: string;
2120
}
2221

@@ -34,7 +33,6 @@ export interface NormalizedTableColumnAnchor<
3433
column: NormalizedTableColumnAnchor<T, K>;
3534
}>;
3635
text(this: void, row: T): string | null;
37-
enabled(this: void, row: T): boolean;
3836
}
3937

4038
/**
@@ -47,10 +45,6 @@ export function normalizeAnchorColumn<T, K extends keyof T>(
4745
type: "anchor",
4846
text: getValueFn(column.text, column.key, String, ""),
4947
href: column.href,
50-
enabled:
51-
typeof column.enabled === "function"
52-
? column.enabled
53-
: () => Boolean(column.enabled ?? true),
5448
sortable: column.key ?? null,
5549
};
5650
}

0 commit comments

Comments
 (0)