Added option for query permission in the popup and integration app permissions modal

This commit is contained in:
devanshu052000 2025-05-28 02:59:09 +05:30
parent cbf908362c
commit c2fc4fe60f
4 changed files with 78 additions and 13 deletions

View file

@ -1,5 +1,6 @@
import React, { useState, useCallback } from 'react'; import React, { useState, useCallback } from 'react';
import { Tooltip } from 'react-tooltip'; import { Tooltip } from 'react-tooltip';
import { ToolTip } from '@/_components/ToolTip';
import { updateQuerySuggestions } from '@/_helpers/appUtils'; import { updateQuerySuggestions } from '@/_helpers/appUtils';
// import { Confirm } from '../Viewer/Confirm'; // import { Confirm } from '../Viewer/Confirm';
import { toast } from 'react-hot-toast'; import { toast } from 'react-hot-toast';
@ -18,6 +19,7 @@ import Edit from '@/_ui/Icon/bulkIcons/Edit';
import Trash from '@/_ui/Icon/solidIcons/Trash'; import Trash from '@/_ui/Icon/solidIcons/Trash';
import { OverlayTrigger, Popover } from 'react-bootstrap'; import { OverlayTrigger, Popover } from 'react-bootstrap';
import classNames from 'classnames'; import classNames from 'classnames';
import SolidIcon from '@/_ui/Icon/SolidIcons';
export const QueryCard = ({ dataQuery, darkMode = false, localDs }) => { export const QueryCard = ({ dataQuery, darkMode = false, localDs }) => {
const appId = useStore((state) => state.app.appId); const appId = useStore((state) => state.app.appId);
@ -31,6 +33,7 @@ export const QueryCard = ({ dataQuery, darkMode = false, localDs }) => {
const deleteDataQueries = useStore((state) => state.dataQuery.deleteDataQueries); const deleteDataQueries = useStore((state) => state.dataQuery.deleteDataQueries);
const duplicateQuery = useStore((state) => state.dataQuery.duplicateQuery); const duplicateQuery = useStore((state) => state.dataQuery.duplicateQuery);
const setPreviewData = useStore((state) => state.queryPanel.setPreviewData); const setPreviewData = useStore((state) => state.queryPanel.setPreviewData);
const toggleQueryPermissionModal = useStore((state) => state.queryPanel.toggleQueryPermissionModal);
const [showDeleteConfirmation, setShowDeleteConfirmation] = useState(false); const [showDeleteConfirmation, setShowDeleteConfirmation] = useState(false);
const [showQueryMenu, setShowQueryMenu] = useState(false); const [showQueryMenu, setShowQueryMenu] = useState(false);
const hasPermissions = const hasPermissions =
@ -40,6 +43,9 @@ export const QueryCard = ({ dataQuery, darkMode = false, localDs }) => {
canDeleteDataSource() canDeleteDataSource()
: true; : true;
const featureAccess = useStore((state) => state?.license?.featureAccess, shallow);
const licenseValid = !featureAccess?.licenseStatus?.isExpired && featureAccess?.licenseStatus?.isLicenseValid;
const shouldFreeze = useStore((state) => state.getShouldFreeze()); const shouldFreeze = useStore((state) => state.getShouldFreeze());
const QUERY_MENU_OPTIONS = [ const QUERY_MENU_OPTIONS = [
@ -47,16 +53,34 @@ export const QueryCard = ({ dataQuery, darkMode = false, localDs }) => {
label: 'Rename', label: 'Rename',
value: 'rename', value: 'rename',
icon: <Edit width={16} />, icon: <Edit width={16} />,
showTooltip: false,
}, },
{ {
label: 'Duplicate', label: 'Duplicate',
value: 'duplicate', value: 'duplicate',
icon: <Copy width={16} />, icon: <Copy width={16} />,
showTooltip: false,
},
{
label: 'Query permission',
value: 'permission',
icon: (
<img
alt="permission-icon"
src="assets/images/icons/editor/left-sidebar/authorization.svg"
width="16"
height="16"
/>
),
trailingIcon: !licenseValid ? <SolidIcon width={16} name="enterprisecrown" className="mx-1" /> : undefined,
tooltipText: 'Query permissions are available only in paid plans',
showTooltip: !licenseValid,
}, },
{ {
label: 'Delete', label: 'Delete',
value: 'delete', value: 'delete',
icon: <Trash width={16} fill={'#E54D2E'} />, icon: <Trash width={16} fill={'#E54D2E'} />,
showTooltip: false,
}, },
]; ];
@ -67,6 +91,10 @@ export const QueryCard = ({ dataQuery, darkMode = false, localDs }) => {
if (value === 'duplicate') { if (value === 'duplicate') {
debouncedDuplicateQuery(dataQuery?.id, appId); debouncedDuplicateQuery(dataQuery?.id, appId);
} }
if (value === 'permission') {
if (!licenseValid) return;
toggleQueryPermissionModal(true);
}
if (value === 'delete') { if (value === 'delete') {
deleteDataQuery(); deleteDataQuery();
} }
@ -198,24 +226,32 @@ export const QueryCard = ({ dataQuery, darkMode = false, localDs }) => {
<Popover id="list-menu" className={darkMode && 'dark-theme'}> <Popover id="list-menu" className={darkMode && 'dark-theme'}>
<Popover.Body bsPrefix="list-item-popover-body"> <Popover.Body bsPrefix="list-item-popover-body">
{QUERY_MENU_OPTIONS.map((option) => ( {QUERY_MENU_OPTIONS.map((option) => (
<div <ToolTip
data-cy={`query-menu-${String(option?.value).toLowerCase()}-button`}
className="list-item-popover-option"
key={option?.value} key={option?.value}
onClick={(e) => { message={option?.tooltipText}
e.stopPropagation(); placement="right"
handleQueryMenuActions(option.value); show={option?.showTooltip}
}}
> >
<div className="list-item-popover-menu-option-icon">{option.icon}</div>
<div <div
className={classNames('list-item-option-menu-label', { data-cy={`query-menu-${String(option?.value).toLowerCase()}-button`}
'color-tomato9': option.value === 'delete', className="list-item-popover-option"
})} key={option?.value}
onClick={(e) => {
e.stopPropagation();
handleQueryMenuActions(option.value);
}}
> >
{option?.label} <div className="list-item-popover-menu-option-icon">{option.icon}</div>
<div
className={classNames('list-item-option-menu-label', {
'color-tomato9': option.value === 'delete',
})}
>
{option?.label}
</div>
{option.trailingIcon && option.trailingIcon}
</div> </div>
</div> </ToolTip>
))} ))}
</Popover.Body> </Popover.Body>
</Popover> </Popover>

View file

@ -16,6 +16,9 @@ import DataSourceSelect from '../QueryManager/Components/DataSourceSelect';
import { OverlayTrigger, Popover } from 'react-bootstrap'; import { OverlayTrigger, Popover } from 'react-bootstrap';
import FolderEmpty from '@/_ui/Icon/solidIcons/FolderEmpty'; import FolderEmpty from '@/_ui/Icon/solidIcons/FolderEmpty';
import useStore from '@/AppBuilder/_stores/store'; import useStore from '@/AppBuilder/_stores/store';
import AppPermissionsModal from '@/modules/Appbuilder/components/AppPermissionsModal';
import { shallow } from 'zustand/shallow';
import { appPermissionService } from '@/_services';
export const QueryDataPane = ({ darkMode }) => { export const QueryDataPane = ({ darkMode }) => {
const { t } = useTranslation(); const { t } = useTranslation();
@ -34,6 +37,11 @@ export const QueryDataPane = ({ darkMode }) => {
function isDataSourceLocal(dataQuery) { function isDataSourceLocal(dataQuery) {
return dataSources.some((dataSource) => dataSource.id === dataQuery.data_source_id); return dataSources.some((dataSource) => dataSource.id === dataQuery.data_source_id);
} }
const featureAccess = useStore((state) => state?.license?.featureAccess, shallow);
const licenseValid = !featureAccess?.licenseStatus?.isExpired && featureAccess?.licenseStatus?.isLicenseValid;
const selectedQuery = useStore((state) => state.queryPanel.selectedQuery);
const showQueryPermissionModal = useStore((state) => state.queryPanel.showQueryPermissionModal);
const toggleQueryPermissionModal = useStore((state) => state.queryPanel.toggleQueryPermissionModal);
useEffect(() => { useEffect(() => {
setQueryPanelSearchTerm(searchTermForFilters); setQueryPanelSearchTerm(searchTermForFilters);
@ -171,6 +179,20 @@ export const QueryDataPane = ({ darkMode }) => {
{filteredQueries.map((query) => ( {filteredQueries.map((query) => (
<QueryCard key={query.id} dataQuery={query} darkMode={darkMode} localDs={!!isDataSourceLocal(query)} /> <QueryCard key={query.id} dataQuery={query} darkMode={darkMode} localDs={!!isDataSourceLocal(query)} />
))} ))}
{licenseValid && (
<AppPermissionsModal
modalType="query"
resourceId={selectedQuery?.id}
showModal={showQueryPermissionModal}
toggleModal={toggleQueryPermissionModal}
darkMode={darkMode}
fetchPermission={(id, appId) => appPermissionService.getQueryPermission(appId, id)}
createPermission={(id, appId, body) => appPermissionService.createQueryPermission(appId, id, body)}
updatePermission={(id, appId, body) => appPermissionService.updateQueryPermission(appId, id, body)}
deletePermission={(id, appId) => appPermissionService.deleteQueryPermission(appId, id)}
// onSuccess={(data) => updateQueryWithPermissions(selectedQuery?.id, data)}
/>
)}
</div> </div>
<Tooltip <Tooltip
id="query-card-name-tooltip" id="query-card-name-tooltip"

View file

@ -26,6 +26,7 @@ const initialState = {
loadingDataQueries: false, loadingDataQueries: false,
isPreviewQueryLoading: false, isPreviewQueryLoading: false,
queryPanelSearchTem: '', queryPanelSearchTem: '',
showQueryPermissionModal: false,
}; };
export const createQueryPanelSlice = (set, get) => ({ export const createQueryPanelSlice = (set, get) => ({
@ -1113,5 +1114,10 @@ export const createQueryPanelSlice = (set, get) => ({
}; };
previewQuery(query, false, undefined, moduleId); previewQuery(query, false, undefined, moduleId);
}, },
toggleQueryPermissionModal: (show) => {
set((state) => {
state.queryPanel.showQueryPermissionModal = show;
});
},
}, },
}); });

View file

@ -64,6 +64,7 @@ button:focus:not(:focus-visible) {
padding: 10px 14px; padding: 10px 14px;
cursor: pointer; cursor: pointer;
display: flex; display: flex;
align-items: center;
&:hover { &:hover {
background-color: var(--slate3); background-color: var(--slate3);