Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add RBAC extensions and dashboard access management #793

Merged
merged 42 commits into from
Feb 28, 2024
Merged
Show file tree
Hide file tree
Changes from 36 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
ffbffd8
added the button and the new modal into the sidebar.
AleSim94 Jan 8, 2024
5397cb7
the access feature is almost done, now you can add labels to the db o…
AleSim94 Jan 12, 2024
ce9a2f9
added logic to showcase correct labels from the db for each dashboard…
AleSim94 Jan 15, 2024
202c9f8
quick design update + code refactor
AleSim94 Jan 15, 2024
f304556
changing from APOC to full cypher with string interpolation to preven…
alfredorubin96 Jan 15, 2024
fea0c95
added logic for handling issues with cleaning the state of the TextIn…
AleSim94 Jan 15, 2024
f8caba2
removed not needed import
AleSim94 Jan 15, 2024
b0789d1
fixing code smells from SonarQube
alfredorubin96 Jan 15, 2024
74f5179
Added skeleton for RBAC label button
nielsdejong Jan 19, 2024
c81f025
Merge with latest develop
nielsdejong Jan 19, 2024
9e7866d
Merge branch 'feature/customer_N_role_rbac_label' into feature/custom…
nielsdejong Jan 19, 2024
443f175
Re-added forms extension
nielsdejong Jan 19, 2024
2719066
added new components and new logic
AleSim94 Feb 2, 2024
a7e45dd
Added check for handling no access to view roles
nielsdejong Feb 2, 2024
41f28df
the modal structure is in place , added all dropdowns + updated useEf…
AleSim94 Feb 22, 2024
77503b6
small fix for the dropdown
AleSim94 Feb 22, 2024
995a8ae
Added retrieval of allow/denylists
nielsdejong Feb 22, 2024
34317e3
Minor fixes
nielsdejong Feb 22, 2024
4844156
added logic for users to be selected and added them in the handleSave…
AleSim94 Feb 22, 2024
b1f7e3f
Style fixes, aligned naming
nielsdejong Feb 22, 2024
c2af19a
Merge branch 'feature/customer_N_dashboard_RBAC_label' of github.com:…
nielsdejong Feb 22, 2024
a32586b
Iterating on assignment/revoking of privileges
nielsdejong Feb 22, 2024
a4757fd
added new images and doc for the new features
AleSim94 Feb 23, 2024
76ffc6b
added img for the modal
AleSim94 Feb 23, 2024
e454b5d
Docs
nielsdejong Feb 23, 2024
07cb4d8
Merge branch 'feature/customer_N_dashboard_RBAC_label' of github.com:…
nielsdejong Feb 23, 2024
80a9aa5
added new comment, removed text from button and added null to the whe…
AleSim94 Feb 26, 2024
196e29a
Handling grants/denies for labels, big code cleanup
nielsdejong Feb 26, 2024
1bd83b5
removed unnecessary imports and corrected misspellings
AleSim94 Feb 27, 2024
bc56edd
Added role assignment logic
nielsdejong Feb 27, 2024
d7aab00
Merge
nielsdejong Feb 27, 2024
54ffb23
Added in artificial delay to assign roles
nielsdejong Feb 27, 2024
fa99ffe
Updated docs and naming of the extension
nielsdejong Feb 27, 2024
978e6bc
updated the query and fixed bug for fetching allowDenyList whenever s…
AleSim94 Feb 27, 2024
5e35559
added 2 pics for access control that needs to be reviewed which one i…
AleSim94 Feb 27, 2024
bd4c41f
Merge branch 'develop' into feature/customer_N_dashboard_RBAC_label
nielsdejong Feb 28, 2024
481954e
Clean up files, final fixes to phrasing in docs
nielsdejong Feb 28, 2024
09e67a5
Merge branch 'develop' into feature/customer_N_dashboard_RBAC_label
nielsdejong Feb 28, 2024
ca59f09
Skip flaky tests
nielsdejong Feb 28, 2024
7bd6f7a
Merge branch 'develop' into feature/customer_N_dashboard_RBAC_label
nielsdejong Feb 28, 2024
89c29f9
Removed unneeded dashboard fetch for access control
nielsdejong Feb 28, 2024
751120d
Merge branch 'develop' into feature/customer_N_dashboard_RBAC_label
nielsdejong Feb 28, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/modules/ROOT/images/dashboardnew.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/modules/ROOT/images/rolelabelmodal.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/modules/ROOT/images/rolesmenu.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions docs/modules/ROOT/nav.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
*** xref:user-guide/extensions/report-actions.adoc[Report Actions]
*** xref:user-guide/extensions/natural-language-queries.adoc[Text2Cypher - Natural Language Queries]
*** xref:user-guide/extensions/forms.adoc[Forms]
*** xref:user-guide/extensions/access-control-management.adoc[Access Control Management]
** xref:user-guide/faq.adoc[FAQ]
* xref:developer-guide/index.adoc[Developer Guide]
** xref:developer-guide/build-and-run.adoc[Build & Run]
Expand Down
9 changes: 9 additions & 0 deletions docs/modules/ROOT/pages/user-guide/access-control.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
= Access Control

