-
Notifications
You must be signed in to change notification settings - Fork 3.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: IDE tab list search view #34759
Changes from 5 commits
c6b51da
9ec92b4
86bc62e
4d8516e
ac04312
aa4c87a
9600269
4569848
bd1a481
557a0b4
4f17e33
ff0355b
215c162
257eb48
b93b2e8
7755e3a
126197d
c09ae9f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -115,7 +115,7 @@ | |
"d3-geo": "^3.1.0", | ||
"dayjs": "^1.10.6", | ||
"deep-diff": "^1.0.2", | ||
"design-system": "npm:@appsmithorg/[email protected].42", | ||
"design-system": "npm:@appsmithorg/[email protected].43", | ||
"design-system-old": "npm:@appsmithorg/[email protected]", | ||
"downloadjs": "^1.4.7", | ||
"echarts": "^5.4.2", | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
import React from "react"; | ||
import React, { useState } from "react"; | ||
import { useSelector } from "react-redux"; | ||
import { Button, Flex, Text } from "design-system"; | ||
import { Flex, Text } from "design-system"; | ||
import styled from "styled-components"; | ||
|
||
import { selectJSSegmentEditorList } from "@appsmith/selectors/appIDESelectors"; | ||
|
@@ -13,12 +13,14 @@ import { | |
import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; | ||
import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag"; | ||
import { getHasCreateActionPermission } from "@appsmith/utils/BusinessFeatures/permissionPageHelpers"; | ||
import { createMessage, EDITOR_PANE_TEXTS } from "@appsmith/constants/messages"; | ||
import { ActionParentEntityType } from "@appsmith/entities/Engine/actionHelpers"; | ||
import { FilesContextProvider } from "pages/Editor/Explorer/Files/FilesContextProvider"; | ||
import { useJSAdd } from "@appsmith/pages/Editor/IDE/EditorPane/JS/hooks"; | ||
import { JSListItem } from "@appsmith/pages/Editor/IDE/EditorPane/JS/ListItem"; | ||
import { BlankState } from "./BlankState"; | ||
import { AddAndSearchbar } from "../components/AddAndSearchbar"; | ||
import { fuzzySearchInFiles } from "../utils"; | ||
import { EDITOR_PANE_TEXTS, createMessage } from "@appsmith/constants/messages"; | ||
|
||
const JSContainer = styled(Flex)` | ||
& .t--entity-item { | ||
|
@@ -32,22 +34,29 @@ const JSContainer = styled(Flex)` | |
`; | ||
|
||
const ListJSObjects = () => { | ||
const [searchTerm, setSearchTerm] = useState(""); | ||
const pageId = useSelector(getCurrentPageId); | ||
const jsList = useSelector(selectJSSegmentEditorList); | ||
const files = useSelector(selectJSSegmentEditorList); | ||
const activeActionId = useActiveAction(); | ||
const applicationId = useSelector(getCurrentApplicationId); | ||
|
||
const pagePermissions = useSelector(getPagePermissions); | ||
|
||
const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled); | ||
|
||
const localFiles = fuzzySearchInFiles(searchTerm, files); | ||
|
||
const canCreateActions = getHasCreateActionPermission( | ||
isFeatureEnabled, | ||
pagePermissions, | ||
); | ||
|
||
const { openAddJS } = useJSAdd(); | ||
|
||
const onSearch = (str: string) => { | ||
setSearchTerm(str); | ||
}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missed this the first time around, but it seems that passing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Changed this |
||
|
||
return ( | ||
<JSContainer | ||
className="ide-editor-left-pane__content-js" | ||
|
@@ -57,19 +66,13 @@ const ListJSObjects = () => { | |
overflow="hidden" | ||
py="spaces-3" | ||
> | ||
{jsList && jsList.length > 0 && canCreateActions && ( | ||
<Flex flexDirection="column" px="spaces-3"> | ||
<Button | ||
className="t--add-item" | ||
kind={"secondary"} | ||
onClick={openAddJS} | ||
size={"sm"} | ||
startIcon={"add-line"} | ||
> | ||
{createMessage(EDITOR_PANE_TEXTS.js_add_button)} | ||
</Button> | ||
</Flex> | ||
)} | ||
{files && files.length > 0 ? ( | ||
<AddAndSearchbar | ||
hasAddPermission={canCreateActions} | ||
onAddClick={openAddJS} | ||
onSearch={onSearch} | ||
/> | ||
) : null} | ||
<FilesContextProvider | ||
canCreateActions={canCreateActions} | ||
editorId={applicationId} | ||
|
@@ -83,7 +86,7 @@ const ListJSObjects = () => { | |
overflowY="auto" | ||
px="spaces-3" | ||
> | ||
{jsList.map(({ group, items }) => { | ||
{localFiles.map(({ group, items }) => { | ||
return ( | ||
<Flex flexDirection={"column"} key={group}> | ||
{group !== "NA" ? ( | ||
|
@@ -112,10 +115,19 @@ const ListJSObjects = () => { | |
</Flex> | ||
); | ||
})} | ||
{localFiles.length === 0 && searchTerm !== "" ? ( | ||
<Text | ||
className="font-normal text-center" | ||
color="var(--ads-v2-color-fg-muted)" | ||
kind="body-s" | ||
> | ||
{createMessage(EDITOR_PANE_TEXTS.empty_search_result, "JS")} | ||
</Text> | ||
) : null} | ||
</Flex> | ||
</FilesContextProvider> | ||
|
||
{(!jsList || jsList.length === 0) && <BlankState />} | ||
{(!files || files.length === 0) && <BlankState />} | ||
</JSContainer> | ||
); | ||
}; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import React from "react"; | ||
import { Flex, Button, SearchInput } from "design-system"; | ||
|
||
interface Props { | ||
onAddClick: () => void; | ||
hasAddPermission: boolean; | ||
onSearch: (value: string) => void; | ||
} | ||
|
||
const AddAndSearchbar = ({ hasAddPermission, onAddClick, onSearch }: Props) => { | ||
return ( | ||
<Flex alignItems="center" flexDirection="row" gap="spaces-3" px="spaces-3"> | ||
<SearchInput onChange={onSearch} size="sm" /> | ||
{hasAddPermission ? ( | ||
<Button | ||
className="t--add-item !min-w-[24px]" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will take this up in a separate PR since this change is not introduced by this PR rather this is a change in location. Also, this update will cause updates in some cypress files as well. |
||
isIconButton | ||
kind={"secondary"} | ||
onClick={onAddClick} | ||
size={"sm"} | ||
startIcon={"add-line"} | ||
/> | ||
) : null} | ||
</Flex> | ||
); | ||
}; | ||
|
||
export { AddAndSearchbar }; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import type { EditorSegmentList } from "@appsmith/selectors/appIDESelectors"; | ||
import { fuzzySearchInFiles } from "./utils"; | ||
import { PluginType } from "entities/Action"; | ||
|
||
const sampleFiles: EditorSegmentList = [ | ||
{ | ||
group: "Group 1", | ||
items: [ | ||
{ title: "file1.js", type: PluginType.API, key: "file1" }, | ||
{ title: "file2.js", type: PluginType.API, key: "file2" }, | ||
], | ||
}, | ||
{ | ||
group: "Group 2", | ||
items: [ | ||
{ title: "file3.js", type: PluginType.API, key: "file3" }, | ||
{ title: "file4.js", type: PluginType.API, key: "file4" }, | ||
], | ||
}, | ||
]; | ||
|
||
describe("fuzzySearchInFiles", () => { | ||
sagar-qa007 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
it("should return all files if searchStr is empty", () => { | ||
const result = fuzzySearchInFiles("", sampleFiles); | ||
expect(result).toEqual(sampleFiles); | ||
}); | ||
|
||
it("should return filtered files based on searchStr", () => { | ||
const result = fuzzySearchInFiles("file1", sampleFiles); | ||
expect(result).toEqual([ | ||
{ | ||
group: "Group 1", | ||
items: [{ title: "file1.js", type: PluginType.API, key: "file1" }], | ||
}, | ||
]); | ||
}); | ||
|
||
it("should return empty array if no match found", () => { | ||
const result = fuzzySearchInFiles("nonexistentfile", sampleFiles); | ||
expect(result).toEqual([]); | ||
}); | ||
|
||
it("should return filtered files from multiple groups", () => { | ||
const result = fuzzySearchInFiles("file", sampleFiles); | ||
expect(result).toEqual(sampleFiles); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,30 @@ | ||
import Fuse from "fuse.js"; | ||
import type { EditorSegmentList } from "@appsmith/selectors/appIDESelectors"; | ||
|
||
export const createAddClassName = (name: string) => { | ||
return "t--datasoucre-create-option-" + name.toLowerCase().replace(/ /g, "_"); | ||
}; | ||
|
||
const FUSE_OPTIONS = { | ||
shouldSort: true, | ||
threshold: 0.1, | ||
keys: ["title"], | ||
}; | ||
|
||
export const fuzzySearchInFiles = ( | ||
searchStr: string, | ||
files: EditorSegmentList, | ||
) => { | ||
if (searchStr && searchStr !== "") { | ||
const newFiles = files | ||
.map((group) => { | ||
const fuse = new Fuse(group.items, FUSE_OPTIONS); | ||
const resultItems = fuse.search(searchStr); | ||
return { ...group, items: resultItems }; | ||
}) | ||
.filter((group) => group.items.length > 0); | ||
return newFiles; | ||
} | ||
|
||
return files; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a bit of nitpicking, typically
onSearch
is a naming convention used for events, while handlers are prefixed withhandle
, e.g.handleSearch
.