From 780eb68f47997403afc82fe206afc71124d6d012 Mon Sep 17 00:00:00 2001 From: Vitali Pinchuk <146737590+vitPinchuk@users.noreply.github.com> Date: Thu, 14 Nov 2024 19:51:48 +0300 Subject: [PATCH 1/3] Update rows heights when group collapse (#159) * fix height * Update CHANGELOG.md --------- Co-authored-by: Mikhail Volkov --- CHANGELOG.md | 1 + package-lock.json | 4 +- provisioning/dashboards/panels.json | 357 +++++++++++++++++++++++++++- src/components/Table/Table.tsx | 1 + 4 files changed, 358 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f0c124d..8bb4364 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Features / Enhancements - Updated useNestedObjects hook to display request errors and empty values (#158) +- Updated rows heights when group collapse (#159) ## 1.6.0 (2024-10-29) diff --git a/package-lock.json b/package-lock.json index 435b857..bc636a5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "business-table", - "version": "1.6.0", + "version": "1.7.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "business-table", - "version": "1.6.0", + "version": "1.7.0", "license": "Apache-2.0", "dependencies": { "@emotion/css": "^11.13.0", diff --git a/provisioning/dashboards/panels.json b/provisioning/dashboards/panels.json index 3204d1f..7d20e91 100644 --- a/provisioning/dashboards/panels.json +++ b/provisioning/dashboards/panels.json @@ -72,6 +72,9 @@ "background": { "applyToRow": false }, + "header": { + "fontSize": "md" + }, "width": { "auto": true, "max": 50, @@ -119,6 +122,9 @@ "background": { "applyToRow": false }, + "header": { + "fontSize": "md" + }, "width": { "auto": true, "min": 200, @@ -166,6 +172,9 @@ "background": { "applyToRow": false }, + "header": { + "fontSize": "md" + }, "width": { "auto": true, "min": 100, @@ -213,6 +222,9 @@ "background": { "applyToRow": false }, + "header": { + "fontSize": "md" + }, "width": { "auto": true, "min": 200, @@ -261,6 +273,9 @@ "background": { "applyToRow": false }, + "header": { + "fontSize": "md" + }, "width": { "auto": false, "min": 100, @@ -428,6 +443,9 @@ "background": { "applyToRow": false }, + "header": { + "fontSize": "md" + }, "width": { "auto": true, "value": 100 @@ -473,6 +491,9 @@ "background": { "applyToRow": false }, + "header": { + "fontSize": "md" + }, "width": { "auto": true, "value": 100 @@ -520,6 +541,9 @@ "background": { "applyToRow": false }, + "header": { + "fontSize": "md" + }, "width": { "auto": true, "value": 100 @@ -565,6 +589,9 @@ "background": { "applyToRow": true }, + "header": { + "fontSize": "md" + }, "width": { "auto": true, "value": 100 @@ -622,6 +649,9 @@ "background": { "applyToRow": false }, + "header": { + "fontSize": "md" + }, "width": { "auto": true, "value": 100 @@ -669,6 +699,9 @@ "background": { "applyToRow": false }, + "header": { + "fontSize": "md" + }, "width": { "auto": true, "value": 100 @@ -789,6 +822,300 @@ ], "type": "volkovlabs-table-panel" }, + { + "datasource": { + "type": "marcusolsson-static-datasource", + "uid": "P1D2C73DC01F2359B" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 24, + "x": 0, + "y": 13 + }, + "id": 12, + "options": { + "nestedObjects": [], + "tables": [ + { + "items": [ + { + "aggregation": "none", + "appearance": { + "alignment": "start", + "background": { + "applyToRow": false + }, + "colors": {}, + "header": { + "fontSize": "md" + }, + "width": { + "auto": true, + "min": 20, + "value": 100 + }, + "wrap": true + }, + "edit": { + "editor": { + "type": "string" + }, + "enabled": false, + "permission": { + "mode": "", + "userRole": [] + } + }, + "enabled": true, + "field": { + "name": "labels", + "source": "A" + }, + "filter": { + "enabled": false, + "mode": "client", + "variable": "" + }, + "footer": [], + "group": true, + "label": "", + "objectId": "", + "pin": "", + "sort": { + "descFirst": false, + "enabled": false + }, + "type": "auto" + }, + { + "aggregation": "none", + "appearance": { + "alignment": "start", + "background": { + "applyToRow": false + }, + "colors": {}, + "header": { + "fontSize": "md" + }, + "width": { + "auto": true, + "min": 20, + "value": 100 + }, + "wrap": true + }, + "edit": { + "editor": { + "type": "string" + }, + "enabled": false, + "permission": { + "mode": "", + "userRole": [] + } + }, + "enabled": true, + "field": { + "name": "title", + "source": "A" + }, + "filter": { + "enabled": false, + "mode": "client", + "variable": "" + }, + "footer": [], + "group": false, + "label": "", + "objectId": "", + "pin": "", + "sort": { + "descFirst": false, + "enabled": false + }, + "type": "auto" + }, + { + "aggregation": "none", + "appearance": { + "alignment": "start", + "background": { + "applyToRow": false + }, + "colors": {}, + "header": { + "fontSize": "md" + }, + "width": { + "auto": true, + "min": 20, + "value": 100 + }, + "wrap": true + }, + "edit": { + "editor": { + "type": "string" + }, + "enabled": false, + "permission": { + "mode": "", + "userRole": [] + } + }, + "enabled": true, + "field": { + "name": "start_date", + "source": "A" + }, + "filter": { + "enabled": false, + "mode": "client", + "variable": "" + }, + "footer": [], + "group": false, + "label": "", + "objectId": "", + "pin": "", + "sort": { + "descFirst": false, + "enabled": false + }, + "type": "auto" + }, + { + "aggregation": "none", + "appearance": { + "alignment": "start", + "background": { + "applyToRow": false + }, + "colors": {}, + "header": { + "fontSize": "md" + }, + "width": { + "auto": true, + "min": 20, + "value": 100 + }, + "wrap": true + }, + "edit": { + "editor": { + "type": "string" + }, + "enabled": false, + "permission": { + "mode": "", + "userRole": [] + } + }, + "enabled": true, + "field": { + "name": "description", + "source": "A" + }, + "filter": { + "enabled": false, + "mode": "client", + "variable": "" + }, + "footer": [], + "group": false, + "label": "", + "objectId": "", + "pin": "", + "sort": { + "descFirst": false, + "enabled": false + }, + "type": "auto" + } + ], + "name": "Test", + "pagination": { + "enabled": false, + "mode": "client" + }, + "update": { + "datasource": "", + "payload": {} + } + } + ], + "tabsSorting": false, + "toolbar": { + "export": false + } + }, + "targets": [ + { + "frame": { + "fields": [ + { + "config": {}, + "name": "labels", + "type": "string", + "values": [] + }, + { + "config": {}, + "name": "title", + "type": "string", + "values": [] + }, + { + "config": {}, + "name": "start_date", + "type": "string", + "values": [] + }, + { + "config": {}, + "name": "description", + "type": "string", + "values": [] + } + ], + "meta": { + "custom": { + "customCode": "const createArray = (length, fillCell) => new Array(length).fill(fillCell)\n\nconst result = {\n ...frame,\n fields: frame.fields.map((field) => {\n if (field.name === 'labels') {\n return ({\n ...field,\n values: [createArray(4, 'Grafana 11.4'), createArray(4, 'Grafana 11.3'), createArray(4, 'Grafana 11.2'), createArray(4, 'Grafana 11.0'), createArray(4, 'Grafana 10.4'), createArray(4, 'Grafana 10.3'), createArray(4, 'Grafana 10.2'), createArray(4, 'Grafana 10.1'), createArray(4, 'Grafana 10.0')].flat()\n })\n }\n if (field.name === 'title') {\n return ({\n ...field,\n values: createArray(36, 'Title').map((item, index) => `${item} - ${index}`)\n })\n }\n if (field.name === 'start_date') {\n return ({\n ...field,\n values: createArray(36, '20-10-2024 10:00:30')\n })\n }\n if (field.name === 'description') {\n return ({\n ...field,\n values: createArray(36, '

Features/ 1

- Updated behavior
- Added All options
- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.')\n })\n }\n return ({\n ...field,\n values: []\n })\n })\n}\n\nreturn Promise.resolve(result);", + "valuesEditor": "custom" + } + } + }, + "refId": "A" + } + ], + "title": "Expanded rows - height", + "type": "volkovlabs-table-panel" + }, { "datasource": { "type": "marcusolsson-static-datasource", @@ -825,7 +1152,7 @@ "h": 13, "w": 24, "x": 0, - "y": 13 + "y": 23 }, "id": 11, "options": { @@ -839,6 +1166,9 @@ "background": { "applyToRow": false }, + "header": { + "fontSize": "md" + }, "width": { "auto": true, "value": 100 @@ -884,6 +1214,9 @@ "background": { "applyToRow": false }, + "header": { + "fontSize": "md" + }, "width": { "auto": true, "value": 100 @@ -931,6 +1264,9 @@ "background": { "applyToRow": false }, + "header": { + "fontSize": "md" + }, "width": { "auto": true, "value": 100 @@ -976,6 +1312,9 @@ "background": { "applyToRow": true }, + "header": { + "fontSize": "md" + }, "width": { "auto": true, "value": 100 @@ -1033,6 +1372,9 @@ "background": { "applyToRow": false }, + "header": { + "fontSize": "md" + }, "width": { "auto": true, "value": 100 @@ -1080,6 +1422,9 @@ "background": { "applyToRow": false }, + "header": { + "fontSize": "md" + }, "width": { "auto": true, "value": 100 @@ -1228,7 +1573,7 @@ "h": 8, "w": 24, "x": 0, - "y": 26 + "y": 36 }, "id": 8, "options": { @@ -1245,6 +1590,9 @@ "background": { "applyToRow": false }, + "header": { + "fontSize": "md" + }, "width": { "auto": true, "value": 100 @@ -1292,6 +1640,9 @@ "background": { "applyToRow": false }, + "header": { + "fontSize": "md" + }, "width": { "auto": true, "value": 100 @@ -1431,6 +1782,6 @@ "timezone": "", "title": "Panels", "uid": "O4tc_E6Gz", - "version": 3, + "version": 9, "weekStart": "" } diff --git a/src/components/Table/Table.tsx b/src/components/Table/Table.tsx index a8f5d45..f8d0a9f 100644 --- a/src/components/Table/Table.tsx +++ b/src/components/Table/Table.tsx @@ -308,6 +308,7 @@ export const Table = ({ const rowVirtualizer = useVirtualizer({ getScrollElement: useCallback(() => scrollableContainerRef.current, [scrollableContainerRef]), count: rows.length, + getItemKey: useCallback((index: number) => rows[index].id, [rows]), estimateSize: useCallback(() => 36, []), measureElement: useCallback((el: HTMLElement | HTMLTableRowElement) => el.offsetHeight, []), overscan: 10, From b6d4f90560c056d38588d99b0872558b0b14ea3e Mon Sep 17 00:00:00 2001 From: Vitali Pinchuk <146737590+vitPinchuk@users.noreply.github.com> Date: Thu, 14 Nov 2024 20:18:51 +0300 Subject: [PATCH 2/3] Update filter options to match exactly (#160) * upd filter behavior * update test * update test ci * Update CHANGELOG.md --------- Co-authored-by: Mikhail Volkov --- CHANGELOG.md | 1 + src/utils/table.test.ts | 20 ++++++++++++++++++++ src/utils/table.ts | 12 +++++++++++- 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8bb4364..9064abc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - Updated useNestedObjects hook to display request errors and empty values (#158) - Updated rows heights when group collapse (#159) +- Updated filter options to match exactly (#160) ## 1.6.0 (2024-10-29) diff --git a/src/utils/table.test.ts b/src/utils/table.test.ts index b3b2f81..2f1b8a7 100644 --- a/src/utils/table.test.ts +++ b/src/utils/table.test.ts @@ -601,6 +601,26 @@ describe('Table utils', () => { }), included: false, }, + { + name: 'Should include value if one of options match', + value: 'labels1', + columnId: 'label', + filter: createColumnFilter({ + type: ColumnFilterType.FACETED, + value: ['labels1', 'labels11'], + }), + included: true, + }, + { + name: 'Should exclude value if no one options match', + value: 'labels1', + columnId: 'label', + filter: createColumnFilter({ + type: ColumnFilterType.FACETED, + value: ['labels11', 'labels111'], + }), + included: false, + }, ]; it.each(tests)('$name', runColumnFilterTest); diff --git a/src/utils/table.ts b/src/utils/table.ts index 407dec1..e8d88e4 100644 --- a/src/utils/table.ts +++ b/src/utils/table.ts @@ -133,6 +133,16 @@ const timestampFilter = ( return true; }; +/** + * Apply Faceted Filter + * @param row + * @param columnId + * @param filterValue + */ +const facetedFilter = (row: Row, columnId: string, filterValue: unknown[]) => { + return filterValue.some((val) => row.getValue(columnId) === val); +}; + /** * Column Filter */ @@ -156,7 +166,7 @@ export const columnFilter = ( return numberFilter(row, columnId, filter.value, filter.operator); } case ColumnFilterType.FACETED: { - return filterFns.arrIncludesSome(row, columnId, filter.value, addMeta); + return facetedFilter(row, columnId, filter.value); } case ColumnFilterType.TIMESTAMP: { /** From 5854eb935dacb7c28c9a9f0dd3da73ef0c3127c1 Mon Sep 17 00:00:00 2001 From: Vitali Pinchuk <146737590+vitPinchuk@users.noreply.github.com> Date: Thu, 14 Nov 2024 20:38:54 +0300 Subject: [PATCH 3/3] Add Sanitized HTML and Markdown column type (#154) * Html and markdown added * Update version * req: pluginVersion removed * use rich text * add row to scopedVars * up scopedVars * upd test ci * Update Provisioning --------- Co-authored-by: Mikhail Volkov --- CHANGELOG.md | 2 + provisioning/dashboards/panels.json | 285 +++++++++++++++++- .../CellRenderer/CellRenderer.test.tsx | 19 ++ .../components/CellRenderer/CellRenderer.tsx | 6 +- .../CellRenderer/LayoutCellRenderer.test.tsx | 45 +++ .../CellRenderer/LayoutCellRenderer.tsx | 61 ++++ .../components/ColumnEditor/ColumnEditor.tsx | 5 + src/constants.ts | 3 + src/types/table.ts | 1 + 9 files changed, 419 insertions(+), 8 deletions(-) create mode 100644 src/components/Table/components/CellRenderer/LayoutCellRenderer.test.tsx create mode 100644 src/components/Table/components/CellRenderer/LayoutCellRenderer.tsx diff --git a/CHANGELOG.md b/CHANGELOG.md index 9064abc..2c164a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,8 +5,10 @@ ### 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) ## 1.6.0 (2024-10-29) diff --git a/provisioning/dashboards/panels.json b/provisioning/dashboards/panels.json index 7d20e91..c415706 100644 --- a/provisioning/dashboards/panels.json +++ b/provisioning/dashboards/panels.json @@ -24,7 +24,7 @@ "editable": true, "fiscalYearStartMonth": 0, "graphTooltip": 0, - "id": 3, + "id": 4, "links": [], "panels": [ { @@ -70,7 +70,7 @@ "appearance": { "alignment": "end", "background": { - "applyToRow": false + "applyToRow": true }, "header": { "fontSize": "md" @@ -114,7 +114,7 @@ "descFirst": false, "enabled": true }, - "type": "auto" + "type": "coloredBackground" }, { "appearance": { @@ -331,6 +331,7 @@ "export": true } }, + "pluginVersion": "1.7.0", "targets": [ { "datasource": { @@ -758,6 +759,7 @@ "export": true } }, + "pluginVersion": "1.7.0", "targets": [ { "datasource": { @@ -1055,7 +1057,7 @@ "descFirst": false, "enabled": false }, - "type": "auto" + "type": "rich_text" } ], "name": "Test", @@ -1074,6 +1076,7 @@ "export": false } }, + "pluginVersion": "1.7.0", "targets": [ { "frame": { @@ -1481,6 +1484,7 @@ "export": true } }, + "pluginVersion": "1.7.0", "targets": [ { "datasource": { @@ -1547,6 +1551,7 @@ }, { "datasource": { + "default": true, "type": "marcusolsson-static-datasource", "uid": "P1D2C73DC01F2359B" }, @@ -1570,11 +1575,276 @@ "overrides": [] }, "gridPos": { - "h": 8, + "h": 13, "w": 24, "x": 0, "y": 36 }, + "id": 13, + "options": { + "columnMode": "auto", + "columns": [], + "nestedObjects": [], + "tables": [ + { + "items": [ + { + "appearance": { + "alignment": "end", + "background": { + "applyToRow": false + }, + "header": { + "fontSize": "md" + }, + "width": { + "auto": true, + "max": 50, + "value": 100 + }, + "wrap": true + }, + "edit": { + "editor": { + "type": "string" + }, + "enabled": false, + "permission": { + "field": { + "name": "", + "source": "" + }, + "mode": "", + "userRole": [] + } + }, + "enabled": true, + "field": { + "name": "id", + "source": "A" + }, + "filter": { + "enabled": false, + "mode": "client", + "variable": "" + }, + "footer": [], + "group": false, + "label": "", + "pin": "left", + "sort": { + "descFirst": false, + "enabled": true + }, + "type": "auto" + }, + { + "aggregation": "none", + "appearance": { + "alignment": "start", + "background": { + "applyToRow": false + }, + "colors": {}, + "header": { + "fontSize": "md" + }, + "width": { + "auto": true, + "min": 20, + "value": 100 + }, + "wrap": true + }, + "edit": { + "editor": { + "type": "string" + }, + "enabled": false, + "permission": { + "mode": "", + "userRole": [] + } + }, + "enabled": true, + "field": { + "name": "HTML", + "source": "A" + }, + "filter": { + "enabled": false, + "mode": "client", + "variable": "" + }, + "footer": [], + "group": false, + "label": "", + "objectId": "", + "pin": "", + "sort": { + "descFirst": false, + "enabled": false + }, + "type": "rich_text" + }, + { + "aggregation": "none", + "appearance": { + "alignment": "start", + "background": { + "applyToRow": false + }, + "colors": {}, + "header": { + "fontSize": "md" + }, + "width": { + "auto": true, + "min": 20, + "value": 100 + }, + "wrap": true + }, + "edit": { + "editor": { + "type": "string" + }, + "enabled": false, + "permission": { + "mode": "", + "userRole": [] + } + }, + "enabled": true, + "field": { + "name": "Markdown", + "source": "A" + }, + "filter": { + "enabled": false, + "mode": "client", + "variable": "" + }, + "footer": [], + "group": false, + "label": "", + "objectId": "", + "pin": "", + "sort": { + "descFirst": false, + "enabled": false + }, + "type": "rich_text" + } + ], + "name": "Main", + "pagination": { + "enabled": false, + "mode": "client" + }, + "update": { + "datasource": "", + "payload": {} + } + } + ], + "tabsSorting": false, + "toolbar": { + "export": true + } + }, + "pluginVersion": "1.7.0", + "targets": [ + { + "datasource": { + "type": "marcusolsson-static-datasource", + "uid": "P1D2C73DC01F2359B" + }, + "frame": { + "fields": [ + { + "config": {}, + "name": "id", + "type": "number", + "values": [1, 2, 3, 4] + }, + { + "config": {}, + "name": "HTML", + "type": "string", + "values": [ + "

Features/ 1

- Updated behavior
- Added All options
", + "

Features/ 2

- Updated behavior
- Added All options
", + "

Features/ 3

- Updated behavior
- Added All options
", + "

$title

- Updated behavior
- Added All options
" + ] + }, + { + "config": {}, + "name": "Markdown", + "type": "string", + "values": [ + "# Heading level 1", + "This is the first line. And this is the second line.", + "I just use **bold text**.", + "> To create a blockquote, add a > in front of a paragraph." + ] + } + ], + "meta": {}, + "name": "data" + }, + "refId": "A" + } + ], + "title": "HTML, Markdown", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": {}, + "includeByName": {}, + "indexByName": {}, + "renameByName": { + "id": "", + "name": "Name", + "value": "Value" + } + } + } + ], + "type": "volkovlabs-table-panel" + }, + { + "datasource": { + "type": "marcusolsson-static-datasource", + "uid": "P1D2C73DC01F2359B" + }, + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 49 + }, "id": 8, "options": { "columnMode": "auto", @@ -1700,6 +1970,7 @@ "export": false } }, + "pluginVersion": "1.7.0", "targets": [ { "datasource": { @@ -1775,13 +2046,13 @@ ] }, "time": { - "from": "now-6h", + "from": "now-1y", "to": "now" }, "timepicker": {}, "timezone": "", "title": "Panels", "uid": "O4tc_E6Gz", - "version": 9, + "version": 1, "weekStart": "" } diff --git a/src/components/Table/components/CellRenderer/CellRenderer.test.tsx b/src/components/Table/components/CellRenderer/CellRenderer.test.tsx index 09ba6af..5839acd 100644 --- a/src/components/Table/components/CellRenderer/CellRenderer.test.tsx +++ b/src/components/Table/components/CellRenderer/CellRenderer.test.tsx @@ -7,6 +7,7 @@ import { createColumnConfig } from '@/utils'; import { CellRenderer } from './CellRenderer'; import { DefaultCellRenderer } from './DefaultCellRenderer'; +import { LayoutCellRenderer } from './LayoutCellRenderer'; type Props = React.ComponentProps; @@ -17,6 +18,13 @@ jest.mock('./DefaultCellRenderer', () => ({ DefaultCellRenderer: jest.fn(() => null), })); +/** + * Mock Layout Cell Renderer + */ +jest.mock('./LayoutCellRenderer', () => ({ + LayoutCellRenderer: jest.fn(() => null), +})); + describe('CellRenderer', () => { /** * Get component @@ -37,6 +45,7 @@ describe('CellRenderer', () => { beforeEach(() => { jest.mocked(DefaultCellRenderer).mockClear(); + jest.mocked(LayoutCellRenderer).mockClear(); }); it('Should work if no meta', () => { @@ -75,6 +84,16 @@ describe('CellRenderer', () => { expect(DefaultCellRenderer).toHaveBeenCalled(); }); + it('Should render layout cell renderer if HTML selected', () => { + render( + getComponent({ + column: createColumnWithMeta({ config: createColumnConfig({ type: CellType.RICH_TEXT as any }) }), + }) + ); + + expect(LayoutCellRenderer).toHaveBeenCalled(); + }); + it('Should render default cell renderer by default', () => { render(getComponent({ column: createColumnWithMeta({ config: createColumnConfig({ type: 'abc' as any }) }) })); diff --git a/src/components/Table/components/CellRenderer/CellRenderer.tsx b/src/components/Table/components/CellRenderer/CellRenderer.tsx index b9e6f9d..b5dbf1b 100644 --- a/src/components/Table/components/CellRenderer/CellRenderer.tsx +++ b/src/components/Table/components/CellRenderer/CellRenderer.tsx @@ -4,6 +4,7 @@ import React from 'react'; import { CellType } from '@/types'; import { DefaultCellRenderer } from './DefaultCellRenderer'; +import { LayoutCellRenderer } from './LayoutCellRenderer'; /** * Properties @@ -20,7 +21,7 @@ interface Props extends CellContext { /** * Cell Renderer */ -export const CellRenderer: React.FC = ({ renderValue, column, bgColor }) => { +export const CellRenderer: React.FC = ({ renderValue, column, bgColor, row }) => { /** * No meta */ @@ -40,6 +41,9 @@ export const CellRenderer: React.FC = ({ renderValue, column, bgColor }) case CellType.COLORED_BACKGROUND: { return ; } + case CellType.RICH_TEXT: { + return ; + } default: { return ; } diff --git a/src/components/Table/components/CellRenderer/LayoutCellRenderer.test.tsx b/src/components/Table/components/CellRenderer/LayoutCellRenderer.test.tsx new file mode 100644 index 0000000..a9ecfc8 --- /dev/null +++ b/src/components/Table/components/CellRenderer/LayoutCellRenderer.test.tsx @@ -0,0 +1,45 @@ +import { render, screen } from '@testing-library/react'; +import { getJestSelectors } from '@volkovlabs/jest-selectors'; +import React from 'react'; + +import { TEST_IDS } from '@/constants'; +import { tablePanelContext } from '@/hooks'; + +import { LayoutCellRenderer } from './LayoutCellRenderer'; + +type Props = React.ComponentProps; + +describe('LayoutCellRenderer', () => { + /** + * replaceVariables + */ + const replaceVariables = jest.fn(); + + /** + * Selectors + */ + const getSelectors = getJestSelectors(TEST_IDS.layoutCellRenderer); + const selectors = getSelectors(screen); + + /** + * Get component + */ + const getComponent = (props: Partial) => { + return ( + + ; + + ); + }; + + beforeEach(() => { + replaceVariables.mockImplementation((str: string) => str); + }); + + it('Should render value', () => { + render(getComponent({ value: '

text

', row: { original: { id: '4' } } as any })); + + expect(selectors.root()).toBeInTheDocument(); + expect(selectors.root()).toHaveTextContent('text'); + }); +}); diff --git a/src/components/Table/components/CellRenderer/LayoutCellRenderer.tsx b/src/components/Table/components/CellRenderer/LayoutCellRenderer.tsx new file mode 100644 index 0000000..1c07265 --- /dev/null +++ b/src/components/Table/components/CellRenderer/LayoutCellRenderer.tsx @@ -0,0 +1,61 @@ +import { textUtil } from '@grafana/data'; +import { Row } from '@tanstack/react-table'; +import MarkdownIt from 'markdown-it'; +import React from 'react'; + +import { TEST_IDS } from '@/constants'; +import { tablePanelContext } from '@/hooks'; + +/** + * Properties + */ +interface Props { + /** + * Value + * + * @type {string } + */ + value: string; + + /** + * Row + * + * @type {string } + */ + row: Row; +} + +/** + * Layout Cell Renderer + * @param value + */ +export const LayoutCellRenderer: React.FC = ({ value, row }) => { + /** + * Scoped Vars + */ + const scopedVars = { + row: { + value: row.original, + }, + }; + + /** + * Markdown it + */ + const md = new MarkdownIt({ + html: true, + }); + + /** + * Context + */ + + const { replaceVariables } = tablePanelContext.useContext(); + + return ( +
+ ); +}; diff --git a/src/components/editors/TablesEditor/components/TableEditor/components/ColumnsEditor/components/ColumnEditor/ColumnEditor.tsx b/src/components/editors/TablesEditor/components/TableEditor/components/ColumnsEditor/components/ColumnEditor/ColumnEditor.tsx index 85f94e0..8088b82 100644 --- a/src/components/editors/TablesEditor/components/TableEditor/components/ColumnsEditor/components/ColumnEditor/ColumnEditor.tsx +++ b/src/components/editors/TablesEditor/components/TableEditor/components/ColumnsEditor/components/ColumnEditor/ColumnEditor.tsx @@ -61,6 +61,11 @@ const cellTypeOptions = [ value: CellType.COLORED_TEXT, label: 'Colored text', }, + { + value: CellType.RICH_TEXT, + label: 'Rich text', + description: 'HTML / Markdown', + }, { value: CellType.NESTED_OBJECTS, label: 'Nested objects', diff --git a/src/constants.ts b/src/constants.ts index 37af0e3..40b8594 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -116,6 +116,9 @@ export const TEST_IDS = { defaultCellRenderer: { root: createSelector('data-testid default-cell-renderer'), }, + layoutCellRenderer: { + root: createSelector('data-testid layout-cell-renderer'), + }, aggregatedCellRenderer: { root: createSelector('data-testid aggregated-cell-renderer'), }, diff --git a/src/types/table.ts b/src/types/table.ts index bfe6c0e..d96e2cf 100644 --- a/src/types/table.ts +++ b/src/types/table.ts @@ -8,6 +8,7 @@ export enum CellType { AUTO = 'auto', COLORED_TEXT = 'coloredText', COLORED_BACKGROUND = 'coloredBackground', + RICH_TEXT = 'rich_text', NESTED_OBJECTS = 'nested_objects', }