The Access Control feature in NeoDash is a security measure that allows Users with write access or higher privileges to manage who has access to specific dashboards.


== How it Works

Navigate to a specific dashboard and inside the dashboard settings click on the 'Access Control' option in the dashboard sidebar. This opens a modal where users can add labels to the dashboard. These labels are then used to determine which users have access to the dashboard. Please keep in mind that prior to doing this, an administrator needs to provide certain privileges for different user roles for each label in order for this to work. You can read more about how RBAC works in Neo4j by reading the [Neo4j RBAC documentation](https://neo4j.com/docs/operations-manual/current/authentication-authorization/manage-privileges/).

13 changes: 11 additions & 2 deletions docs/modules/ROOT/pages/user-guide/dashboards.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
In NeoDash, a dashboard consists of several pages, each of which can
consist of multiple reports.

image::dashboard2.png[Dashboard]
image::dashboardnew.png[Dashboard]

As an example: The screenshot above shows a dashboard with three pages:
`Breweries`, `Beer Ratings` and `Styles`. The dashboard title `My
Expand All @@ -21,7 +21,7 @@ dashboard or open an existing one (if available). After being connected,
the buttons on the sidebar can be used to save, load or share a
dashboard.

image::saveloadshare.png[Save/Load/Share Button]
image::dashboardnewsettings.png[Save/Load/Share Button]

=== Save a Dashboard

Expand Down Expand Up @@ -115,6 +115,15 @@ When creating a NeoDash deployment on a production database, it is not
recommended to use the `Share' feature. Rather, set up a dedicated
standalone deployment of NeoDash. See Publishing for more infomation.

=== Dashboard Access Control
With this feature, you can manage dashboard access by leveraging the native Neo4j Role-based Access Control (RBAC) functionality. Attach additional labels to the currently selected dashboard node within this window, either by utilizing existing labels in your database or creating new ones, to regulate access permissions.

You can find the Dashboard Access Control feature by clicking on the three dots next to the dashboard name in the sidebar and selecting the "Access Control" option.

> This approach should be used together with restricted privileges on labels, assigned to certain roles. See link:../extensions/access-control-management[Access Control Management] for details.

image::dashboardaccesscontrol.png[Dashboard Access Control]

== Dashboard Settings

Settings for the entire dashboard can be accessed by clicking the
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
= Access Control Management

This extension lets you manage access control for roles and users, letting you assign, users to roles as well as controlling which node labels can be read by a user.

This extension is only visible to users with the role of "Administrator" or "Super User". Enabling this extension will allow the admin user to manage the labels of the roles in the database and then attach them to the users.


== Using the Extension ==
If you have logged in to Neodash as an admin user, you will be able to enable the extension in the "Extensions" menu. Clicking on this extension will give the user an new button next to settings button in the main dashboard page. If the user click on this button, a menu will appear with all the roles in the database.

image::rolesmenu.png[Role menu]

The user can then click on any role and a window will appear with the role's context:

* User list - This is a list of users from your database. You can select multiple users from the list and the role will be added to all the selected users.

* Allow list - This is a list of labels that the role will be granted to read. You can select multiple labels from the list or if you want every label to be granted, you can select "*" from the list. (Requires a database to be selected)

* Deny list - This is a list of labels that the role will be denied to read. You can select multiple labels from the list or if you want every label to be denied, you can select "*" from the list. (Requires a database to be selected)


Finally when the admin user clicks on the "Save" button, the role will be updated in the database and the labels will be granted or denied to the users that were selected for the specific role and database.

image::rolelabelmodal.png[Role modal]

> Universal (Cross-database) `GRANT` and `DENY` privileges are not supported by this extension. Privileges must be added on a database-specific level. See the Neo4j https://neo4j.com/docs/operations-manual/current/authentication-authorization/privileges-reads/[documentation on read privileges] for more information.
1 change: 1 addition & 0 deletions docs/modules/ROOT/pages/user-guide/extensions/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ The currently available extensions in NeoDash are:
- link:report-actions[Report Actions]
- link:natural-language-queries[Text2Cypher - Natural Language Queries]
- link:forms[Forms]
- link:access-control-management[Access Control Management]

== Types of Extensions

Expand Down
Binary file added public/accesscontrol.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/accesscontrol2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/dashboard/header/DashboardTitle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,10 @@ export const NeoDashboardTitle = ({
{/* If the app is not running in standalone mode (i.e. in edit mode) always show dashboard settings. */}
{!standaloneSettings.standalone ? (
<div className='flex flex-row flex-wrap items-center gap-2'>
{editable ? renderExtensionsButtons() : <></>}
<NeoSettingsModal dashboardSettings={dashboardSettings} updateDashboardSetting={updateDashboardSetting} />
{editable ? <NeoExportModal /> : <></>}
{editable ? <NeoExtensionsModal closeMenu={handleSettingsMenuClose} /> : <></>}
{editable ? renderExtensionsButtons() : <></>}
</div>
) : (
<></>
Expand Down
20 changes: 20 additions & 0 deletions src/dashboard/sidebar/DashboardSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import NeoDashboardSidebarDeleteModal from './modal/DashboardSidebarDeleteModal';
import NeoDashboardSidebarInfoModal from './modal/DashboardSidebarInfoModal';
import NeoDashboardSidebarShareModal from './modal/DashboardSidebarShareModal';
import NeoDashboardSidebarAccessModal from './modal/DashboardSidebarAccessModal';
import LegacyShareModal from './modal/legacy/LegacyShareModal';
import { NEODASH_VERSION } from '../DashboardReducer';

Expand All @@ -67,6 +68,7 @@
LOAD = 7,
SAVE = 8,
NONE = 9,
ACCESS = 10,
}

// We use "index = -1" to represent a non-saved draft dashboard in the sidebar's dashboard list.
Expand Down Expand Up @@ -256,6 +258,16 @@
}}
/>

<NeoDashboardSidebarAccessModal
open={modalOpen == Modal.ACCESS}
database={dashboardDatabase}
dashboard={dashboards[inspectedIndex]}
handleClose={() => {
setModalOpen(Modal.NONE);
setCachedDashboard('');

Check warning on line 267 in src/dashboard/sidebar/DashboardSidebar.tsx

View check run for this annotation

Codecov / codecov/patch

src/dashboard/sidebar/DashboardSidebar.tsx#L265-L267

Added lines #L265 - L267 were not covered by tests
}}
/>

<SideNavigation
position='left'
type='overlay'
Expand Down Expand Up @@ -336,6 +348,14 @@
setMenuOpen(Menu.NONE);
setModalOpen(Modal.SHARE);
}}
handleAccessClicked={() => {
nielsdejong marked this conversation as resolved.
Show resolved Hide resolved
setMenuOpen(Menu.NONE);
const d = dashboards[inspectedIndex];
loadDashboardFromNeo4j(driver, dashboardDatabase, d.uuid, (text) => {
setCachedDashboard(JSON.parse(text));

Check warning on line 355 in src/dashboard/sidebar/DashboardSidebar.tsx

View check run for this annotation

Codecov / codecov/patch

src/dashboard/sidebar/DashboardSidebar.tsx#L351-L355

Added lines #L351 - L355 were not covered by tests
});
setModalOpen(Modal.ACCESS);

Check warning on line 357 in src/dashboard/sidebar/DashboardSidebar.tsx

View check run for this annotation

Codecov / codecov/patch

src/dashboard/sidebar/DashboardSidebar.tsx#L357

Added line #L357 was not covered by tests
}}
handleDeleteClicked={() => {
setMenuOpen(Menu.NONE);
setModalOpen(Modal.DELETE);
Expand Down
3 changes: 3 additions & 0 deletions src/dashboard/sidebar/menu/DashboardSidebarDashboardMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
DocumentTextIconOutline,
InformationCircleIconOutline,
ShareIconOutline,
FingerPrintIconOutline,
TrashIconOutline,
XMarkIconOutline,
} from '@neo4j-ndl/react/icons';
Expand All @@ -25,6 +26,7 @@ export const NeoDashboardSidebarDashboardMenu = ({
handleLoadClicked,
handleExportClicked,
handleShareClicked,
handleAccessClicked,
handleDeleteClicked,
handleClose,
}) => {
Expand All @@ -49,6 +51,7 @@ export const NeoDashboardSidebarDashboardMenu = ({
<MenuItem onClick={handleLoadClicked} icon={<CloudArrowUpIconOutline />} title='Load' />
{/* <MenuItem onClick={() => {}} icon={<DocumentDuplicateIconOutline />} title='Clone' /> */}
<MenuItem onClick={handleExportClicked} icon={<DocumentTextIconOutline />} title='Export' />
<MenuItem onClick={handleAccessClicked} icon={<FingerPrintIconOutline />} title='Access' />
<MenuItem onClick={handleShareClicked} icon={<ShareIconOutline />} title='Share' />
<MenuItem onClick={handleDeleteClicked} icon={<TrashIconOutline />} title='Delete' />
</MenuItems>
Expand Down
215 changes: 215 additions & 0 deletions src/dashboard/sidebar/modal/DashboardSidebarAccessModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
import React, { useEffect, useState, useContext } from 'react';
import { IconButton, Button, Dialog, TextInput } from '@neo4j-ndl/react';
import { Menu, MenuItem, Chip } from '@mui/material';
import { Neo4jContext, Neo4jContextState } from 'use-neo4j/dist/neo4j.context';
import { PlusCircleIconOutline } from '@neo4j-ndl/react/icons';
import { QueryStatus, runCypherQuery } from '../../../report/ReportQueryRunner';
import { createNotificationThunk } from '../../../page/PageThunks';
import { useDispatch } from 'react-redux';
/**
* Configures setting the current Neo4j database connection for the dashboard.
* @param open - Whether the modal is open or not.
* @param database - The current Neo4j database.
* @param dashboard - The current dashboard.
* @param handleClose - The function to close the modal.
*/
export const NeoDashboardSidebarAccessModal = ({ open, database, dashboard, handleClose }) => {
const [anchorEl, setAnchorEl] = useState(null);
const [selectedLabels, setSelectedLabels] = useState([]);
const [allLabels, setAllLabels] = useState([]);
const [neo4jLabels, setNeo4jLabels] = useState([]);
const [newLabel, setNewLabel] = useState('');
const INITIAL_LABEL = '_Neodash_Dashboard';
const [feedback, setFeedback] = useState('');
const { driver } = useContext<Neo4jContextState>(Neo4jContext);
const dispatch = useDispatch();

useEffect(() => {
if (!open) {
return;
}
runCypherQuery(

Check warning on line 31 in src/dashboard/sidebar/modal/DashboardSidebarAccessModal.tsx

View check run for this annotation

Codecov / codecov/patch

src/dashboard/sidebar/modal/DashboardSidebarAccessModal.tsx#L31

Added line #L31 was not covered by tests
driver,
database,
'CALL db.labels()',
{},
1000,
() => {},
(records) => setNeo4jLabels(records.map((record) => record.get('label')))

Check warning on line 38 in src/dashboard/sidebar/modal/DashboardSidebarAccessModal.tsx

View check run for this annotation

Codecov / codecov/patch

src/dashboard/sidebar/modal/DashboardSidebarAccessModal.tsx#L37-L38

Added lines #L37 - L38 were not covered by tests
);

const query = `

Check warning on line 41 in src/dashboard/sidebar/modal/DashboardSidebarAccessModal.tsx

View check run for this annotation

Codecov / codecov/patch

src/dashboard/sidebar/modal/DashboardSidebarAccessModal.tsx#L41

Added line #L41 was not covered by tests
MATCH (d:${INITIAL_LABEL} {uuid: "${dashboard.uuid}"})
RETURN labels(d) as labels
`;
runCypherQuery(

Check warning on line 45 in src/dashboard/sidebar/modal/DashboardSidebarAccessModal.tsx

View check run for this annotation

Codecov / codecov/patch

src/dashboard/sidebar/modal/DashboardSidebarAccessModal.tsx#L45

Added line #L45 was not covered by tests
driver,
database,
query,
{},
1000,
(error) => {
console.error(error);

Check warning on line 52 in src/dashboard/sidebar/modal/DashboardSidebarAccessModal.tsx

View check run for this annotation

Codecov / codecov/patch

src/dashboard/sidebar/modal/DashboardSidebarAccessModal.tsx#L51-L52

Added lines #L51 - L52 were not covered by tests
},
(records) => {

Check warning on line 54 in src/dashboard/sidebar/modal/DashboardSidebarAccessModal.tsx

View check run for this annotation

Codecov / codecov/patch

src/dashboard/sidebar/modal/DashboardSidebarAccessModal.tsx#L54

Added line #L54 was not covered by tests
// Set the selectedLabels state to the labels of the dashboard
setSelectedLabels(records[0].get('labels'));
setAllLabels(records[0].get('labels'));

Check warning on line 57 in src/dashboard/sidebar/modal/DashboardSidebarAccessModal.tsx

View check run for this annotation

Codecov / codecov/patch

src/dashboard/sidebar/modal/DashboardSidebarAccessModal.tsx#L56-L57

Added lines #L56 - L57 were not covered by tests
}
);
setFeedback('');
setNewLabel('');

Check warning on line 61 in src/dashboard/sidebar/modal/DashboardSidebarAccessModal.tsx

View check run for this annotation

Codecov / codecov/patch

src/dashboard/sidebar/modal/DashboardSidebarAccessModal.tsx#L60-L61

Added lines #L60 - L61 were not covered by tests
}, [open]);

useEffect(() => {
setAllLabels([INITIAL_LABEL]);
setSelectedLabels([INITIAL_LABEL]);
}, []);

const handleOpenMenu = (event) => {
setAnchorEl(event.currentTarget);

Check warning on line 70 in src/dashboard/sidebar/modal/DashboardSidebarAccessModal.tsx

View check run for this annotation

Codecov / codecov/patch

src/dashboard/sidebar/modal/DashboardSidebarAccessModal.tsx#L70

Added line #L70 was not covered by tests
};

const handleCloseMenu = () => {
setAnchorEl(null);

Check warning on line 74 in src/dashboard/sidebar/modal/DashboardSidebarAccessModal.tsx

View check run for this annotation

Codecov / codecov/patch

src/dashboard/sidebar/modal/DashboardSidebarAccessModal.tsx#L74

Added line #L74 was not covered by tests
};

const handleLabelSelect = (label) => {
if (!selectedLabels.includes(label) && label !== INITIAL_LABEL) {
setSelectedLabels([...selectedLabels, label]);

Check warning on line 79 in src/dashboard/sidebar/modal/DashboardSidebarAccessModal.tsx

View check run for this annotation

Codecov / codecov/patch

src/dashboard/sidebar/modal/DashboardSidebarAccessModal.tsx#L79

Added line #L79 was not covered by tests
}
handleCloseMenu();

Check warning on line 81 in src/dashboard/sidebar/modal/DashboardSidebarAccessModal.tsx

View check run for this annotation

Codecov / codecov/patch

src/dashboard/sidebar/modal/DashboardSidebarAccessModal.tsx#L81

Added line #L81 was not covered by tests
};

const handleDeleteLabel = (label) => {
if (label !== INITIAL_LABEL) {
const updatedLabels = selectedLabels.filter((selectedLabel) => selectedLabel !== label);
setSelectedLabels(updatedLabels);

Check warning on line 87 in src/dashboard/sidebar/modal/DashboardSidebarAccessModal.tsx

View check run for this annotation

Codecov / codecov/patch

src/dashboard/sidebar/modal/DashboardSidebarAccessModal.tsx#L86-L87

Added lines #L86 - L87 were not covered by tests
}
};

const handleAddNewLabel = (e) => {
if (e.key === 'Enter' && newLabel.trim() !== '') {
if (selectedLabels.includes(newLabel)) {
setFeedback('Label already exists. Please enter a unique label.');
handleCloseMenu();
} else {
setSelectedLabels([...selectedLabels, newLabel]);
handleLabelSelect(newLabel);
setNewLabel('');
handleCloseMenu();
setFeedback('');

Check warning on line 101 in src/dashboard/sidebar/modal/DashboardSidebarAccessModal.tsx

View check run for this annotation

Codecov / codecov/patch

src/dashboard/sidebar/modal/DashboardSidebarAccessModal.tsx#L94-L101

Added lines #L94 - L101 were not covered by tests
}
}
};

const handleSave = () => {
// Finding the difference between what is stored and what has been selected in the UI
let toDelete = allLabels.filter((item) => selectedLabels.indexOf(item) < 0);

Check warning on line 108 in src/dashboard/sidebar/modal/DashboardSidebarAccessModal.tsx

View check run for this annotation

Codecov / codecov/patch

src/dashboard/sidebar/modal/DashboardSidebarAccessModal.tsx#L108

Added line #L108 was not covered by tests

const query = `

Check warning on line 110 in src/dashboard/sidebar/modal/DashboardSidebarAccessModal.tsx

View check run for this annotation

Codecov / codecov/patch

src/dashboard/sidebar/modal/DashboardSidebarAccessModal.tsx#L110

Added line #L110 was not covered by tests
MATCH (d:${INITIAL_LABEL} {uuid: "${dashboard.uuid}"})
SET d:${selectedLabels.join(':')}
${toDelete.length > 0 ? `REMOVE d:${toDelete.join(':')}` : ''}
RETURN 1;
`;

runCypherQuery(

Check warning on line 117 in src/dashboard/sidebar/modal/DashboardSidebarAccessModal.tsx

View check run for this annotation

Codecov / codecov/patch

src/dashboard/sidebar/modal/DashboardSidebarAccessModal.tsx#L117

Added line #L117 was not covered by tests
driver,
database,
query,
{ selectedLabels: selectedLabels },
1000,
(status) => {

Check warning on line 123 in src/dashboard/sidebar/modal/DashboardSidebarAccessModal.tsx

View check run for this annotation

Codecov / codecov/patch

src/dashboard/sidebar/modal/DashboardSidebarAccessModal.tsx#L123

Added line #L123 was not covered by tests
if (status == QueryStatus.COMPLETE) {
dispatch(

Check warning on line 125 in src/dashboard/sidebar/modal/DashboardSidebarAccessModal.tsx

View check run for this annotation

Codecov / codecov/patch

src/dashboard/sidebar/modal/DashboardSidebarAccessModal.tsx#L125

Added line #L125 was not covered by tests
createNotificationThunk(
'🎉 Success!',
'Selected Labels have successfully been added to the dashboard node.'
)
);
handleClose();
} else {
dispatch(

Check warning on line 133 in src/dashboard/sidebar/modal/DashboardSidebarAccessModal.tsx

View check run for this annotation

Codecov / codecov/patch

src/dashboard/sidebar/modal/DashboardSidebarAccessModal.tsx#L131-L133

Added lines #L131 - L133 were not covered by tests
createNotificationThunk(
'Unable to save dashboard',
`Do you have write access to the '${database}' database?`
)
);
}
},
() => {}

Check warning on line 141 in src/dashboard/sidebar/modal/DashboardSidebarAccessModal.tsx

View check run for this annotation

Codecov / codecov/patch

src/dashboard/sidebar/modal/DashboardSidebarAccessModal.tsx#L141

Added line #L141 was not covered by tests
);
};

return (
<Dialog size='small' open={open} onClose={handleClose} aria-labelledby='form-dialog-title'>
<Dialog.Header id='form-dialog-title'>Dasboard Access Control - '{dashboard?.title}'</Dialog.Header>
<Dialog.Content>
Welcome to the Dashboard Access settings!
<br />
In this modal, you can select the labels that you want to add to the current dashboard node.
<br />
For more information, please refer to the{' '}
<a
href='https://neo4j.com/labs/neodash/2.4/user-guide/access-control-management/'
target='_blank'
rel='noopener noreferrer'
style={{ color: 'blue', textDecoration: 'underline' }}
>
documentation
</a>
.
</Dialog.Content>
<div>
<Menu anchorEl={anchorEl} open={Boolean(anchorEl)} onClose={handleCloseMenu}>
{/* Fetch labels dynamically from Neo4j and map to menu items */}
{neo4jLabels
.filter((e) => !selectedLabels.includes(e))

Check warning on line 168 in src/dashboard/sidebar/modal/DashboardSidebarAccessModal.tsx

View check run for this annotation

Codecov / codecov/patch

src/dashboard/sidebar/modal/DashboardSidebarAccessModal.tsx#L168

Added line #L168 was not covered by tests
.map((label) => (
<MenuItem key={label} onClick={() => handleLabelSelect(label)}>

Check warning on line 170 in src/dashboard/sidebar/modal/DashboardSidebarAccessModal.tsx

View check run for this annotation

Codecov / codecov/patch

src/dashboard/sidebar/modal/DashboardSidebarAccessModal.tsx#L170

Added line #L170 was not covered by tests
{label}
</MenuItem>
))}
<MenuItem>
<TextInput
value={newLabel}
onChange={(e) => setNewLabel(e.target.value)}
onKeyDown={(e: KeyboardEvent) => {
handleAddNewLabel(e);
e.stopPropagation();

Check warning on line 180 in src/dashboard/sidebar/modal/DashboardSidebarAccessModal.tsx

View check run for this annotation

Codecov / codecov/patch

src/dashboard/sidebar/modal/DashboardSidebarAccessModal.tsx#L177-L180

Added lines #L177 - L180 were not covered by tests
}}
errorText={feedback}
placeholder='Create New label'
autoComplete='off'
/>
</MenuItem>
</Menu>
<div style={{ display: 'flex', flexWrap: 'wrap', alignItems: 'center', marginTop: '10px' }}>
{selectedLabels.map((label) => (
<Chip
key={label}
label={label}
variant='outlined'
onDelete={label === INITIAL_LABEL ? undefined : () => handleDeleteLabel(label)}
style={{ marginRight: '5px', marginBottom: '5px' }}
/>
))}
<IconButton title='Add Label' size='large' clean style={{ marginBottom: '5px' }} onClick={handleOpenMenu}>
<PlusCircleIconOutline color='#018BFF' />
</IconButton>
</div>
</div>
<Dialog.Actions>
<Button onClick={handleClose} style={{ float: 'right' }} fill='outlined' floating>
Cancel
</Button>
<Button onClick={handleSave} color='primary' style={{ float: 'right', marginRight: '10px' }} floating>
Save
</Button>
</Dialog.Actions>
</Dialog>
);
};

export default NeoDashboardSidebarAccessModal;
Loading
Loading