Skip to content

Commit 6b11588

Browse files
Merge branch 'develop' into fix/ParameterListParse
2 parents 03ed871 + 58c8bc5 commit 6b11588

File tree

12 files changed

+71
-37
lines changed

12 files changed

+71
-37
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
"d3-scale-chromatic": "^3.0.0",
6666
"dayjs": "^1.11.7",
6767
"dom-to-image": "^2.6.0",
68+
"dompurify": "^3.1.0",
6869
"leaflet": "^1.7.1",
6970
"lodash.debounce": "^4.0.8",
7071
"lodash.isequal": "^4.5.0",

public/style.css

Lines changed: 18 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -125,17 +125,13 @@
125125
margin-top: -10px;
126126
}
127127

128-
.MuiDataGrid-virtualScroller {
129-
overflow-y: hidden !important;
130-
}
131-
132-
.MuiDataGrid-panel{
128+
.MuiDataGrid-panel {
133129
translate: 0px -152%;
134130
}
135131

136132
.MuiCard-root {
137-
box-shadow: 0 0 #0000,0 0 #0000,var(--tw-shadow) !important;
138-
box-shadow: var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow) !important;
133+
box-shadow: 0 0 #0000, 0 0 #0000, var(--tw-shadow) !important;
134+
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow) !important;
139135
}
140136

141137
.white-text {
@@ -188,7 +184,6 @@
188184
text-align: center;
189185
}
190186

