-
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: Updated new tab ui with search and load more #34981
Changes from 1 commit
6ddf1c8
6c59766
be7c2ed
a006f80
15479d0
5faa22a
3f971f7
6c3f2ed
536eeec
2d37c01
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 |
---|---|---|
@@ -1,8 +1,8 @@ | ||
import React, { useCallback } from "react"; | ||
import React, { useCallback, useState } from "react"; | ||
import SegmentAddHeader from "../components/SegmentAddHeader"; | ||
import { EDITOR_PANE_TEXTS } from "@appsmith/constants/messages"; | ||
import type { ListItemProps } from "design-system"; | ||
import { Flex, Tag } from "design-system"; | ||
import { Flex, SearchInput } from "design-system"; | ||
import { useDispatch, useSelector } from "react-redux"; | ||
import { getCurrentPageId } from "selectors/editorSelectors"; | ||
import GroupedList from "../components/GroupedList"; | ||
|
@@ -12,11 +12,15 @@ import { | |
} from "@appsmith/pages/Editor/IDE/EditorPane/JS/hooks"; | ||
import type { ActionOperation } from "components/editorComponents/GlobalSearch/utils"; | ||
import type { AddProps } from "../types/AddProps"; | ||
import { createAddClassName } from "../utils"; | ||
import { createAddClassName, fuzzySearchInObjectItems } from "../utils"; | ||
import { FocusEntity } from "navigation/FocusEntity"; | ||
import type { GroupedListProps } from "../components/types"; | ||
import { EmptySearchResult } from "../components/EmptySearchResult"; | ||
|
||
const AddJS = ({ containerProps, innerContainerProps }: AddProps) => { | ||
const dispatch = useDispatch(); | ||
const pageId = useSelector(getCurrentPageId); | ||
const [searchTerm, setSearchTerm] = useState(""); | ||
|
||
const groupedJsOperations = useGroupedAddJsOperations(); | ||
|
||
|
@@ -35,13 +39,27 @@ const AddJS = ({ containerProps, innerContainerProps }: AddProps) => { | |
return { | ||
startIcon: data.icon, | ||
title, | ||
description: !!data.isBeta ? <Tag isClosable={false}>Beta</Tag> : "", | ||
description: | ||
data.focusEntityType === FocusEntity.JS_MODULE_INSTANCE | ||
? data.dsName | ||
: "", | ||
descriptionType: "inline", | ||
onClick: onCreateItemClick.bind(null, data), | ||
wrapperClassName: createAddClassName(title), | ||
} as ListItemProps; | ||
}; | ||
|
||
const groups = groupedJsOperations.map((op) => ({ | ||
groupTitle: op.title, | ||
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. This is not required by any means, but I think if you destructure function arguments code become more concise and readable. const groups = groupedJsOperations.map(({title, className, operations}) => ({
groupTitle: title,
className: className,
items: operations.map(getListItems),
})); |
||
className: op.className, | ||
items: op.operations.map(getListItems), | ||
})); | ||
|
||
const localGroups = fuzzySearchInObjectItems<GroupedListProps[]>( | ||
searchTerm, | ||
groups, | ||
); | ||
|
||
return ( | ||
<Flex | ||
data-testid="t--ide-add-pane" | ||
|
@@ -61,18 +79,11 @@ const AddJS = ({ containerProps, innerContainerProps }: AddProps) => { | |
onCloseClick={closeAddJS} | ||
titleMessage={EDITOR_PANE_TEXTS.js_create_tab_title} | ||
/> | ||
|
||
<GroupedList | ||
flexProps={{ | ||
pr: "spaces-2", | ||
px: "spaces-3", | ||
}} | ||
groups={groupedJsOperations.map((op) => ({ | ||
groupTitle: op.title, | ||
className: op.className, | ||
items: op.operations.map(getListItems), | ||
}))} | ||
/> | ||
<SearchInput onChange={setSearchTerm} value={searchTerm} /> | ||
{localGroups.length > 0 ? <GroupedList groups={localGroups} /> : null} | ||
{localGroups.length === 0 && searchTerm !== "" ? ( | ||
<EmptySearchResult type="JS" /> | ||
) : null} | ||
</Flex> | ||
</Flex> | ||
); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ import { useSelector } from "react-redux"; | |
import { Flex, Text } from "design-system"; | ||
import styled from "styled-components"; | ||
|
||
import type { EditorSegmentList } from "@appsmith/selectors/appIDESelectors"; | ||
import { selectJSSegmentEditorList } from "@appsmith/selectors/appIDESelectors"; | ||
import { useActiveAction } from "@appsmith/pages/Editor/Explorer/hooks"; | ||
import { | ||
|
@@ -19,8 +20,8 @@ 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"; | ||
import { fuzzySearchInObjectItems } from "../utils"; | ||
import { EmptySearchResult } from "../components/EmptySearchResult"; | ||
|
||
const JSContainer = styled(Flex)` | ||
& .t--entity-item { | ||
|
@@ -44,7 +45,10 @@ const ListJSObjects = () => { | |
|
||
const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled); | ||
|
||
const localFiles = fuzzySearchInFiles(searchTerm, files); | ||
const localFiles = fuzzySearchInObjectItems<EditorSegmentList>( | ||
searchTerm, | ||
files, | ||
); | ||
|
||
const canCreateActions = getHasCreateActionPermission( | ||
isFeatureEnabled, | ||
|
@@ -112,13 +116,7 @@ const ListJSObjects = () => { | |
); | ||
})} | ||
{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> | ||
<EmptySearchResult type="JS object" /> | ||
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. Should this be imported from |
||
) : null} | ||
</Flex> | ||
</FilesContextProvider> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import React from "react"; | ||
import { Text } from "design-system"; | ||
import { EDITOR_PANE_TEXTS, createMessage } from "@appsmith/constants/messages"; | ||
|
||
const EmptySearchResult = ({ type }: { type: string }) => { | ||
return ( | ||
<Text | ||
className="font-normal text-center" | ||
color="var(--ads-v2-color-fg-muted)" | ||
kind="body-s" | ||
> | ||
{createMessage(EDITOR_PANE_TEXTS.empty_search_result, type)} | ||
</Text> | ||
); | ||
}; | ||
|
||
export { EmptySearchResult }; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
import React, { useState } from "react"; | ||
import type { GroupedListProps } from "./types"; | ||
import { DEFAULT_GROUP_LIST_SIZE } from "./constants"; | ||
import { Flex, List, Text } from "design-system"; | ||
import styled from "styled-components"; | ||
|
||
interface GroupProps { | ||
group: GroupedListProps; | ||
} | ||
|
||
const StyledList = styled(List)` | ||
padding: 0; | ||
gap: 0; | ||
|
||
& .ds-load-more .ads-v2-listitem__title { | ||
--color: var(--ads-v2-color-fg-subtle); | ||
} | ||
& .ads-v2-listitem__wrapper .ads-v2-listitem__idesc { | ||
opacity: 0; | ||
} | ||
|
||
& .ads-v2-listitem__wrapper:hover .ads-v2-listitem__idesc { | ||
opacity: 1; | ||
} | ||
`; | ||
|
||
const Group: React.FC<GroupProps> = ({ group }) => { | ||
const [visibleItems, setVisibleItems] = useState<number>( | ||
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. I suggest renaming const [visibleItemsCount, setVisibleItemsCount] = useState<number>( |
||
DEFAULT_GROUP_LIST_SIZE, | ||
); | ||
const { className, groupTitle } = group; | ||
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. const { className, groupTitle, groupItems } = group;
const items = groupItems.slice(0, visibleItems);
const hasMoreItems = groupItems.length > visibleItems;
const handleLoadMore = () => {
setVisibleItemsCount(groupItems.length);
}; |
||
const items = group.items.slice(0, visibleItems); | ||
const hasMoreItems = group.items.length > visibleItems; | ||
|
||
const handleLoadMore = () => { | ||
setVisibleItems(group.items.length); | ||
}; | ||
|
||
if (hasMoreItems) { | ||
items.push({ | ||
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. You should never mutate objects directly in React, as it can lead to unpredictable results. This can be fixed by moving items composition into a const items = useMemo(() => {
const items = groupItems.slice(0, visibleItemsCount);
const hasMoreItems = groupItems.length > visibleItemsCount;
if (hasMoreItems) {
items.push({
title: "Load more...",
description: "",
descriptionType: "inline",
onClick: handleLoadMore,
className: "ds-load-more",
});
if (groupTitle === "Datasources") {
items.push(groupItems[groupItems.length - 1]);
}
}
return items;
}, [groupItems, visibleItemsCount, handleLoadMore, groupTitle]); |
||
title: "Load more...", | ||
description: "", | ||
descriptionType: "inline", | ||
onClick: handleLoadMore, | ||
className: "ds-load-more", | ||
}); | ||
} | ||
|
||
// TODO: try to avoid this | ||
if (hasMoreItems && groupTitle === "Datasources") { | ||
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. Ideally string |
||
items.push(group.items[group.items.length - 1]); | ||
} | ||
|
||
return ( | ||
<Flex | ||
borderBottom="1px solid var(--ads-v2-color-border-muted)" | ||
className="groups-list-group" | ||
flexDirection="column" | ||
key={groupTitle} | ||
pb="spaces-3" | ||
> | ||
{groupTitle ? ( | ||
<Text | ||
className="pr-[var(--ads-v2-spaces-3)] py-[var(--ads-v2-spaces-1)]" | ||
color="var(--ads-v2-color-fg-muted)" | ||
kind="body-s" | ||
> | ||
{groupTitle} | ||
</Text> | ||
) : null} | ||
<StyledList className={className} items={items} /> | ||
</Flex> | ||
); | ||
}; | ||
|
||
export { Group }; |
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.
Consider using template literals for consistency and future extensibility.
The functions returning strings in this file use regular strings. For consistency with other parts of the codebase that might use template literals and to facilitate easier modifications in the future (like introducing variables into the strings), consider using template literals here as well.
Committable suggestion