diff --git a/app/client/packages/design-system/ads/src/Box/Box.constants.ts b/app/client/packages/design-system/ads/src/Box/Box.constants.ts index 2f270b1beedb..d7e13fd1342c 100644 --- a/app/client/packages/design-system/ads/src/Box/Box.constants.ts +++ b/app/client/packages/design-system/ads/src/Box/Box.constants.ts @@ -27,4 +27,6 @@ export const PropsToBeCssPrefixPrepended = [ "px", "py", "gap", + "rowGap", + "columnGap", ]; diff --git a/app/client/src/IDE/utils/filterEntityGroupsBySearchTerm.test.ts b/app/client/src/IDE/utils/filterEntityGroupsBySearchTerm.test.ts new file mode 100644 index 000000000000..645e4f4f8595 --- /dev/null +++ b/app/client/src/IDE/utils/filterEntityGroupsBySearchTerm.test.ts @@ -0,0 +1,31 @@ +import { filterEntityGroupsBySearchTerm } from "."; + +const groups = [ + { + name: "Group 1", + items: [{ title: "file1" }, { title: "file2" }], + }, + { + title: "Group 2", + items: [{ title: "file3" }, { title: "file4" }], + }, +]; + +describe("filterEntityGroupsBySearchTerm", () => { + test.each([ + ["", groups], + [ + "file1", + [ + { + name: "Group 1", + items: [{ title: "file1" }], + }, + ], + ], + ["notfound", []], + ["file", groups], + ])("%s -> %j", (searchTerm, output) => { + expect(filterEntityGroupsBySearchTerm(searchTerm, groups)).toEqual(output); + }); +}); diff --git a/app/client/src/IDE/utils/filterEntityGroupsBySearchTerm.ts b/app/client/src/IDE/utils/filterEntityGroupsBySearchTerm.ts new file mode 100644 index 000000000000..fcdbc425c0cb --- /dev/null +++ b/app/client/src/IDE/utils/filterEntityGroupsBySearchTerm.ts @@ -0,0 +1,43 @@ +import Fuse, { type FuseOptions } from "fuse.js"; + +/** Searchable properties. Must be defined in this way to be able to derive union type and satisfy FuseOptions */ +const keys: ["title"] = ["title"]; + +/** Union type to make sure these particular keys are present in collection that's being passed in for search. */ +type Keys = (typeof keys)[number]; + +type BaseGroup = Record; +type BaseItem = Record; +type Group = G & { + items: T[]; +}; + +const FUSE_OPTIONS: FuseOptions = { + shouldSort: true, + threshold: 0.1, + keys, +}; + +/** Filter entity groups by search term using fuse.js */ +export const filterEntityGroupsBySearchTerm = < + G extends BaseGroup, + T extends BaseItem, +>( + searchTerm: string, + groups: Array>, +): Array> => { + if (!searchTerm) { + return groups; + } + + return groups.reduce((result: Array>, group) => { + const { items, ...rest } = group; + const searchResults = new Fuse(items, FUSE_OPTIONS).search(searchTerm); + + if (searchResults.length) { + result.push({ ...rest, items: searchResults } as Group); + } + + return result; + }, []); +}; diff --git a/app/client/src/IDE/utils/index.ts b/app/client/src/IDE/utils/index.ts new file mode 100644 index 000000000000..987455e2e73e --- /dev/null +++ b/app/client/src/IDE/utils/index.ts @@ -0,0 +1 @@ +export { filterEntityGroupsBySearchTerm } from "./filterEntityGroupsBySearchTerm"; diff --git a/app/client/src/PluginActionEditor/components/PluginActionResponse/components/DatasourceTab/Datasource.tsx b/app/client/src/PluginActionEditor/components/PluginActionResponse/components/DatasourceTab/Datasource.tsx index 0771efb25e93..1162f39978a0 100644 --- a/app/client/src/PluginActionEditor/components/PluginActionResponse/components/DatasourceTab/Datasource.tsx +++ b/app/client/src/PluginActionEditor/components/PluginActionResponse/components/DatasourceTab/Datasource.tsx @@ -25,6 +25,7 @@ import { BOTTOMBAR_HEIGHT } from "./constants"; import { useEditorType } from "ee/hooks"; import { useParentEntityInfo } from "ee/hooks/datasourceEditorHooks"; import DatasourceInfo from "./DatasourceInfo"; +import { getPlugin } from "ee/selectors/entitiesSelector"; interface Props { datasourceId: string; @@ -45,6 +46,8 @@ const Datasource = (props: Props) => { getPluginIdFromDatasourceId(state, props.datasourceId), ); + const plugin = useSelector((state) => getPlugin(state, pluginId || "")); + const editorType = useEditorType(location.pathname); const { parentEntityId } = useParentEntityInfo(editorType); @@ -143,6 +146,7 @@ const Datasource = (props: Props) => { { datasourceId={props.datasourceId} datasourceName={props.datasourceName} datasourceStructure={datasourceStructure} + plugin={plugin} selectedTable={selectedTable} setSelectedTable={setSelectedTable} /> diff --git a/app/client/src/PluginActionEditor/components/PluginActionResponse/components/DatasourceTab/DatasourceInfo.tsx b/app/client/src/PluginActionEditor/components/PluginActionResponse/components/DatasourceTab/DatasourceInfo.tsx index e671e70d4afc..acfa33571870 100644 --- a/app/client/src/PluginActionEditor/components/PluginActionResponse/components/DatasourceTab/DatasourceInfo.tsx +++ b/app/client/src/PluginActionEditor/components/PluginActionResponse/components/DatasourceTab/DatasourceInfo.tsx @@ -10,16 +10,19 @@ import { getQueryParams } from "utils/URLUtils"; import history from "utils/history"; import { useEditorType } from "ee/hooks"; import { useParentEntityInfo } from "ee/hooks/datasourceEditorHooks"; +import type { Plugin } from "api/PluginApi"; interface Props { datasourceId: string; datasourceName: string; showEditButton: boolean; + plugin?: Plugin; } const DatasourceInfo = ({ datasourceId, datasourceName, + plugin, showEditButton, }: Props) => { const editorType = useEditorType(location.pathname); @@ -50,6 +53,7 @@ const DatasourceInfo = ({ {showEditButton && ( diff --git a/app/client/src/PluginActionEditor/components/PluginActionResponse/components/DatasourceTab/DatasourceSelector/index.tsx b/app/client/src/PluginActionEditor/components/PluginActionResponse/components/DatasourceTab/DatasourceSelector/index.tsx index 6f3ef2f510f1..252643232aaf 100644 --- a/app/client/src/PluginActionEditor/components/PluginActionResponse/components/DatasourceTab/DatasourceSelector/index.tsx +++ b/app/client/src/PluginActionEditor/components/PluginActionResponse/components/DatasourceTab/DatasourceSelector/index.tsx @@ -1,6 +1,5 @@ import React from "react"; -import { UIComponentTypes } from "api/PluginApi"; -import { usePluginActionContext } from "PluginActionEditor/PluginActionContext"; +import { UIComponentTypes, type Plugin } from "api/PluginApi"; import ApiDatasourceSelector from "./ApiDatasourceSelector"; import QueryDatasourceSelector from "./QueryDatasourceSelector"; import { @@ -16,16 +15,17 @@ const API_FORM_COMPONENTS = [ export interface DatasourceProps { datasourceId: string; datasourceName: string; + plugin?: Plugin; } const DatasourceSelector = (props: DatasourceProps) => { - const { plugin } = usePluginActionContext(); - - return API_FORM_COMPONENTS.includes(plugin.uiComponent) ? ( - - ) : ( - - ); + return props.plugin ? ( + API_FORM_COMPONENTS.includes(props.plugin.uiComponent) ? ( + + ) : ( + + ) + ) : null; }; export default DatasourceSelector; diff --git a/app/client/src/PluginActionEditor/components/PluginActionResponse/components/DatasourceTab/DatasourceTables.tsx b/app/client/src/PluginActionEditor/components/PluginActionResponse/components/DatasourceTab/DatasourceTables.tsx index 1664ff7667aa..ef23751816ef 100644 --- a/app/client/src/PluginActionEditor/components/PluginActionResponse/components/DatasourceTab/DatasourceTables.tsx +++ b/app/client/src/PluginActionEditor/components/PluginActionResponse/components/DatasourceTab/DatasourceTables.tsx @@ -9,12 +9,14 @@ import { refreshDatasourceStructure } from "actions/datasourceActions"; import { useDispatch } from "react-redux"; import { SchemaTableContainer } from "./styles"; import DatasourceInfo from "./DatasourceInfo"; +import type { Plugin } from "api/PluginApi"; interface Props { datasourceId: string; datasourceName: string; currentActionId: string; datasourceStructure: DatasourceStructure; + plugin?: Plugin; setSelectedTable: (table: string) => void; selectedTable: string | undefined; } @@ -24,6 +26,7 @@ const DatasourceTables = ({ datasourceId, datasourceName, datasourceStructure, + plugin, selectedTable, setSelectedTable, }: Props) => { @@ -56,6 +59,7 @@ const DatasourceTables = ({