191-
192187
.card-view.expanded {
193188
position: absolute;
194189
top: 0;
@@ -218,24 +213,23 @@
218213

219214
.card-view .MuiTablePagination-root {
220215
margin-top: 0px;
221-
222216
}
223217

224218
@keyframes pulse {
225-
0% {
226-
transform: scale(0.95);
227-
box-shadow: 0 0 0 0 rgba(0, 0, 0, 0.7);
228-
}
219+
0% {
220+
transform: scale(0.95);
221+
box-shadow: 0 0 0 0 rgba(0, 0, 0, 0.7);
222+
}
229223

230-
70% {
231-
transform: scale(1);
232-
box-shadow: 0 0 0 10px rgba(0, 0, 0, 0);
233-
}
224+
70% {
225+
transform: scale(1);
226+
box-shadow: 0 0 0 10px rgba(0, 0, 0, 0);
227+
}
234228

235-
100% {
236-
transform: scale(0.95);
237-
box-shadow: 0 0 0 0 rgba(0, 0, 0, 0);
238-
}
229+
100% {
230+
transform: scale(0.95);
231+
box-shadow: 0 0 0 0 rgba(0, 0, 0, 0);
232+
}
239233
}
240234

241235
/* Workaround for Needle not handling menu placement of dropdowns on modals */
@@ -247,14 +241,14 @@
247241
/* End workaround */
248242

249243
/* Workaround for cleaning the Gantt chart UI */
250-
.gantt-wrapper > div > div:first-child > div:first-child > div:first-child > div> div:not(:first-child) {
244+
.gantt-wrapper > div > div:first-child > div:first-child > div:first-child > div > div:not(:first-child) {
251245
display: none;
252246
}
253-
.gantt-wrapper > div > div > div > div> div> div> div:not(:first-child) {
247+
.gantt-wrapper > div > div > div > div > div > div > div:not(:first-child) {
254248
display: none;
255249
}
256250
/* End Gantt chart workaround */
257251

258252
.markdown-widget a {
259253
text-decoration: underline;
260-
}
254+
}

src/chart/graph/component/GraphEntityInspectionTable.tsx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,19 @@ import React from 'react';
22
import ShowMoreText from 'react-show-more-text';
33
import { Checkbox, Table, TableBody, TableCell, TableContainer, TableHead, TableRow } from '@mui/material';
44
import { TextLink } from '@neo4j-ndl/react';
5+
import DOMPurify from 'dompurify';
56

67
export const formatProperty = (property) => {
7-
if (property.startsWith('http://') || property.startsWith('https://')) {
8+
const str = property?.toString() || '';
9+
if (str.startsWith('http://') || str.startsWith('https://')) {
810
return (
9-
<TextLink externalLink href={property}>
10-
{property}
11+
<TextLink externalLink href={str}>
12+
{str}
1113
</TextLink>
1214
);
1315
}
14-
return property;
16+
const cleanValue = DOMPurify.sanitize(str);
17+
return <div dangerouslySetInnerHTML={{ __html: cleanValue }} />;
1518
};
1619

1720
/**
@@ -88,7 +91,7 @@ export const GraphEntityInspectionTable = ({
8891
{key}
8992
</TableCell>
9093
<TableCell align={'left'} style={{ color: tableTextColor }}>
91-
<ShowMoreText lines={2}>{formatProperty(entity && entity.properties[key].toString())}</ShowMoreText>
94+
<ShowMoreText lines={2}>{formatProperty(entity?.properties[key])}</ShowMoreText>
9295
</TableCell>
9396
{checklistEnabled ? (
9497
<TableCell align={'center'}>

src/chart/parameter/ParameterSelectionChart.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ export const NeoParameterSelectionChart = (props: ChartProps) => {
9494
compatibilityMode={compatibilityMode}
9595
multiSelector={multiSelector}
9696
manualParameterSave={manualParameterSave}
97+
autoSort={true}
9798
/>
9899
);
99100
} else if (type == 'Relationship Property') {
@@ -112,6 +113,7 @@ export const NeoParameterSelectionChart = (props: ChartProps) => {
112113
compatibilityMode={compatibilityMode}
113114
multiSelector={multiSelector}
114115
manualParameterSave={manualParameterSave}
116+
autoSort={true}
115117
/>
116118
);
117119
} else if (type == 'Date Picker') {
@@ -147,6 +149,7 @@ export const NeoParameterSelectionChart = (props: ChartProps) => {
147149
compatibilityMode={compatibilityMode}
148150
multiSelector={multiSelector}
149151
manualParameterSave={manualParameterSave}
152+
autoSort={false}
150153
/>
151154
);
152155
}

src/chart/parameter/component/NodePropertyParameterSelect.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,12 +165,14 @@ const NodePropertyParameterSelectComponent = (props: ParameterSelectProps) => {
165165
/>
166166
);
167167
}
168+
let options = extraRecords?.map((r) => r?._fields?.[displayValueRowIndex] || '(no data)');
169+
options = props.autoSort ? options.sort() : options;
168170
return (
169171
<div className={'n-flex n-flex-row n-flex-wrap n-items-center'}>
170172
<Autocomplete
171173
id='autocomplete'
172174
multiple={multiSelector}
173-
options={extraRecords?.map((r) => r?._fields?.[displayValueRowIndex] || '(no data)').sort()}
175+
options={options}
174176
disabled={disabled}
175177
limitTags={multiSelectLimit}
176178
style={{
@@ -198,7 +200,8 @@ const NodePropertyParameterSelectComponent = (props: ParameterSelectProps) => {
198200
if (autoSelectFirstValue && paramValueDisplayLocal == '') {
199201
debouncedQueryCallback(props.query, { input: '', ...allParameters }, (records) => {
200202
if (records && records.length > 0 && records[0] && records[0]._fields) {
201-
const values = records?.map((r) => r?._fields?.[displayValueRowIndex] || '(no data)').sort();
203+
let values = records?.map((r) => r?._fields?.[displayValueRowIndex] || '(no data)');
204+
values = props.autoSort ? values.sort() : values;
202205
setExtraRecords(records);
203206
propagateSelection(undefined, values[0]);
204207
}

src/chart/parameter/component/ParameterSelect.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,8 @@ export interface ParameterSelectProps {
6262
* Add the possibility for manual selection confirmation
6363
*/
6464
manualParameterSave?: boolean;
65+
/**
66+
* Pass true if results should be sorted automatically
67+
*/
68+
autoSort?: boolean;
6569
}

src/chart/parameter/component/QueryParameterSelect.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ const QueryParameterSelectComponent = (props: ParameterSelectProps) => {
1717
allParameters={props.allParameters}
1818
compatibilityMode={props.compatibilityMode}
1919
multiSelector={props.multiSelector}
20+
autoSort={props.autoSort}
2021
/>
2122
);
2223
};

src/chart/table/TableChart.tsx

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,15 @@ const fallbackRenderer = (value) => {
3838
return JSON.stringify(value);
3939
};
4040

41+
function htmlToPlainText(html): string {
42+
// Create a temporary div element to hold the sanitized HTML content
43+
const tempElement = document.createElement('div');
44+
// Set the HTML content directly as innerHTML of the temporary element
45+
tempElement.innerHTML = html.props.dangerouslySetInnerHTML.__html;
46+
// Extract plain text using textContent
47+
return tempElement.textContent ?? '';
48+
}
49+
4150
function renderAsButtonWrapper(renderer) {
4251
return function renderAsButton(value) {
4352
const outputValue = renderer(value, true);
@@ -50,7 +59,7 @@ function renderAsButtonWrapper(renderer) {
5059
style={{ width: '100%', marginLeft: '5px', marginRight: '5px' }}
5160
variant='contained'
5261
color='primary'
53-
>{outputValue}</Button>
62+
>{`${htmlToPlainText(outputValue)}`}</Button>
5463
);
5564
};
5665
}
@@ -262,7 +271,8 @@ export const NeoTableChart = (props: ChartProps) => {
262271
<DataGrid
263272
key={'tableKey'}
264273
headerHeight={32}
265-
rowHeight={tableRowHeight}
274+
density={compact ? 'compact' : 'standard'}
275+
getRowHeight={() => 'auto'}
266276
rows={rows}
267277
columns={columns}
268278
columnVisibilityModel={columnVisibilityModel}
@@ -305,6 +315,12 @@ export const NeoTableChart = (props: ChartProps) => {
305315
})
306316
.join(' ');
307317
}}
318+
sx={{
319+
'&.MuiDataGrid-root--densityCompact .MuiDataGrid-cell': { py: '3px' },
320+
'&.MuiDataGrid-root--densityStandard .MuiDataGrid-cell': { py: '15px' },
321+
'&.MuiDataGrid-root--densityComfortable .MuiDataGrid-cell': { py: '22px' },
322+
'&.MuiDataGrid-root .MuiDataGrid-cell': { wordBreak: 'break-word' },
323+
}}
308324
/>
309325
</div>
310326
</ThemeProvider>

