Skip to content

Commit ecd5772

Browse files
authored
Merge pull request #440 from BSd3v/v35-release
bumping to 35.2.0
2 parents aafdddf + 51a59cd commit ecd5772

9 files changed

Lines changed: 6297 additions & 15886 deletions

.eslintignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
*.css
2-
registerServiceWorker.js
2+
registerServiceWorker.js
3+
node_modules/

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,16 @@ Links "DE#nnn" prior to version 2.0 point to the Dash Enterprise closed-source D
88

99
### Added
1010
- [#436](https://github.com/plotly/dash-ag-grid/pull/436) Enabled Filter Handlers to simplify custom filter components by splitting the filter logic out from the UI component.
11+
- [#440](https://github.com/plotly/dash-ag-grid/pull/440)
12+
- added `columnTypes` to prop categories for parsing functions
13+
14+
### Changed
15+
- [#440](https://github.com/plotly/dash-ag-grid/pull/440)
16+
- Markdown update for npm
17+
- `linkTarget` now works even if `dangerously_allow_code` is `true` and no `target` is passed in the link.
18+
- `_self` will auto apply as a `linkTarget`.
19+
- `_blank` will auto apply `rel='noreferrer noopener 'nofollow'` for security reasons, but will open in a new tab.
20+
- version bump to v`35.2.0` for the grid
1121

1222
## [35.0.0rc0] - 2026-01-21
1323
### Changed

package-lock.json

Lines changed: 6138 additions & 15822 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 36 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "dash-ag-grid",
3-
"version": "35.0.0rc0",
3+
"version": "35.2.0",
44
"description": "Dash wrapper around AG Grid, the best interactive data grid for the web.",
55
"repository": {
66
"type": "git",
@@ -18,62 +18,65 @@
1818
"build:js": "webpack --mode production",
1919
"build:backends": "dash-generate-components ./src/lib/components dash_ag_grid -p package-info.json --r-prefix '' --jl-prefix ''",
2020
"build": "run-s pre-flight-version && run-s prepublishOnly build:js build:backends",
21-
"postbuild": "es-check es2017 dash_ag_grid/*.js",
21+
"postbuild": "es-check es2018 dash_ag_grid/*.js",
2222
"private::format.eslint": "eslint --quiet --fix src",
2323
"private::format.prettier": "prettier --write src --ignore-path=.prettierignore",
2424
"format": "run-s private::format.*",
2525
"private::lint.eslint": "eslint src",
2626
"private::lint.prettier": "prettier src --list-different --ignore-path=.prettierignore",
2727
"lint": "run-s private::lint.*",
28-
"dist": "npm run build && run-s pre-flight-dag-version && python setup.py sdist bdist_wheel"
28+
"dist": "npm run build && run-s pre-flight-dag-version && python setup.py sdist bdist_wheel",
29+
"update-packages": "ncu -u && npm install"
2930
},
3031
"author": "Plotly <chris@plot.ly>",
3132
"license": "MIT",
3233
"dependencies": {
33-
"@emotion/react": "^11.11.3",
34-
"@emotion/styled": "^11.11.0",
35-
"@mui/icons-material": "^5.15.7",
36-
"@mui/material": "^5.15.7",
37-
"ag-grid-community": "35.0.0",
38-
"ag-grid-enterprise": "35.0.0",
39-
"ag-grid-react": "35.0.0",
40-
"d3-format": "^3.1.0",
34+
"@emotion/react": "^11.14.0",
35+
"@emotion/styled": "^11.14.1",
36+
"@mui/icons-material": "^7.3.9",
37+
"@mui/material": "^7.3.9",
38+
"ag-grid-community": "35.2.0",
39+
"ag-grid-enterprise": "35.2.0",
40+
"ag-grid-react": "35.2.0",
41+
"d3-format": "^3.1.2",
4142
"d3-time": "^3.1.0",
4243
"d3-time-format": "^4.1.0",
4344
"esprima": "^4.0.1",
44-
"ramda": "^0.29.1",
45-
"react-markdown": "^8.0.7",
45+
"npm-check-updates": "^19.6.3",
46+
"ramda": "^0.32.0",
47+
"react-markdown": "^10.1.0",
48+
"rehype-external-links": "^3.0.0",
4649
"rehype-raw": "^7.0.0",
47-
"remark-gfm": "^3.0.1",
50+
"remark-gfm": "^4.0.1",
4851
"static-eval": "^2.1.1"
4952
},
5053
"devDependencies": {
51-
"@babel/cli": "^7.23.9",
52-
"@babel/core": "^7.23.9",
53-
"@babel/eslint-parser": "^7.23.10",
54+
"@babel/cli": "^7.28.6",
55+
"@babel/core": "^7.29.0",
56+
"@babel/eslint-parser": "^7.28.6",
5457
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
55-
"@babel/preset-env": "^7.23.9",
56-
"@babel/preset-react": "^7.23.3",
58+
"@babel/preset-env": "^7.29.0",
59+
"@babel/preset-react": "^7.28.5",
5760
"@plotly/webpack-dash-dynamic-import": "^1.3.0",
58-
"babel-loader": "^9.1.3",
59-
"css-loader": "^6.10.0",
61+
"babel-loader": "^10.1.1",
62+
"css-loader": "^7.1.4",
6063
"es-check": "^7.1.1",
61-
"esbuild-loader": "^4.1.0",
64+
"esbuild-loader": "^4.4.2",
6265
"eslint": "^8.56.0",
63-
"eslint-config-prettier": "^9.1.0",
64-
"eslint-plugin-import": "^2.29.1",
65-
"eslint-plugin-react": "^7.33.2",
66+
"eslint-config-prettier": "^10.1.8",
67+
"eslint-plugin-import": "^2.32.0",
68+
"eslint-plugin-react": "^7.37.5",
6669
"npm-run-all": "^4.1.5",
67-
"prettier": "^3.2.4",
70+
"prettier": "^3.8.1",
6871
"prop-types": "^15.8.1",
69-
"react": "^18.2.0",
72+
"react": "^18.3.1",
7073
"react-docgen": "^5.4.3",
71-
"react-dom": "^18.2.0",
72-
"rimraf": "^5.0.5",
73-
"style-loader": "^3.3.4",
74-
"styled-jsx": "^5.1.2",
75-
"webpack": "^5.90.1",
76-
"webpack-cli": "^5.1.4"
74+
"react-dom": "^18.3.1",
75+
"rimraf": "^6.1.3",
76+
"style-loader": "^4.0.0",
77+
"styled-jsx": "^5.1.7",
78+
"webpack": "^5.105.4",
79+
"webpack-cli": "^6.0.1"
7780
},
7881
"files": [
7982
"/dash_ag_grid/*{.js,.map}",

src/lib/renderers/markdownRenderer.js

Lines changed: 36 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,39 +3,53 @@ import PropTypes from 'prop-types';
33

44
import rehypeRaw from 'rehype-raw';
55
import remarkGfm from 'remark-gfm';
6+
import rehypeExternalLinks from 'rehype-external-links';
67

78
import ReactMarkdown from 'react-markdown';
89

910
export default function MarkdownRenderer(props) {
10-
const {colDef, target, value, dangerously_allow_code} = props;
11+
const {colDef, value, dangerously_allow_code} = props;
1112
// Markdown renderer with HTML rendering enabled.
1213
// rehypeRaw allows HTML rendering.
1314
// Convert <p> tags to simple <divs> using the components prop.
1415
const rehypePlugins = dangerously_allow_code ? [rehypeRaw] : [];
1516

16-
let linkTarget;
17-
if (!dangerously_allow_code) {
18-
linkTarget = colDef.linkTarget || '_self';
19-
}
17+
const linkTarget = colDef.linkTarget || '_self';
18+
19+
rehypePlugins.push([
20+
rehypeExternalLinks,
21+
{
22+
target: dangerously_allow_code ? linkTarget : null,
23+
rel: ['noopener', 'noreferrer', 'nofollow'],
24+
},
25+
]);
2026

2127
return (
22-
<ReactMarkdown
23-
linkTarget={linkTarget}
24-
remarkPlugins={[[remarkGfm, {singleTilde: false}]]}
25-
components={{
26-
p: 'div',
27-
a: ({node: _, children, ...props}) => {
28-
const linkProps = props;
29-
if (target === '_blank') {
30-
linkProps.rel = 'noopener noreferrer';
31-
}
32-
return <a {...linkProps}>{children}</a>;
33-
},
34-
}}
35-
className="agGrid-Markdown"
36-
rehypePlugins={rehypePlugins}
37-
children={value ? String(value) : null}
38-
/>
28+
<div className="agGrid-Markdown">
29+
<ReactMarkdown
30+
remarkPlugins={[[remarkGfm, {singleTilde: false}]]}
31+
components={{
32+
p: 'div',
33+
a({node: _, children, target, ...props}) {
34+
const linkProps = props;
35+
const subLinkTarget = dangerously_allow_code
36+
? target || linkTarget
37+
: linkTarget;
38+
// Use the correct target for links
39+
if (subLinkTarget === '_blank') {
40+
linkProps.rel = 'noopener noreferrer nofollow';
41+
}
42+
return (
43+
<a {...{target: subLinkTarget, ...linkProps}}>
44+
{children}
45+
</a>
46+
);
47+
},
48+
}}
49+
rehypePlugins={rehypePlugins}
50+
children={value ? String(value) : null}
51+
/>
52+
</div>
3953
);
4054
}
4155

src/lib/utils/propCategories.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,7 @@ export const COLUMN_ARRAY_NESTED_FUNCTIONS = {
322322
export const OBJ_MAYBE_FUNCTION_OR_MAP_MAYBE_FUNCTIONS = {
323323
dataTypeDefinitions: 1,
324324
aggFuncs: 1,
325+
columnTypes: 1,
325326
};
326327

327328
/**

tests/test_cell_data_type_override.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,3 +80,70 @@ def test_cd001_cell_data_types_override(enforced_locale, dash_duo):
8080
date_input_element.send_keys("01172024" + Keys.ENTER)
8181

8282
grid.wait_for_cell_text(0, 1, "17/01/2024")
83+
84+
85+
def test_cd002_column_types_formatting(dash_duo):
86+
app = Dash(__name__)
87+
88+
rowData = [
89+
{"col1": 0.12345, "col2": 0.98765},
90+
{"col1": 0.5, "col2": 0.25},
91+
]
92+
93+
columnDefs = [
94+
{
95+
"field": "col1",
96+
"type": "rightAligned",
97+
"valueFormatter": {"function": "d3.format('.3f')(params.value)"},
98+
},
99+
{
100+
"field": "col2",
101+
"type": "float",
102+
},
103+
]
104+
105+
dashGridOptions = {
106+
"columnTypes": {
107+
"float": {
108+
"cellClass": "ag-right-aligned-cell",
109+
"headerClass": "ag-right-aligned-header",
110+
"valueFormatter": {
111+
"function": "d3.format('.3f')(params.value)"
112+
},
113+
}
114+
}
115+
}
116+
117+
app.layout = html.Div(
118+
[
119+
dag.AgGrid(
120+
id="grid-column-types",
121+
columnDefs=columnDefs,
122+
rowData=rowData,
123+
defaultColDef={"editable": True},
124+
dashGridOptions=dashGridOptions,
125+
)
126+
]
127+
)
128+
129+
dash_duo.start_server(app)
130+
131+
grid = utils.Grid(dash_duo, "grid-column-types")
132+
133+
action = utils.ActionChains(dash_duo.driver)
134+
135+
# ---- Test col1 formatter ----
136+
# edit valye
137+
action.double_click(grid.get_cell(0, 0)).perform()
138+
input_el = dash_duo.find_element("#grid-column-types .ag-input-field-input")
139+
input_el.send_keys("0.1" + Keys.ENTER)
140+
141+
# expect formatted to 3 decimals
142+
grid.wait_for_cell_text(0, 0, "0.100")
143+
144+
# ---- Test col2 formatter via column type ----
145+
action.double_click(grid.get_cell(0, 1)).perform()
146+
input_el = dash_duo.find_element("#grid-column-types .ag-input-field-input")
147+
input_el.send_keys("0.2" + Keys.ENTER)
148+
149+
grid.wait_for_cell_text(0, 1, "0.200")

tests/test_column_state.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -568,19 +568,18 @@ def toggle_column_visibility(selected_columns):
568568

569569
# Hide column 'b'
570570
dropdown = dash_duo.find_element("#select-columns")
571-
option_b = dash_duo.find_element('span.Select-value-icon:nth-child(1)')
571+
dropdown.click()
572+
option_b = dash_duo.find_element('label:nth-child(2) > span.dash-options-list-option-wrapper > input')
572573
option_b.click()
573574
time.sleep(1)
574575

575576
# Only column 'a' should be visible
576577
grid_headers = dash_duo.find_elements("div.ag-header-cell-label")
577578
header_texts = [h.text for h in grid_headers]
578-
assert "a" not in header_texts
579-
assert "b" in header_texts
579+
assert "a" in header_texts
580+
assert "b" not in header_texts
580581

581582
# Show both columns again
582-
dropdown.click()
583-
option_b = dash_duo.find_element('.Select-menu')
584583
option_b.click()
585584
time.sleep(1)
586585
grid_headers = dash_duo.find_elements("div.ag-header-cell-label")

tests/test_markdown_components.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -150,20 +150,20 @@ def test_mc001_markdown_components(dash_duo):
150150

151151
assert (
152152
safe_grid.get_cell(2, 2).get_attribute("innerHTML")
153-
== '<div class="agGrid-Markdown"><div><a href="#" target="_blank">Example</a></div></div>'
153+
== '<div class="agGrid-Markdown"><div><a target="_blank" href="#" rel="noopener noreferrer nofollow">Example</a></div></div>'
154154
)
155155
safe_grid.wait_for_cell_text(
156156
1, 2, '<a href="#" target="_blank">Link to new tab</a>'
157157
)
158158

159159
assert (
160160
dangerous_grid.get_cell(2, 2).get_attribute("innerHTML")
161-
== '<div class="agGrid-Markdown"><div><a href="#">Example</a></div></div>'
161+
== '<div class="agGrid-Markdown"><div><a target="_self" href="#">Example</a></div></div>'
162162
)
163163
dangerous_grid.wait_for_cell_text(1, 2, "Link to new tab")
164164
assert (
165165
dangerous_grid.get_cell(1, 2).get_attribute("innerHTML")
166-
== '<div class="agGrid-Markdown"><div><a href="#" target="_blank">Link to new tab</a></div></div>'
166+
== '<div class="agGrid-Markdown"><div><a target="_blank" href="#" rel="noopener noreferrer nofollow">Link to new tab</a></div></div>'
167167
)
168168

169169
assert safe2_grid.get_cell(0, 2).text == ""

0 commit comments

Comments
 (0)