chore: Replacing the entity group list component on state inspector and data side pane with new ADS component (#38621)
## Description Replacing the entity group list component on state inspector and data side pane with new ADS component Fixes [#38290](https://github.com/appsmithorg/appsmith/issues/38290) ## Automation /ok-to-test tags="@tag.Datasource" ### 🔍 Cypress test results <!-- This is an auto-generated comment: Cypress test results --> > [!TIP] > 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉 > Workflow run: <https://github.com/appsmithorg/appsmith/actions/runs/12763738469> > Commit: a4b717244604617d39fb1869d039899dd024c687 > <a href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=12763738469&attempt=2" target="_blank">Cypress dashboard</a>. > Tags: `@tag.Datasource` > Spec: > <hr>Tue, 14 Jan 2025 09:50:48 UTC <!-- end of auto-generated comment: Cypress test results --> ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [ ] No <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Release Notes - **New Features** - Enhanced list item styling with configurable height. - Added support for dynamic item count in entity groups. - Improved icon rendering with customizable dimensions. - Introduced a new constant for default group list size. - **Improvements** - Simplified rendering of grouped items in various components. - Refined type safety for boolean assignments. - Updated state management for entity groups. - Enhanced control over item visibility in modals and lists. - **Technical Updates** - Introduced new data attributes for enhanced component interactions. - Modernized component rendering logic. - Replaced custom styled list with a dedicated `EntityGroupsList` component for better maintainability. - Expanded story examples for the `ListItem` component to showcase various configurations. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
parent
b6f7164c14
commit
d187854e40
|
|
@ -211,20 +211,36 @@ export const ListItemInlineDescStory = ListItemTemplate.bind({}) as StoryObj;
|
|||
ListItemInlineDescStory.storyName = "List item inline description";
|
||||
ListItemInlineDescStory.argTypes = ListItemArgTypes;
|
||||
ListItemInlineDescStory.args = {
|
||||
title: "Action item 1",
|
||||
title:
|
||||
"Action_item_1_with_a_very_long_name_that_should_show_ellipsis_in_the_same_line",
|
||||
description: "inline",
|
||||
};
|
||||
|
||||
export const ListItemBlockDescStory = ListItemTemplate.bind({}) as StoryObj;
|
||||
ListItemBlockDescStory.storyName = "List item block description";
|
||||
ListItemBlockDescStory.argTypes = ListItemArgTypes;
|
||||
ListItemBlockDescStory.args = {
|
||||
export const ListItemBlockDescWithIconStory = ListItemTemplate.bind(
|
||||
{},
|
||||
) as StoryObj;
|
||||
ListItemBlockDescWithIconStory.storyName =
|
||||
"List item block description with icon";
|
||||
ListItemBlockDescWithIconStory.argTypes = ListItemArgTypes;
|
||||
ListItemBlockDescWithIconStory.args = {
|
||||
startIcon: <Icon name="file-list-2-line" size={"md"} />,
|
||||
title: "Action item 1",
|
||||
description: "block",
|
||||
descriptionType: "block",
|
||||
};
|
||||
|
||||
export const ListItemBlockDescWithoutIconStory = ListItemTemplate.bind(
|
||||
{},
|
||||
) as StoryObj;
|
||||
ListItemBlockDescWithoutIconStory.storyName =
|
||||
"List item block description without icon";
|
||||
ListItemBlockDescWithoutIconStory.argTypes = ListItemArgTypes;
|
||||
ListItemBlockDescWithoutIconStory.args = {
|
||||
title: "Action item 1",
|
||||
description: "Action item 1 block description",
|
||||
descriptionType: "block",
|
||||
};
|
||||
|
||||
export const ListItemOverflowStory = ListItemTemplate.bind({}) as StoryObj;
|
||||
ListItemOverflowStory.storyName = "List item title overflow";
|
||||
ListItemOverflowStory.argTypes = ListItemArgTypes;
|
||||
|
|
|
|||
|
|
@ -31,6 +31,10 @@ const Sizes = {
|
|||
export const TooltipTextWrapper = styled.div`
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
|
||||
&.${ListItemIDescClassName}-wrapper {
|
||||
min-width: unset;
|
||||
}
|
||||
`;
|
||||
|
||||
export const RightControlWrapper = styled.div`
|
||||
|
|
@ -54,8 +58,11 @@ export const TopContentWrapper = styled.div`
|
|||
`;
|
||||
|
||||
export const BottomContentWrapper = styled.div`
|
||||
padding-left: var(--ads-v2-spaces-7);
|
||||
padding-bottom: var(--ads-v2-spaces-2);
|
||||
|
||||
&[data-isiconpresent="true"] {
|
||||
padding-left: var(--ads-v2-spaces-7);
|
||||
}
|
||||
`;
|
||||
|
||||
export const InlineDescriptionWrapper = styled.div`
|
||||
|
|
@ -91,8 +98,14 @@ export const StyledListItem = styled.div<{
|
|||
gap: var(--ads-v2-spaces-1);
|
||||
flex-shrink: 0;
|
||||
flex-direction: column;
|
||||
max-height: 32px;
|
||||
|
||||
${({ size }) => Sizes[size]}
|
||||
|
||||
&[data-isblockdescription="true"] {
|
||||
max-height: 54px;
|
||||
}
|
||||
|
||||
&[data-rightcontrolvisibility="hover"] {
|
||||
${RightControlWrapper} {
|
||||
display: none;
|
||||
|
|
@ -128,6 +141,7 @@ export const StyledListItem = styled.div<{
|
|||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
flex: 1;
|
||||
padding-right: var(--ads-v2-spaces-2);
|
||||
}
|
||||
|
||||
& .${ListItemTitleClassName} {
|
||||
|
|
|
|||
|
|
@ -64,7 +64,10 @@ function TextWithTooltip(props: TextProps & { isMultiline?: boolean }) {
|
|||
|
||||
return (
|
||||
<Tooltip content={props.children} isDisabled={disableTooltip}>
|
||||
<TooltipTextWrapper onMouseOver={handleShowFullText}>
|
||||
<TooltipTextWrapper
|
||||
className={`${props.className}-wrapper`}
|
||||
onMouseOver={handleShowFullText}
|
||||
>
|
||||
<Text
|
||||
{...props}
|
||||
className={clsx(ListItemTextOverflowClassName, props.className)}
|
||||
|
|
@ -87,8 +90,12 @@ function ListItem(props: ListItemProps) {
|
|||
startIcon,
|
||||
title,
|
||||
} = props;
|
||||
const isBlockDescription = descriptionType === "block" && description;
|
||||
const isInlineDescription = descriptionType === "inline" && description;
|
||||
const isBlockDescription = Boolean(
|
||||
descriptionType === "block" && description,
|
||||
);
|
||||
const isInlineDescription = Boolean(
|
||||
descriptionType === "inline" && description,
|
||||
);
|
||||
|
||||
const handleOnClick = useEventCallback((e: React.MouseEvent) => {
|
||||
e.stopPropagation();
|
||||
|
|
@ -114,6 +121,7 @@ function ListItem(props: ListItemProps) {
|
|||
<StyledListItem
|
||||
className={clsx(ListItemClassName, props.className)}
|
||||
data-disabled={props.isDisabled || false}
|
||||
data-isblockdescription={isBlockDescription}
|
||||
data-rightcontrolvisibility={rightControlVisibility}
|
||||
data-selected={props.isSelected}
|
||||
id={props.id}
|
||||
|
|
@ -152,7 +160,7 @@ function ListItem(props: ListItemProps) {
|
|||
)}
|
||||
</TopContentWrapper>
|
||||
{isBlockDescription && (
|
||||
<BottomContentWrapper>
|
||||
<BottomContentWrapper data-isiconpresent={Boolean(startIcon)}>
|
||||
<TextWithTooltip
|
||||
className={ListItemBDescClassName}
|
||||
color="var(--ads-v2-color-fg-muted)"
|
||||
|
|
|
|||
|
|
@ -19,7 +19,12 @@ export default meta;
|
|||
const EntityGroupTemplate = <T,>(props: EntityGroupProps<T>) => {
|
||||
const { addConfig, className, groupTitle, items } = props;
|
||||
|
||||
return <EntityGroup group={{ addConfig, className, groupTitle, items }} />;
|
||||
return (
|
||||
<EntityGroup
|
||||
group={{ addConfig, className, groupTitle, items }}
|
||||
visibleItems={5}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const SingleGroupWithAddNLazyLoad = EntityGroupTemplate.bind(
|
||||
|
|
@ -83,7 +88,7 @@ SingleGroupWithAddNLazyLoad.args = {
|
|||
const EntityGroupsListTemplate = <T,>(props: EntityGroupsListProps<T>) => {
|
||||
const { groups } = props;
|
||||
|
||||
return <EntityGroupsList groups={groups} showDivider />;
|
||||
return <EntityGroupsList groups={groups} showDivider visibleItems={5} />;
|
||||
};
|
||||
|
||||
export const MultipleGroupsWithAddNLazyLoad = EntityGroupsListTemplate.bind(
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useMemo } from "react";
|
||||
import React, { useEffect, useMemo } from "react";
|
||||
import { LoadMore } from "./EntityGroupsList.styles";
|
||||
import type {
|
||||
EntityGroupProps,
|
||||
|
|
@ -9,13 +9,13 @@ import { List, ListItem, type ListItemProps } from "../../../List";
|
|||
import { Divider } from "../../../Divider";
|
||||
|
||||
const EntityGroupsList = <T,>(props: EntityGroupsListProps<T>) => {
|
||||
const { flexProps, groups, showDivider } = props;
|
||||
const { flexProps, groups, showDivider, visibleItems } = props;
|
||||
|
||||
return (
|
||||
<Flex flexDirection="column" gap="spaces-4" overflowY="auto" {...flexProps}>
|
||||
{groups.map((group, index) => (
|
||||
<Flex flexDirection="column" gap="spaces-3" key={group.groupTitle}>
|
||||
<EntityGroup group={group} />
|
||||
<EntityGroup group={group} visibleItems={visibleItems} />
|
||||
{showDivider && index < groups.length - 1 && (
|
||||
<Divider
|
||||
style={{ borderColor: "var(--ads-v2-color-border-muted)" }}
|
||||
|
|
@ -27,8 +27,20 @@ const EntityGroupsList = <T,>(props: EntityGroupsListProps<T>) => {
|
|||
);
|
||||
};
|
||||
|
||||
const EntityGroup = <T,>({ group }: { group: EntityGroupProps<T> }) => {
|
||||
const [visibleItemsCount, setVisibleItemsCount] = React.useState(5);
|
||||
const EntityGroup = <T,>({
|
||||
group,
|
||||
visibleItems,
|
||||
}: {
|
||||
group: EntityGroupProps<T>;
|
||||
visibleItems?: number;
|
||||
}) => {
|
||||
const [visibleItemsCount, setVisibleItemsCount] = React.useState(
|
||||
visibleItems || group.items.length,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setVisibleItemsCount(visibleItems || group.items.length);
|
||||
}, [group.items.length, visibleItems]);
|
||||
|
||||
const lazyLoading = useMemo(() => {
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -16,4 +16,5 @@ export interface EntityGroupsListProps<T> {
|
|||
groups: EntityGroupProps<T>[];
|
||||
flexProps?: FlexProps;
|
||||
showDivider?: boolean;
|
||||
visibleItems?: number;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1670,7 +1670,7 @@ export const getQuerySegmentItems = createSelector(
|
|||
}
|
||||
|
||||
return {
|
||||
icon: ActionUrlIcon(iconUrl),
|
||||
icon: ActionUrlIcon(iconUrl, "16", "16"),
|
||||
title: action.config.name,
|
||||
key: action.config.baseId,
|
||||
type: action.config.pluginType,
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
import React, { useState } from "react";
|
||||
import ReactJson from "react-json-view";
|
||||
import {
|
||||
EntityGroupsList,
|
||||
Flex,
|
||||
List,
|
||||
ListItem,
|
||||
type ListItemProps,
|
||||
SearchInput,
|
||||
Text,
|
||||
|
|
@ -51,33 +50,19 @@ export const StateInspector = () => {
|
|||
value={searchTerm}
|
||||
/>
|
||||
</Flex>
|
||||
<Flex
|
||||
flexDirection="column"
|
||||
gap="spaces-3"
|
||||
overflowY="auto"
|
||||
pl="spaces-3"
|
||||
pr="spaces-3"
|
||||
>
|
||||
{filteredItemGroups.map((item) => (
|
||||
<Styled.Group
|
||||
flexDirection="column"
|
||||
gap="spaces-2"
|
||||
key={item.group}
|
||||
>
|
||||
<Styled.GroupName
|
||||
className="overflow-hidden overflow-ellipsis whitespace-nowrap flex-shrink-0"
|
||||
kind="body-s"
|
||||
>
|
||||
{item.group}
|
||||
</Styled.GroupName>
|
||||
<List>
|
||||
{item.items.map((eachItem) => (
|
||||
<ListItem key={eachItem.title} {...eachItem} />
|
||||
))}
|
||||
</List>
|
||||
</Styled.Group>
|
||||
))}
|
||||
</Flex>
|
||||
<EntityGroupsList
|
||||
flexProps={{
|
||||
pl: "spaces-3",
|
||||
pr: "spaces-3",
|
||||
}}
|
||||
groups={filteredItemGroups.map((item) => {
|
||||
return {
|
||||
groupTitle: item.group,
|
||||
items: item.items,
|
||||
className: "",
|
||||
};
|
||||
})}
|
||||
/>
|
||||
</Flex>
|
||||
{selectedItem ? (
|
||||
<Flex
|
||||
|
|
|
|||
|
|
@ -350,8 +350,8 @@ export function AppsmithAIIcon() {
|
|||
);
|
||||
}
|
||||
|
||||
export function ActionUrlIcon(url: string) {
|
||||
return <img src={url} />;
|
||||
export function ActionUrlIcon(url: string, height?: string, width?: string) {
|
||||
return <img height={height} src={url} width={width} />;
|
||||
}
|
||||
|
||||
export function DefaultModuleIcon() {
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import { getIDEViewMode } from "selectors/ideSelectors";
|
|||
import type { FlexProps } from "@appsmith/ads";
|
||||
import { EditorViewMode } from "ee/entities/IDE/constants";
|
||||
import { filterEntityGroupsBySearchTerm } from "IDE/utils";
|
||||
import { DEFAULT_GROUP_LIST_SIZE } from "../../constants";
|
||||
|
||||
const AddJS = () => {
|
||||
const dispatch = useDispatch();
|
||||
|
|
@ -98,7 +99,14 @@ const AddJS = () => {
|
|||
/>
|
||||
<SearchInput onChange={setSearchTerm} value={searchTerm} />
|
||||
{filteredItemGroups.length > 0 ? (
|
||||
<EntityGroupsList groups={filteredItemGroups} showDivider />
|
||||
<EntityGroupsList
|
||||
flexProps={{
|
||||
pb: "spaces-3",
|
||||
}}
|
||||
groups={filteredItemGroups}
|
||||
showDivider
|
||||
visibleItems={DEFAULT_GROUP_LIST_SIZE}
|
||||
/>
|
||||
) : null}
|
||||
{filteredItemGroups.length === 0 && searchTerm !== "" ? (
|
||||
<NoSearchResults
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import { useSelector } from "react-redux";
|
|||
import { getIDEViewMode } from "selectors/ideSelectors";
|
||||
import { EditorViewMode } from "ee/entities/IDE/constants";
|
||||
import { filterEntityGroupsBySearchTerm } from "IDE/utils";
|
||||
import { DEFAULT_GROUP_LIST_SIZE } from "../../constants";
|
||||
|
||||
const AddQuery = () => {
|
||||
const [searchTerm, setSearchTerm] = useState("");
|
||||
|
|
@ -59,7 +60,14 @@ const AddQuery = () => {
|
|||
/>
|
||||
<SearchInput autoFocus onChange={setSearchTerm} value={searchTerm} />
|
||||
{filteredItemGroups.length > 0 ? (
|
||||
<EntityGroupsList groups={filteredItemGroups} showDivider />
|
||||
<EntityGroupsList
|
||||
flexProps={{
|
||||
pb: "spaces-3",
|
||||
}}
|
||||
groups={filteredItemGroups}
|
||||
showDivider
|
||||
visibleItems={DEFAULT_GROUP_LIST_SIZE}
|
||||
/>
|
||||
) : null}
|
||||
{filteredItemGroups.length === 0 && searchTerm !== "" ? (
|
||||
<NoSearchResults
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React, { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import styled from "styled-components";
|
||||
import { Flex, List, ListItem, Text } from "@appsmith/ads";
|
||||
import { EntityGroupsList, Flex } from "@appsmith/ads";
|
||||
import { useSelector } from "react-redux";
|
||||
import {
|
||||
getDatasourceUsageCountForApp,
|
||||
|
|
@ -43,10 +43,6 @@ const DatasourceIcon = styled.img`
|
|||
width: 16px;
|
||||
`;
|
||||
|
||||
const StyledList = styled(List)`
|
||||
gap: 0;
|
||||
`;
|
||||
|
||||
interface DataSidePaneProps {
|
||||
// TODO: Fix this the next time the file is edited
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
|
|
@ -128,45 +124,33 @@ const DataSidePane = (props: DataSidePaneProps) => {
|
|||
icon={"datasource-v3"}
|
||||
/>
|
||||
) : null}
|
||||
<Flex
|
||||
flexDirection={"column"}
|
||||
gap="spaces-4"
|
||||
overflowY="auto"
|
||||
px="spaces-3"
|
||||
>
|
||||
{Object.entries(groupedDatasources).map(([key, value]) => (
|
||||
<Flex flexDirection={"column"} key={key}>
|
||||
<Flex px="spaces-3" py="spaces-1">
|
||||
<Text
|
||||
className="overflow-hidden overflow-ellipsis whitespace-nowrap"
|
||||
kind="body-s"
|
||||
>
|
||||
{key}
|
||||
</Text>
|
||||
</Flex>
|
||||
<StyledList>
|
||||
{value.map((data) => (
|
||||
<ListItem
|
||||
className="t--datasource"
|
||||
description={get(dsUsageMap, data.id, "")}
|
||||
descriptionType="block"
|
||||
isSelected={currentSelectedDatasource === data.id}
|
||||
key={data.id}
|
||||
onClick={() => goToDatasource(data.id)}
|
||||
startIcon={
|
||||
<DatasourceIcon
|
||||
src={getAssetUrl(
|
||||
groupedPlugins[data.pluginId].iconLocation,
|
||||
)}
|
||||
/>
|
||||
}
|
||||
title={data.name}
|
||||
/>
|
||||
))}
|
||||
</StyledList>
|
||||
</Flex>
|
||||
))}
|
||||
</Flex>
|
||||
<EntityGroupsList
|
||||
flexProps={{ px: "spaces-3" }}
|
||||
groups={Object.entries(groupedDatasources).map(([key, value]) => {
|
||||
return {
|
||||
groupTitle: key,
|
||||
items: value.map((data) => {
|
||||
return {
|
||||
id: data.id,
|
||||
title: data.name,
|
||||
startIcon: (
|
||||
<DatasourceIcon
|
||||
src={getAssetUrl(
|
||||
groupedPlugins[data.pluginId].iconLocation,
|
||||
)}
|
||||
/>
|
||||
),
|
||||
description: get(dsUsageMap, data.id, ""),
|
||||
descriptionType: "block",
|
||||
className: "t--datasource",
|
||||
isSelected: currentSelectedDatasource === data.id,
|
||||
onClick: () => goToDatasource(data.id),
|
||||
};
|
||||
}),
|
||||
className: "",
|
||||
};
|
||||
})}
|
||||
/>
|
||||
</PaneBody>
|
||||
</Flex>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import { CREATE_A_NEW_ITEM, createMessage } from "ee/constants/messages";
|
|||
import { useGroupedAddQueryOperations } from "ee/pages/Editor/IDE/EditorPane/Query/hooks";
|
||||
import { getShowCreateNewModal } from "selectors/ideSelectors";
|
||||
import { setShowQueryCreateNewModal } from "actions/ideActions";
|
||||
import { DEFAULT_GROUP_LIST_SIZE } from "../../constants";
|
||||
|
||||
const CreateNewQueryModal: React.FC = () => {
|
||||
const dispatch = useDispatch();
|
||||
|
|
@ -36,7 +37,11 @@ const CreateNewQueryModal: React.FC = () => {
|
|||
<ModalContent className="!w-[400px] action-creator-create-new-modal">
|
||||
<ModalHeader>{createMessage(CREATE_A_NEW_ITEM, "query")}</ModalHeader>
|
||||
<ModalBody>
|
||||
<EntityGroupsList groups={itemGroups} showDivider />
|
||||
<EntityGroupsList
|
||||
groups={itemGroups}
|
||||
showDivider
|
||||
visibleItems={DEFAULT_GROUP_LIST_SIZE}
|
||||
/>
|
||||
</ModalBody>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
|
|
|
|||
1
app/client/src/pages/Editor/IDE/constants.ts
Normal file
1
app/client/src/pages/Editor/IDE/constants.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export const DEFAULT_GROUP_LIST_SIZE = 5;
|
||||
Loading…
Reference in New Issue
Block a user