src/extensions/rbac/RBACManagementMenu.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ export const RBACManagementMenu = ({ anchorEl, MenuOpen, handleClose, createNoti
6464
onClose={handleClose}
6565
size='small'
6666
>
67-
<MenuItems>
67+
<MenuItems className='n-overflow-y-scroll n-h-44'>
6868
{roles.map((role) => (
6969
<MenuItem key={role} onClick={() => handleRoleClicked(role)} icon={<UserIconOutline />} title={role} />
7070
))}

src/extensions/rbac/RBACUtils.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -258,10 +258,11 @@ export function retrieveDatabaseList(driver, setDatabases: React.Dispatch<React.
258258
export async function updateUsers(driver, currentRole, allUsers, selectedUsers, onSuccess, onFail) {
259259
// 1. Build the query that removes all users from the role.
260260
let globalStatus = -1;
261+
const escapedAllUsers = allUsers.map((user) => `\`${user}\``).join(',');
261262
await runCypherQuery(
262263
driver,
263264
'system',
264-
`REVOKE ROLE ${currentRole} FROM ${allUsers.join(',')}`,
265+
`REVOKE ROLE ${currentRole} FROM ${escapedAllUsers}`,
265266
{},
266267
1000,
267268
(status) => {
@@ -277,10 +278,11 @@ export async function updateUsers(driver, currentRole, allUsers, selectedUsers,
277278
// TODO: Neo4j is very slow in updating after the previous query, even though it is technically a finished query.
278279
// We build in an artificial delay...
279280
if (selectedUsers.length > 0) {
281+
const escapedSelectedUsers = selectedUsers.map((user) => `\`${user}\``).join(',');
280282
await runCypherQuery(
281283
driver,
282284
'system',
283-
`GRANT ROLE ${currentRole} TO ${selectedUsers.join(',')}`,
285+
`GRANT ROLE ${currentRole} TO ${escapedSelectedUsers}`,
284286
{},
285287
1000,
286288
(status) => {

0 commit comments

Comments
 (0)