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

View File

@ -2693,3 +2693,6 @@ export const GOOGLE_RECAPTCHA_FAILED = () =>
"Google reCAPTCHA verification failed";
export const PASSWORD_INSUFFICIENT_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[]) => {
return data.map((fileOperation) => {
let title =
fileOperation.entityExplorerTitle ||
fileOperation.dsName ||
fileOperation.title;
return data
.map((fileOperation) => {
let title =
fileOperation.entityExplorerTitle ||
fileOperation.dsName ||
fileOperation.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:
title =
fileOperation.focusEntityType === FocusEntity.QUERY_MODULE_INSTANCE
? fileOperation.dsName
: "",
descriptionType: "inline",
onClick: onCreateItemClick.bind(null, fileOperation),
} as ListItemProps;
});
? fileOperation.title
: title;
const className = createAddClassName(title);
const icon =
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 };

View File

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

View File

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

View File

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

View File

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