fix: Updating the permission check for run button in response pane (#36893)
## Description Updating the permission check for run button in response pane to fix the button being disabled even though the user has execute permissions. Fixes [#36873](https://github.com/appsmithorg/appsmith/issues/36873) ## Automation /ok-to-test tags="@tag.Sanity" ### 🔍 Cypress test results <!-- This is an auto-generated comment: Cypress test results --> > [!TIP] > 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉 > Workflow run: <https://github.com/appsmithorg/appsmith/actions/runs/11359075861> > Commit: 4bc6d8a650cf28b2a26e84851c55a6d232daaf90 > <a href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=11359075861&attempt=1" target="_blank">Cypress dashboard</a>. > Tags: `@tag.Sanity` > Spec: > <hr>Wed, 16 Oct 2024 05:26:33 UTC <!-- end of auto-generated comment: Cypress test results --> ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [ ] No <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Introduced the `isRunDisabled` property to enhance the `QueryResponseTab` component, improving execution control based on user permissions. - Updated several components to reflect the new `isRunDisabled` prop, streamlining execution permission handling. - **Bug Fixes** - Renamed `disabled` prop to `isRunDisabled` for clarity and consistency across components. - **Documentation** - Enhanced clarity in the UI regarding execution permissions and action contexts. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
parent
00c16e81b3
commit
4f7fd1270e
|
|
@ -149,6 +149,7 @@ function usePluginActionResponseTabs() {
|
|||
actionName={action.name}
|
||||
actionSource={actionSource}
|
||||
currentActionConfig={action}
|
||||
isRunDisabled={blockExecution}
|
||||
isRunning={isRunning}
|
||||
onRunClick={onRunClick}
|
||||
runErrorMessage={""} // TODO
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ describe("ApiResponseView", () => {
|
|||
<Router>
|
||||
<ApiResponseView
|
||||
currentActionConfig={Api1}
|
||||
disabled={false}
|
||||
isRunDisabled={false}
|
||||
isRunning={false}
|
||||
onRunClick={noop}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ import { ApiResponseHeaders } from "PluginActionEditor/components/PluginActionRe
|
|||
interface Props {
|
||||
currentActionConfig: Action;
|
||||
theme?: EditorTheme;
|
||||
disabled: boolean;
|
||||
isRunDisabled: boolean;
|
||||
onRunClick: () => void;
|
||||
actionResponse?: ActionResponse;
|
||||
isRunning: boolean;
|
||||
|
|
@ -43,7 +43,7 @@ function ApiResponseView(props: Props) {
|
|||
const {
|
||||
actionResponse = EMPTY_RESPONSE,
|
||||
currentActionConfig,
|
||||
disabled,
|
||||
isRunDisabled = false,
|
||||
isRunning,
|
||||
theme = EditorTheme.LIGHT,
|
||||
} = props;
|
||||
|
|
@ -99,7 +99,7 @@ function ApiResponseView(props: Props) {
|
|||
<ApiResponse
|
||||
action={currentActionConfig}
|
||||
actionResponse={actionResponse}
|
||||
isRunDisabled={disabled}
|
||||
isRunDisabled={isRunDisabled}
|
||||
isRunning={isRunning}
|
||||
onRunClick={onRunClick}
|
||||
responseTabHeight={responseTabHeight}
|
||||
|
|
@ -113,7 +113,7 @@ function ApiResponseView(props: Props) {
|
|||
panelComponent: (
|
||||
<ApiResponseHeaders
|
||||
actionResponse={actionResponse}
|
||||
isRunDisabled={disabled}
|
||||
isRunDisabled={isRunDisabled}
|
||||
isRunning={isRunning}
|
||||
onDebugClick={onDebugClick}
|
||||
onRunClick={onRunClick}
|
||||
|
|
|
|||
|
|
@ -341,7 +341,7 @@ function CommonEditorForm(props: CommonFormPropsWithExtraParams) {
|
|||
<ApiResponseView
|
||||
actionResponse={actionResponse}
|
||||
currentActionConfig={currentActionConfig}
|
||||
disabled={!isExecutePermitted}
|
||||
isRunDisabled={blockExecution}
|
||||
isRunning={isRunning}
|
||||
onRunClick={onRunClick}
|
||||
theme={theme}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import ActionRightPane from "components/editorComponents/ActionRightPane";
|
|||
import type { ActionResponse } from "api/ActionAPI";
|
||||
import type { Plugin } from "api/PluginApi";
|
||||
import type { UIComponentTypes } from "api/PluginApi";
|
||||
import { EDITOR_TABS } from "constants/QueryEditorConstants";
|
||||
import { EDITOR_TABS, SQL_DATASOURCES } from "constants/QueryEditorConstants";
|
||||
import type { FormEvalOutput } from "reducers/evaluationReducers/formEvaluationReducer";
|
||||
import {
|
||||
getPluginActionConfigSelectedTab,
|
||||
|
|
@ -37,6 +37,10 @@ import { doesPluginRequireDatasource } from "ee/entities/Engine/actionHelpers";
|
|||
import FormRender from "./FormRender";
|
||||
import QueryEditorHeader from "./QueryEditorHeader";
|
||||
import RunHistory from "ee/components/RunHistory";
|
||||
import { useFeatureFlag } from "utils/hooks/useFeatureFlag";
|
||||
import { FEATURE_FLAG } from "ee/entities/FeatureFlag";
|
||||
import { getHasExecuteActionPermission } from "ee/utils/BusinessFeatures/permissionPageHelpers";
|
||||
import { getPluginNameFromId } from "ee/selectors/entitiesSelector";
|
||||
|
||||
const QueryFormContainer = styled.form`
|
||||
flex: 1;
|
||||
|
|
@ -241,6 +245,35 @@ export function EditorJSONtoForm(props: Props) {
|
|||
[dispatch],
|
||||
);
|
||||
|
||||
const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled);
|
||||
const isExecutePermitted = getHasExecuteActionPermission(
|
||||
isFeatureEnabled,
|
||||
currentActionConfig?.userPermissions,
|
||||
);
|
||||
|
||||
// get the current action's plugin name
|
||||
const currentActionPluginName = useSelector((state: AppState) =>
|
||||
getPluginNameFromId(state, currentActionConfig?.pluginId || ""),
|
||||
);
|
||||
|
||||
let actionBody = "";
|
||||
|
||||
if (!!currentActionConfig?.actionConfiguration) {
|
||||
if ("formData" in currentActionConfig?.actionConfiguration) {
|
||||
// if the action has a formData (the action is postUQI e.g. Oracle)
|
||||
actionBody =
|
||||
currentActionConfig.actionConfiguration.formData?.body?.data || "";
|
||||
} else {
|
||||
// if the action is pre UQI, the path is different e.g. mySQL
|
||||
actionBody = currentActionConfig.actionConfiguration?.body || "";
|
||||
}
|
||||
}
|
||||
|
||||
// if (the body is empty and the action is an sql datasource) or the user does not have permission, block action execution.
|
||||
const blockExecution =
|
||||
(!actionBody && SQL_DATASOURCES.includes(currentActionPluginName)) ||
|
||||
!isExecutePermitted;
|
||||
|
||||
// when switching between different redux forms, make sure this redux form has been initialized before rendering anything.
|
||||
// the initialized prop below comes from redux-form.
|
||||
if (!props.initialized) {
|
||||
|
|
@ -252,6 +285,7 @@ export function EditorJSONtoForm(props: Props) {
|
|||
<QueryEditorHeader
|
||||
dataSources={dataSources}
|
||||
formName={formName}
|
||||
isRunDisabled={blockExecution}
|
||||
isRunning={isRunning}
|
||||
onCreateDatasourceClick={onCreateDatasourceClick}
|
||||
onRunClick={onRunClick}
|
||||
|
|
@ -334,6 +368,7 @@ export function EditorJSONtoForm(props: Props) {
|
|||
actionResponse={actionResponse}
|
||||
actionSource={actionSource}
|
||||
currentActionConfig={currentActionConfig}
|
||||
isRunDisabled={blockExecution}
|
||||
isRunning={isRunning}
|
||||
onRunClick={onRunClick}
|
||||
runErrorMessage={runErrorMessage}
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ const ResultsCount = styled.div`
|
|||
interface QueryDebuggerTabsProps {
|
||||
actionSource: SourceEntity;
|
||||
currentActionConfig?: Action;
|
||||
isRunDisabled?: boolean;
|
||||
isRunning: boolean;
|
||||
actionName: string; // Check what and how to get
|
||||
runErrorMessage?: string;
|
||||
|
|
@ -59,6 +60,7 @@ function QueryDebuggerTabs({
|
|||
actionResponse,
|
||||
actionSource,
|
||||
currentActionConfig,
|
||||
isRunDisabled = false,
|
||||
isRunning,
|
||||
onRunClick,
|
||||
runErrorMessage,
|
||||
|
|
@ -233,6 +235,7 @@ function QueryDebuggerTabs({
|
|||
actionName={actionName}
|
||||
actionSource={actionSource}
|
||||
currentActionConfig={currentActionConfig}
|
||||
isRunDisabled={isRunDisabled}
|
||||
isRunning={isRunning}
|
||||
onRunClick={onRunClick}
|
||||
runErrorMessage={runErrorMessage}
|
||||
|
|
|
|||
|
|
@ -5,22 +5,14 @@ import { StyledFormRow } from "./EditorJSONtoForm";
|
|||
import styled from "styled-components";
|
||||
import { useFeatureFlag } from "utils/hooks/useFeatureFlag";
|
||||
import { FEATURE_FLAG } from "ee/entities/FeatureFlag";
|
||||
import {
|
||||
getHasExecuteActionPermission,
|
||||
getHasManageActionPermission,
|
||||
} from "ee/utils/BusinessFeatures/permissionPageHelpers";
|
||||
import { getHasManageActionPermission } from "ee/utils/BusinessFeatures/permissionPageHelpers";
|
||||
import { useActiveActionBaseId } from "ee/pages/Editor/Explorer/hooks";
|
||||
import { useSelector } from "react-redux";
|
||||
import {
|
||||
getActionByBaseId,
|
||||
getPlugin,
|
||||
getPluginNameFromId,
|
||||
} from "ee/selectors/entitiesSelector";
|
||||
import { getActionByBaseId, getPlugin } from "ee/selectors/entitiesSelector";
|
||||
import { QueryEditorContext } from "./QueryEditorContext";
|
||||
import type { Plugin } from "api/PluginApi";
|
||||
import type { Datasource } from "entities/Datasource";
|
||||
import type { AppState } from "ee/reducers";
|
||||
import { SQL_DATASOURCES } from "constants/QueryEditorConstants";
|
||||
import DatasourceSelector from "./DatasourceSelector";
|
||||
import { getSavingStatusForActionName } from "selectors/actionSelectors";
|
||||
import { getAssetUrl } from "ee/utils/airgapHelpers";
|
||||
|
|
@ -51,6 +43,7 @@ interface Props {
|
|||
formName: string;
|
||||
dataSources: Datasource[];
|
||||
onCreateDatasourceClick: () => void;
|
||||
isRunDisabled?: boolean;
|
||||
isRunning: boolean;
|
||||
onRunClick: () => void;
|
||||
}
|
||||
|
|
@ -59,6 +52,7 @@ const QueryEditorHeader = (props: Props) => {
|
|||
const {
|
||||
dataSources,
|
||||
formName,
|
||||
isRunDisabled = false,
|
||||
isRunning,
|
||||
onCreateDatasourceClick,
|
||||
onRunClick,
|
||||
|
|
@ -78,11 +72,6 @@ const QueryEditorHeader = (props: Props) => {
|
|||
currentActionConfig?.userPermissions,
|
||||
);
|
||||
|
||||
const isExecutePermitted = getHasExecuteActionPermission(
|
||||
isFeatureEnabled,
|
||||
currentActionConfig?.userPermissions,
|
||||
);
|
||||
|
||||
const currentPlugin = useSelector((state: AppState) =>
|
||||
getPlugin(state, currentActionConfig?.pluginId || ""),
|
||||
);
|
||||
|
|
@ -95,29 +84,6 @@ const QueryEditorHeader = (props: Props) => {
|
|||
|
||||
const icon = ActionUrlIcon(iconUrl);
|
||||
|
||||
// get the current action's plugin name
|
||||
const currentActionPluginName = useSelector((state: AppState) =>
|
||||
getPluginNameFromId(state, currentActionConfig?.pluginId || ""),
|
||||
);
|
||||
|
||||
let actionBody = "";
|
||||
|
||||
if (!!currentActionConfig?.actionConfiguration) {
|
||||
if ("formData" in currentActionConfig?.actionConfiguration) {
|
||||
// if the action has a formData (the action is postUQI e.g. Oracle)
|
||||
actionBody =
|
||||
currentActionConfig.actionConfiguration.formData?.body?.data || "";
|
||||
} else {
|
||||
// if the action is pre UQI, the path is different e.g. mySQL
|
||||
actionBody = currentActionConfig.actionConfiguration?.body || "";
|
||||
}
|
||||
}
|
||||
|
||||
// if (the body is empty and the action is an sql datasource) or the user does not have permission, block action execution.
|
||||
const blockExecution =
|
||||
(!actionBody && SQL_DATASOURCES.includes(currentActionPluginName)) ||
|
||||
!isExecutePermitted;
|
||||
|
||||
return (
|
||||
<StyledFormRow>
|
||||
<NameWrapper>
|
||||
|
|
@ -141,7 +107,7 @@ const QueryEditorHeader = (props: Props) => {
|
|||
<Button
|
||||
className="t--run-query"
|
||||
data-guided-tour-iid="run-query"
|
||||
isDisabled={blockExecution}
|
||||
isDisabled={isRunDisabled}
|
||||
isLoading={isRunning}
|
||||
onClick={onRunClick}
|
||||
size="md"
|
||||
|
|
|
|||
|
|
@ -28,9 +28,6 @@ import type { SourceEntity } from "entities/AppsmithConsole";
|
|||
import type { Action } from "entities/Action";
|
||||
import { getActionData } from "ee/selectors/entitiesSelector";
|
||||
import { actionResponseDisplayDataFormats } from "../utils";
|
||||
import { useFeatureFlag } from "utils/hooks/useFeatureFlag";
|
||||
import { FEATURE_FLAG } from "ee/entities/FeatureFlag";
|
||||
import { getHasExecuteActionPermission } from "ee/utils/BusinessFeatures/permissionPageHelpers";
|
||||
import { getErrorAsString } from "sagas/ActionExecution/errorUtils";
|
||||
import { isString } from "lodash";
|
||||
import ActionExecutionInProgressView from "components/editorComponents/ActionExecutionInProgressView";
|
||||
|
|
@ -72,6 +69,7 @@ const ResponseContentWrapper = styled.div<{ isError: boolean }>`
|
|||
|
||||
interface Props {
|
||||
actionSource: SourceEntity;
|
||||
isRunDisabled?: boolean;
|
||||
isRunning: boolean;
|
||||
onRunClick: () => void;
|
||||
currentActionConfig: Action;
|
||||
|
|
@ -84,19 +82,13 @@ const QueryResponseTab = (props: Props) => {
|
|||
actionName,
|
||||
actionSource,
|
||||
currentActionConfig,
|
||||
isRunDisabled = false,
|
||||
isRunning,
|
||||
onRunClick,
|
||||
runErrorMessage,
|
||||
} = props;
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled);
|
||||
|
||||
const isExecutePermitted = getHasExecuteActionPermission(
|
||||
isFeatureEnabled,
|
||||
currentActionConfig?.userPermissions,
|
||||
);
|
||||
|
||||
const actionResponse = useSelector((state) =>
|
||||
getActionData(state, currentActionConfig.id),
|
||||
);
|
||||
|
|
@ -341,7 +333,7 @@ const QueryResponseTab = (props: Props) => {
|
|||
)}
|
||||
{!output && !error && (
|
||||
<NoResponse
|
||||
isRunDisabled={!isExecutePermitted}
|
||||
isRunDisabled={isRunDisabled}
|
||||
isRunning={isRunning}
|
||||
onRunClick={responseTabOnRunClick}
|
||||
/>
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user