From 53df291e48a05e80554ad1063e0c98099dbc4f46 Mon Sep 17 00:00:00 2001
From: Matt Shaver <60105315+matthewshaver@users.noreply.github.com>
Date: Wed, 13 Nov 2024 17:00:29 -0500
Subject: [PATCH] Adding sortable tables (#6338)
## What are you changing in this pull request and why?
Adding sortable tables by wrapping markdown in react.
Static tables function the same. To make a sortable table would wrap
markdown table with :
```
{`
Markdown table here
`}
```
I couldn't successfully format this so that the {` `} are not required.
I also couldn't figure out how to enforce this globally (which was a
request). It has to be implemented purposefully.
In the UI this will put light grey arrows to the right of the headers.
When users click the arrows it will sort the table according to the
column and the directional arrow will be darker. There is no "reset,"
but if the user reloads the page, the table will be in the original
order if it wasn't alphabetical by the first column already (which it
really should be unless it's a connections config table).
## Checklist
- [ ] I have reviewed the [Content style
guide](https://github.com/dbt-labs/docs.getdbt.com/blob/current/contributing/content-style-guide.md)
so my content adheres to these guidelines.
- [ ] The topic I'm writing about is for specific dbt version(s) and I
have versioned it according to the [version a whole
page](https://github.com/dbt-labs/docs.getdbt.com/blob/current/contributing/single-sourcing-content.md#adding-a-new-version)
and/or [version a block of
content](https://github.com/dbt-labs/docs.getdbt.com/blob/current/contributing/single-sourcing-content.md#versioning-blocks-of-content)
guidelines.
- [ ] I have added checklist item(s) to this list for anything anything
that needs to happen before this PR is merged, such as "needs technical
review" or "change base branch."
- [ ] The content in this PR requires a dbt release note, so I added one
to the [release notes
page](https://docs.getdbt.com/docs/dbt-versions/dbt-cloud-release-notes).
---------
Co-authored-by: Mirna Wong <89008547+mirnawong1@users.noreply.github.com>
---
website/package-lock.json | 12 ++
website/package.json | 1 +
website/src/components/sortableTable/index.js | 114 ++++++++++++++++++
website/src/theme/MDXComponents/index.js | 2 +
4 files changed, 129 insertions(+)
create mode 100644 website/src/components/sortableTable/index.js
diff --git a/website/package-lock.json b/website/package-lock.json
index 5fdf491f1cf..df0c9652529 100644
--- a/website/package-lock.json
+++ b/website/package-lock.json
@@ -27,6 +27,7 @@
"gray-matter": "^4.0.3",
"hast-util-is-element": "^1.1.0",
"js-yaml": "^4.1.0",
+ "markdown-to-jsx": "^7.5.0",
"mobx": "^6.3.9",
"node-polyfill-webpack-plugin": "^1.1.4",
"papaparse": "^5.3.2",
@@ -17038,6 +17039,17 @@
"url": "https://github.com/sponsors/wooorm"
}
},
+ "node_modules/markdown-to-jsx": {
+ "version": "7.5.0",
+ "resolved": "https://registry.npmjs.org/markdown-to-jsx/-/markdown-to-jsx-7.5.0.tgz",
+ "integrity": "sha512-RrBNcMHiFPcz/iqIj0n3wclzHXjwS7mzjBNWecKKVhNTIxQepIix6Il/wZCn2Cg5Y1ow2Qi84+eJrryFRWBEWw==",
+ "engines": {
+ "node": ">= 10"
+ },
+ "peerDependencies": {
+ "react": ">= 0.14.0"
+ }
+ },
"node_modules/marked": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz",
diff --git a/website/package.json b/website/package.json
index 51edae4bf17..a16c8f9db9b 100644
--- a/website/package.json
+++ b/website/package.json
@@ -30,6 +30,7 @@
"gray-matter": "^4.0.3",
"hast-util-is-element": "^1.1.0",
"js-yaml": "^4.1.0",
+ "markdown-to-jsx": "^7.5.0",
"mobx": "^6.3.9",
"node-polyfill-webpack-plugin": "^1.1.4",
"papaparse": "^5.3.2",
diff --git a/website/src/components/sortableTable/index.js b/website/src/components/sortableTable/index.js
new file mode 100644
index 00000000000..93d54252c94
--- /dev/null
+++ b/website/src/components/sortableTable/index.js
@@ -0,0 +1,114 @@
+import React, { useState, useMemo } from 'react';
+import Markdown from 'markdown-to-jsx';
+
+const stripMarkdown = (text) => {
+ let strippedText = text.replace(/\[([^\]]+)\]\([^)]+\)/g, '$1');
+ strippedText = strippedText.replace(/[_*`~]/g, '');
+ return strippedText;
+};
+
+const parseMarkdownTable = (markdown) => {
+ const rows = markdown.trim().split('\n');
+ const headers = rows[0].split('|').map((header) => header.trim()).filter(Boolean);
+
+ const alignmentsRow = rows[1].split('|').map((align) => align.trim()).filter(Boolean);
+ const columnAlignments = alignmentsRow.map((alignment) => {
+ if (alignment.startsWith(':') && alignment.endsWith(':')) {
+ return 'center';
+ } else if (alignment.startsWith(':')) {
+ return 'left';
+ } else if (alignment.endsWith(':')) {
+ return 'right';
+ } else {
+ return 'left';
+ }
+ });
+
+ const data = rows.slice(2).map(row => row.split('|').map(cell => cell.trim()).filter(Boolean));
+
+ return { headers, data, columnAlignments };
+};
+
+const SortableTable = ({ children }) => {
+ const { headers, data: initialData, columnAlignments } = useMemo(
+ () => parseMarkdownTable(children),
+ [children]
+ );
+
+ const [data, setData] = useState(initialData);
+ const [sortConfig, setSortConfig] = useState({ key: '', direction: 'asc' });
+
+ const sortTable = (keyIndex) => {
+ const newDirection = (sortConfig.key === keyIndex && sortConfig.direction === 'asc') ? 'desc' : 'asc';
+ setSortConfig({ key: keyIndex, direction: newDirection });
+
+ const sortedData = [...data].sort((a, b) => {
+ const aVal = stripMarkdown(a[keyIndex]);
+ const bVal = stripMarkdown(b[keyIndex]);
+ if (aVal < bVal) return newDirection === 'asc' ? -1 : 1;
+ if (aVal > bVal) return newDirection === 'asc' ? 1 : -1;
+ return 0;
+ });
+
+ setData(sortedData);
+ };
+
+ return (
+
+
+
+ {headers.map((header, index) => (
+ sortTable(index)}
+ style={{
+ cursor: 'pointer',
+ position: 'relative',
+ textAlign: columnAlignments[index],
+ padding: '10px'
+ }}
+ >
+
+ {header}
+
+ ↑
+
+
+ ↓
+
+
+ |
+ ))}
+
+
+
+ {data.map((row, rowIndex) => (
+
+ {row.map((cell, cellIndex) => (
+
+ {cell || '\u00A0'}
+ |
+ ))}
+
+ ))}
+
+
+ );
+};
+
+export default SortableTable;
diff --git a/website/src/theme/MDXComponents/index.js b/website/src/theme/MDXComponents/index.js
index d136222a0ce..422d6c99fab 100644
--- a/website/src/theme/MDXComponents/index.js
+++ b/website/src/theme/MDXComponents/index.js
@@ -13,6 +13,7 @@ import Mermaid from '@theme/Mermaid';
/* dbt Customizations:
* Imports the following components below for export
*/
+import SortableTable from '@site/src/components/sortableTable';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem'
import Changelog from '@site/src/components/changelog';
@@ -95,5 +96,6 @@ const MDXComponents = {
DetailsToggle: DetailsToggle,
Expandable: Expandable,
ConfettiTrigger: ConfettiTrigger,
+ SortableTable: SortableTable,
};
export default MDXComponents;