diff --git a/frontend/src/AppBuilder/QueryPanel/QueryCard.jsx b/frontend/src/AppBuilder/QueryPanel/QueryCard.jsx
index 088f3c7318..78050de93d 100644
--- a/frontend/src/AppBuilder/QueryPanel/QueryCard.jsx
+++ b/frontend/src/AppBuilder/QueryPanel/QueryCard.jsx
@@ -1,5 +1,6 @@
import React, { useState, useCallback } from 'react';
import { Tooltip } from 'react-tooltip';
+import { ToolTip } from '@/_components/ToolTip';
import { updateQuerySuggestions } from '@/_helpers/appUtils';
// import { Confirm } from '../Viewer/Confirm';
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 { OverlayTrigger, Popover } from 'react-bootstrap';
import classNames from 'classnames';
+import SolidIcon from '@/_ui/Icon/SolidIcons';
export const QueryCard = ({ dataQuery, darkMode = false, localDs }) => {
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 duplicateQuery = useStore((state) => state.dataQuery.duplicateQuery);
const setPreviewData = useStore((state) => state.queryPanel.setPreviewData);
+ const toggleQueryPermissionModal = useStore((state) => state.queryPanel.toggleQueryPermissionModal);
const [showDeleteConfirmation, setShowDeleteConfirmation] = useState(false);
const [showQueryMenu, setShowQueryMenu] = useState(false);
const hasPermissions =
@@ -40,6 +43,9 @@ export const QueryCard = ({ dataQuery, darkMode = false, localDs }) => {
canDeleteDataSource()
: true;
+ const featureAccess = useStore((state) => state?.license?.featureAccess, shallow);
+ const licenseValid = !featureAccess?.licenseStatus?.isExpired && featureAccess?.licenseStatus?.isLicenseValid;
+
const shouldFreeze = useStore((state) => state.getShouldFreeze());
const QUERY_MENU_OPTIONS = [
@@ -47,16 +53,34 @@ export const QueryCard = ({ dataQuery, darkMode = false, localDs }) => {
label: 'Rename',
value: 'rename',
icon: ,
+ showTooltip: false,
},
{
label: 'Duplicate',
value: 'duplicate',
icon: ,
+ showTooltip: false,
+ },
+ {
+ label: 'Query permission',
+ value: 'permission',
+ icon: (
+
+ ),
+ trailingIcon: !licenseValid ? : undefined,
+ tooltipText: 'Query permissions are available only in paid plans',
+ showTooltip: !licenseValid,
},
{
label: 'Delete',
value: 'delete',
icon: ,
+ showTooltip: false,
},
];
@@ -67,6 +91,10 @@ export const QueryCard = ({ dataQuery, darkMode = false, localDs }) => {
if (value === 'duplicate') {
debouncedDuplicateQuery(dataQuery?.id, appId);
}
+ if (value === 'permission') {
+ if (!licenseValid) return;
+ toggleQueryPermissionModal(true);
+ }
if (value === 'delete') {
deleteDataQuery();
}
@@ -198,24 +226,32 @@ export const QueryCard = ({ dataQuery, darkMode = false, localDs }) => {
diff --git a/frontend/src/AppBuilder/QueryPanel/QueryDataPane.jsx b/frontend/src/AppBuilder/QueryPanel/QueryDataPane.jsx
index 9ac052ae51..a09780734e 100644
--- a/frontend/src/AppBuilder/QueryPanel/QueryDataPane.jsx
+++ b/frontend/src/AppBuilder/QueryPanel/QueryDataPane.jsx
@@ -16,6 +16,9 @@ import DataSourceSelect from '../QueryManager/Components/DataSourceSelect';
import { OverlayTrigger, Popover } from 'react-bootstrap';
import FolderEmpty from '@/_ui/Icon/solidIcons/FolderEmpty';
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 }) => {
const { t } = useTranslation();
@@ -34,6 +37,11 @@ export const QueryDataPane = ({ darkMode }) => {
function isDataSourceLocal(dataQuery) {
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(() => {
setQueryPanelSearchTerm(searchTermForFilters);
@@ -171,6 +179,20 @@ export const QueryDataPane = ({ darkMode }) => {
{filteredQueries.map((query) => (
))}
+ {licenseValid && (
+ 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)}
+ />
+ )}
({
@@ -1113,5 +1114,10 @@ export const createQueryPanelSlice = (set, get) => ({
};
previewQuery(query, false, undefined, moduleId);
},
+ toggleQueryPermissionModal: (show) => {
+ set((state) => {
+ state.queryPanel.showQueryPermissionModal = show;
+ });
+ },
},
});
diff --git a/frontend/src/ToolJetUI/List/list.scss b/frontend/src/ToolJetUI/List/list.scss
index c5aa03aada..786f4e88af 100644
--- a/frontend/src/ToolJetUI/List/list.scss
+++ b/frontend/src/ToolJetUI/List/list.scss
@@ -64,6 +64,7 @@ button:focus:not(:focus-visible) {
padding: 10px 14px;
cursor: pointer;
display: flex;
+ align-items: center;
&:hover {
background-color: var(--slate3);