Skip to content

Commit

Permalink
Add option to hide table header (#157)
Browse files Browse the repository at this point in the history
* add show/hide header for table

* update createTableConfig

* Update CHANGELOG.md

* Fix tests

* fix ci

* Updates

* Update provisioning

---------

Co-authored-by: Mikhail Volkov <[email protected]>
  • Loading branch information
vitPinchuk and mikhail-vl authored Nov 17, 2024
1 parent e4f95dd commit b6bda16
Show file tree
Hide file tree
Showing 18 changed files with 338 additions and 163 deletions.
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
# Change Log

## 1.7.0 (IN PROGRESS)
## 1.7.0 (2024-11-16)

### Features / Enhancements

- Updated useNestedObjects hook to display request errors and empty values (#158)
- Added Sanitized HTML and Markdown column type (#154)
- Updated rows heights when group collapse (#159)
- Updated filter options to match exactly (#160)
- Added Sanitized HTML and Markdown column type (#154)
- Updated data source name to id (#156)
- Added option to hide table header (#157)

## 1.6.0 (2024-10-29)

Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@ You can install the Business Table panel plugin from the [Grafana Plugins catalo
For the latter, please use the following command:

```bash
grafana-cli plugins install volkovlabs-table-panel
grafana cli plugins install volkovlabs-table-panel
```

[![Install Business Suite plugins in Cloud, OSS, Enterprise | Open source community plugins](https://raw.githubusercontent.com/volkovlabs/.github/main/started.png)](https://youtu.be/1qYzHfPXJF8)

## Highlights

- Tree View with expandable and collapsible elements.
Expand Down
6 changes: 0 additions & 6 deletions provisioning/dashboards/panels.json
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,6 @@
"export": true
}
},
"pluginVersion": "1.7.0",
"targets": [
{
"datasource": {
Expand Down Expand Up @@ -759,7 +758,6 @@
"export": true
}
},
"pluginVersion": "1.7.0",
"targets": [
{
"datasource": {
Expand Down Expand Up @@ -1076,7 +1074,6 @@
"export": false
}
},
"pluginVersion": "1.7.0",
"targets": [
{
"frame": {
Expand Down Expand Up @@ -1484,7 +1481,6 @@
"export": true
}
},
"pluginVersion": "1.7.0",
"targets": [
{
"datasource": {
Expand Down Expand Up @@ -1753,7 +1749,6 @@
"export": true
}
},
"pluginVersion": "1.7.0",
"targets": [
{
"datasource": {
Expand Down Expand Up @@ -1970,7 +1965,6 @@
"export": false
}
},
"pluginVersion": "1.7.0",
"targets": [
{
"datasource": {
Expand Down
63 changes: 63 additions & 0 deletions src/components/Table/Table.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ describe('Table', () => {
await act(async () =>
render(
getComponent({
showHeader: true,
columns: [
{
id: 'device',
Expand Down Expand Up @@ -136,6 +137,7 @@ describe('Table', () => {
await act(async () =>
render(
getComponent({
showHeader: true,
columns: [
{
id: 'device',
Expand Down Expand Up @@ -181,6 +183,7 @@ describe('Table', () => {
await act(async () =>
render(
getComponent({
showHeader: true,
columns: [
{
id: 'device',
Expand Down Expand Up @@ -218,6 +221,7 @@ describe('Table', () => {
await act(async () =>
render(
getComponent({
showHeader: true,
columns: [
{
id: 'device',
Expand Down Expand Up @@ -282,6 +286,65 @@ describe('Table', () => {
expect(selectors.footerCell(false, 'value2')).toHaveStyle({ position: 'sticky', right: 0 });
});

it('Should not show header if disabled', async () => {
await act(async () =>
render(
getComponent({
showHeader: false,
columns: [
{
id: 'device',
accessorFn: createColumnAccessorFn('device'),
enablePinning: false,
},
{
id: 'value',
accessorFn: createColumnAccessorFn('value'),
enablePinning: true,
meta: createColumnMeta({
config: createColumnConfig({
pin: ColumnPinDirection.LEFT,
}),
footerEnabled: true,
}),
footer: () => '123',
},
{
id: 'value2',
accessorFn: createColumnAccessorFn('value2'),
enablePinning: true,
meta: createColumnMeta({
config: createColumnConfig({
pin: ColumnPinDirection.RIGHT,
}),
footerEnabled: true,
}),
footer: () => '111',
},
],
data: [
{
device: 'device1',
value: 10,
value2: 11,
},
{
device: 'device2',
value: 20,
value2: 21,
},
],
})
)
);

/**
* Header cell
*/
expect(selectors.headerCell(true, 'value')).not.toBeInTheDocument();
expect(selectors.headerCell(true, 'value2')).not.toBeInTheDocument();
});

it('Should show pagination', async () => {
const pagination = createPagination({ isEnabled: true, isManual: false });

Expand Down
78 changes: 44 additions & 34 deletions src/components/Table/Table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,13 @@ interface Props<TData> {
* Table Instance
*/
tableInstance: MutableRefObject<TableInstance<TData>>;

/**
* Show Header
*
* @type {boolean}
*/
showHeader: boolean;
}

/**
Expand Down Expand Up @@ -185,6 +192,7 @@ export const Table = <TData,>({
width,
pagination,
tableInstance,
showHeader,
}: Props<TData>) => {
/**
* Styles and Theme
Expand Down Expand Up @@ -348,40 +356,42 @@ export const Table = <TData,>({
}}
{...TEST_IDS.table.root.apply()}
>
<thead className={styles.header} ref={tableHeaderRef} style={{ top: topOffset }}>
{table.getHeaderGroups().map((headerGroup) => (
<tr key={headerGroup.id} className={styles.headerRow} {...TEST_IDS.table.headerRow.apply(headerGroup.id)}>
{headerGroup.headers.map((header) => {
const bgColor = header.column.columnDef.meta?.config.appearance.header.backgroundColor;
const fontSize =
header.column.columnDef.meta?.config.appearance.header.fontSize || ColumnHeaderFontSize.MD;
return (
<th
key={header.id}
className={cx(styles.headerCell, {
[styles.sizeLg]: fontSize === ColumnHeaderFontSize.LG,
[styles.sizeMd]: fontSize === ColumnHeaderFontSize.MD,
[styles.sizeSm]: fontSize === ColumnHeaderFontSize.SM,
[styles.sizeXs]: fontSize === ColumnHeaderFontSize.XS,
})}
style={{
maxWidth: header.column.columnDef.maxSize,
minWidth: header.column.columnDef.minSize,
background: bgColor,
width: header.getSize(),
textAlign: header.column.columnDef.meta?.config.appearance.alignment,
justifyContent: header.column.columnDef.meta?.config.appearance.alignment,
...getPinnedHeaderColumnStyle(theme, header.column),
}}
{...TEST_IDS.table.headerCell.apply(header.id)}
>
<TableHeaderCell header={header} size={fontSize} />
</th>
);
})}
</tr>
))}
</thead>
{showHeader && (
<thead className={styles.header} ref={tableHeaderRef} style={{ top: topOffset }}>
{table.getHeaderGroups().map((headerGroup) => (
<tr key={headerGroup.id} className={styles.headerRow} {...TEST_IDS.table.headerRow.apply(headerGroup.id)}>
{headerGroup.headers.map((header) => {
const bgColor = header.column.columnDef.meta?.config.appearance.header.backgroundColor;
const fontSize =
header.column.columnDef.meta?.config.appearance.header.fontSize || ColumnHeaderFontSize.MD;
return (
<th
key={header.id}
className={cx(styles.headerCell, {
[styles.sizeLg]: fontSize === ColumnHeaderFontSize.LG,
[styles.sizeMd]: fontSize === ColumnHeaderFontSize.MD,
[styles.sizeSm]: fontSize === ColumnHeaderFontSize.SM,
[styles.sizeXs]: fontSize === ColumnHeaderFontSize.XS,
})}
style={{
maxWidth: header.column.columnDef.maxSize,
minWidth: header.column.columnDef.minSize,
background: bgColor,
width: header.getSize(),
textAlign: header.column.columnDef.meta?.config.appearance.alignment,
justifyContent: header.column.columnDef.meta?.config.appearance.alignment,
...getPinnedHeaderColumnStyle(theme, header.column),
}}
{...TEST_IDS.table.headerCell.apply(header.id)}
>
<TableHeaderCell header={header} size={fontSize} />
</th>
);
})}
</tr>
))}
</thead>
)}
<tbody
style={{
height: `${rowVirtualizer.getTotalSize()}px`, //tells scrollbar how big the table is
Expand Down
1 change: 1 addition & 0 deletions src/components/TablePanel/TablePanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ export const TablePanel: React.FC<Props> = ({
onUpdateRow={onUpdateRow}
bottomOffset={tableBottomOffset}
paginationRef={paginationRef}
showHeader={currentTable?.showHeader ?? true}
width={width}
pagination={pagination}
tableInstance={tableInstance as never}
Expand Down
4 changes: 2 additions & 2 deletions src/components/editors/TablesEditor/TablesEditor.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,8 @@ describe('TablesEditor', () => {
await act(() => fireEvent.click(selectors.buttonAddNew()));

expect(onChange).toHaveBeenCalledWith([
createTableConfig({ name: 'group1', items: [] }),
createTableConfig({ name: 'group2', items: [] }),
createTableConfig({ name: 'group1', items: [], showHeader: false }),
createTableConfig({ name: 'group2', items: [], showHeader: true }),
]);
});

Expand Down
1 change: 1 addition & 0 deletions src/components/editors/TablesEditor/TablesEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ export const TablesEditor: React.FC<Props> = ({ context: { options, data }, onCh
items.concat([
{
name: newItemName,
showHeader: true,
items: [],
update: { datasource: '', payload: {} },
pagination: { enabled: false, mode: PaginationMode.CLIENT },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,25 @@ describe('TableEditor', () => {
})
);
});

it('Should allow to change header visibility', () => {
render(
getComponent({
value: createTableConfig({
showHeader: true,
items: [createColumnConfig({})],
}),
})
);

expect(selectors.fieldShowHeader()).toBeInTheDocument();
fireEvent.click(selectors.fieldShowHeader());

expect(onChange).toHaveBeenCalledWith(
expect.objectContaining({
showHeader: false,
items: [createColumnConfig({})],
})
);
});
});
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { DataFrame } from '@grafana/data';
import { InlineField, InlineSwitch } from '@grafana/ui';
import React from 'react';

import { TEST_IDS } from '@/constants';
import { EditorProps, TableConfig } from '@/types';

import { ColumnsEditor } from './components';
Expand All @@ -20,16 +22,31 @@ interface Props extends EditorProps<TableConfig> {
*/
export const TableEditor: React.FC<Props> = ({ value, onChange, data }) => {
return (
<ColumnsEditor
name={value.name}
value={value.items}
data={data}
onChange={(items) => {
onChange({
...value,
items,
});
}}
/>
<>
<InlineField label="Show header">
<InlineSwitch
value={value.showHeader}
onChange={(event) =>
onChange({
...value,
showHeader: event.currentTarget.checked,
})
}
{...TEST_IDS.tableEditor.fieldShowHeader.apply()}
/>
</InlineField>
<ColumnsEditor
showTableHeader={value.showHeader}
name={value.name}
value={value.items}
data={data}
onChange={(items) => {
onChange({
...value,
items,
});
}}
/>
</>
);
};
Loading

0 comments on commit b6bda16

Please sign in to comment.