fix: Updated the copy text if plugin not installed, disabled new query and edit for unavailable plugin ds (#40360)

This commit is contained in:
Aman Agarwal 2025-04-25 09:38:07 +05:30 committed by GitHub
parent d1f55d2cc9
commit cf90a8e98c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 74 additions and 38 deletions

View File

@ -15,6 +15,8 @@ import CenteredWrapper from "components/designSystems/appsmith/CenteredWrapper";
import { Text } from "@appsmith/ads"; import { Text } from "@appsmith/ads";
import { useIsEditorInitialised } from "IDE/hooks"; import { useIsEditorInitialised } from "IDE/hooks";
import { useActionSettingsConfig } from "./hooks"; import { useActionSettingsConfig } from "./hooks";
import { createMessage, PLUGIN_NOT_INSTALLED } from "ee/constants/messages";
import { ShowUpgradeMenuItem } from "ee/utils/licenseHelpers";
interface ChildrenProps { interface ChildrenProps {
children: React.ReactNode | React.ReactNode[]; children: React.ReactNode | React.ReactNode[];
@ -54,10 +56,11 @@ const PluginActionEditor = (props: ChildrenProps) => {
if (!plugin) { if (!plugin) {
return ( return (
<CenteredWrapper> <CenteredWrapper className="flex-col">
<Text color="var(--ads-v2-color-fg-error)" kind="heading-m"> <Text color="var(--ads-v2-color-fg-error)" kind="heading-m">
Plugin not installed! {createMessage(PLUGIN_NOT_INSTALLED)}
</Text> </Text>
<ShowUpgradeMenuItem />
</CenteredWrapper> </CenteredWrapper>
); );
} }

View File

@ -2693,3 +2693,6 @@ export const GOOGLE_RECAPTCHA_FAILED = () =>
"Google reCAPTCHA verification failed"; "Google reCAPTCHA verification failed";
export const PASSWORD_INSUFFICIENT_STRENGTH = () => export const PASSWORD_INSUFFICIENT_STRENGTH = () =>
"Insufficient password strength"; "Insufficient password strength";
export const PLUGIN_NOT_INSTALLED = () =>
"Upgrade your plan to unlock access to these integrations.";

View File

@ -45,34 +45,40 @@ export const useAddQueryListItems = () => {
); );
const getListItems = (data: ActionOperation[]) => { const getListItems = (data: ActionOperation[]) => {
return data.map((fileOperation) => { return data
let title = .map((fileOperation) => {
fileOperation.entityExplorerTitle || let title =
fileOperation.dsName || fileOperation.entityExplorerTitle ||
fileOperation.title; fileOperation.dsName ||
fileOperation.title;
title = title =
fileOperation.focusEntityType === FocusEntity.QUERY_MODULE_INSTANCE
? fileOperation.title
: title;
const className = createAddClassName(title);
const icon =
fileOperation.icon ||
(fileOperation.pluginId &&
getPluginEntityIcon(pluginGroups[fileOperation.pluginId]));
return {
startIcon: icon,
className: className,
title,
description:
fileOperation.focusEntityType === FocusEntity.QUERY_MODULE_INSTANCE fileOperation.focusEntityType === FocusEntity.QUERY_MODULE_INSTANCE
? fileOperation.dsName ? fileOperation.title
: "", : title;
descriptionType: "inline", const className = createAddClassName(title);
onClick: onCreateItemClick.bind(null, fileOperation), const icon =
} as ListItemProps; fileOperation.icon ||
}); (fileOperation.pluginId &&
getPluginEntityIcon(pluginGroups[fileOperation.pluginId]));
if (fileOperation.pluginId && !pluginGroups[fileOperation.pluginId]) {
return undefined;
}
return {
startIcon: icon,
className: className,
title,
description:
fileOperation.focusEntityType === FocusEntity.QUERY_MODULE_INSTANCE
? fileOperation.dsName
: "",
descriptionType: "inline",
onClick: onCreateItemClick.bind(null, fileOperation),
} as ListItemProps;
})
.filter((item) => item !== undefined);
}; };
return { getListItems }; return { getListItems };

View File

@ -64,6 +64,9 @@ export const useFilteredFileOperations = ({
}: FilterFileOperationsProps) => { }: FilterFileOperationsProps) => {
const { appWideDS = [], otherDS = [] } = useAppWideAndOtherDatasource(); const { appWideDS = [], otherDS = [] } = useAppWideAndOtherDatasource();
const plugins = useSelector(getPlugins); const plugins = useSelector(getPlugins);
const pluginById = useMemo(() => {
return keyBy(plugins, "id");
}, [plugins]);
const moduleOptions = useModuleOptions(); const moduleOptions = useModuleOptions();
const workflowOptions = useWorkflowOptions(); const workflowOptions = useWorkflowOptions();
@ -106,7 +109,7 @@ export const useFilteredFileOperations = ({
return AiPlugin.id !== ds.pluginId; return AiPlugin.id !== ds.pluginId;
} }
return true; return !!pluginById[ds.pluginId]?.id;
}); });
return useFilteredAndSortedFileOperations({ return useFilteredAndSortedFileOperations({

View File

@ -43,7 +43,7 @@ import type { ExplorerURLParams } from "ee/pages/Editor/Explorer/helpers";
import { getLastSelectedWidget } from "selectors/ui"; import { getLastSelectedWidget } from "selectors/ui";
import AnalyticsUtil from "ee/utils/AnalyticsUtil"; import AnalyticsUtil from "ee/utils/AnalyticsUtil";
import useRecentEntities from "./useRecentEntities"; import useRecentEntities from "./useRecentEntities";
import { noop } from "lodash"; import { keyBy, noop } from "lodash";
import { import {
getCurrentPageId, getCurrentPageId,
getPagePermissions, getPagePermissions,
@ -179,6 +179,9 @@ function GlobalSearch() {
(state: AppState) => state.ui.globalSearch.filterContext.category, (state: AppState) => state.ui.globalSearch.filterContext.category,
); );
const plugins = useSelector(getPlugins); const plugins = useSelector(getPlugins);
const pluginById = useMemo(() => {
return keyBy(plugins, "id");
}, [plugins]);
const setCategory = useCallback( const setCategory = useCallback(
(category: SearchCategory) => { (category: SearchCategory) => {
dispatch(setGlobalSearchFilterContext({ category: category })); dispatch(setGlobalSearchFilterContext({ category: category }));
@ -233,10 +236,15 @@ function GlobalSearch() {
}, [basePageIdToPageIdMap, params?.basePageId, reducerDatasources]); }, [basePageIdToPageIdMap, params?.basePageId, reducerDatasources]);
const filteredDatasources = useMemo(() => { const filteredDatasources = useMemo(() => {
if (!query) return datasourcesList; if (!query)
return datasourcesList.filter(
(datasource) => pluginById[datasource.pluginId]?.id,
);
return datasourcesList.filter((datasource) => return datasourcesList.filter(
isMatching(datasource.name, query), (datasource) =>
isMatching(datasource.name, query) &&
pluginById[datasource.pluginId]?.id,
); );
}, [datasourcesList, query]); }, [datasourcesList, query]);
const recentEntities = useRecentEntities(); const recentEntities = useRecentEntities();

View File

@ -28,6 +28,7 @@ import type { PluginType } from "entities/Plugin";
import { useLocation } from "react-router"; import { useLocation } from "react-router";
import { useHeaderActions } from "ee/hooks/datasourceEditorHooks"; import { useHeaderActions } from "ee/hooks/datasourceEditorHooks";
import { getIDETypeByUrl } from "ee/entities/IDE/utils"; import { getIDETypeByUrl } from "ee/entities/IDE/utils";
import { getPlugin } from "ee/selectors/entitiesSelector";
export const ActionWrapper = styled.div` export const ActionWrapper = styled.div`
display: flex; display: flex;
@ -118,6 +119,10 @@ export const DSFormHeader = (props: DSFormHeaderProps) => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const location = useLocation(); const location = useLocation();
const ideType = getIDETypeByUrl(location.pathname); const ideType = getIDETypeByUrl(location.pathname);
const plugin = useSelector((state) =>
getPlugin(state, datasource?.pluginId || ""),
);
const isEditDisabled = !plugin?.id;
const deleteAction = () => { const deleteAction = () => {
if (isDeleting) return; if (isDeleting) return;
@ -210,8 +215,11 @@ export const DSFormHeader = (props: DSFormHeaderProps) => {
)} )}
<Button <Button
className="t--edit-datasource" className="t--edit-datasource"
isDisabled={isEditDisabled}
kind="secondary" kind="secondary"
onClick={() => { onClick={() => {
if (isEditDisabled) return;
setDatasourceViewMode({ setDatasourceViewMode({
datasourceId: datasourceId, datasourceId: datasourceId,
viewMode: false, viewMode: false,

View File

@ -24,7 +24,7 @@ import { getCurrentPageId, getPageList } from "selectors/editorSelectors";
import type { Datasource } from "entities/Datasource"; import type { Datasource } from "entities/Datasource";
import type { EventLocation } from "ee/utils/analyticsUtilTypes"; import type { EventLocation } from "ee/utils/analyticsUtilTypes";
import { getCurrentEnvironmentId } from "ee/selectors/environmentSelectors"; import { getCurrentEnvironmentId } from "ee/selectors/environmentSelectors";
import { getSelectedTableName } from "ee/selectors/entitiesSelector"; import { getPlugin, getSelectedTableName } from "ee/selectors/entitiesSelector";
interface NewActionButtonProps { interface NewActionButtonProps {
datasource?: Datasource; datasource?: Datasource;
@ -75,6 +75,11 @@ function NewActionButton(props: NewActionButtonProps) {
...pages.filter((p) => p.pageId !== currentPageId), ...pages.filter((p) => p.pageId !== currentPageId),
]; ];
const queryDefaultTableName = useSelector(getSelectedTableName); const queryDefaultTableName = useSelector(getSelectedTableName);
const plugin = useSelector((state) =>
getPlugin(state, datasource?.pluginId || ""),
);
const isDisabled = !!disabled || !plugin?.id;
const createQueryAction = useCallback( const createQueryAction = useCallback(
(pageId: string) => { (pageId: string) => {
@ -106,7 +111,7 @@ function NewActionButton(props: NewActionButtonProps) {
const handleOnInteraction = useCallback( const handleOnInteraction = useCallback(
(open: boolean) => { (open: boolean) => {
if (disabled || isLoading) return; if (isDisabled || isLoading) return;
if (!open) { if (!open) {
setIsPageSelectionOpen(false); setIsPageSelectionOpen(false);
@ -122,7 +127,7 @@ function NewActionButton(props: NewActionButtonProps) {
setIsPageSelectionOpen(true); setIsPageSelectionOpen(true);
}, },
[pages, createQueryAction, disabled, isLoading], [pages, createQueryAction, isDisabled, isLoading],
); );
const getCreateButtonText = () => { const getCreateButtonText = () => {
@ -139,11 +144,11 @@ function NewActionButton(props: NewActionButtonProps) {
return ( return (
<Menu onOpenChange={handleOnInteraction} open={isPageSelectionOpen}> <Menu onOpenChange={handleOnInteraction} open={isPageSelectionOpen}>
<MenuTrigger disabled={disabled}> <MenuTrigger disabled={isDisabled}>
<Button <Button
className="t--create-query" className="t--create-query"
id={"create-query"} id={"create-query"}
isDisabled={!!disabled} isDisabled={isDisabled}
isLoading={isSelected || isLoading} isLoading={isSelected || isLoading}
kind={isNewQuerySecondaryButton ? "secondary" : "primary"} kind={isNewQuerySecondaryButton ? "secondary" : "primary"}
onClick={() => handleOnInteraction(true)} onClick={() => handleOnInteraction(true)}