chore: Adding Group component in ADS Templates (#38512)
## Description Adding Group component in ADS Templates to use the same for a single list of grouped entities in the product. Fixes [#37615](https://github.com/appsmithorg/appsmith/issues/37615) [#37616](https://github.com/appsmithorg/appsmith/issues/37616) [#38288](https://github.com/appsmithorg/appsmith/issues/38288) [#38287](https://github.com/appsmithorg/appsmith/issues/38287) ## Automation /ok-to-test tags="@tag.All" ### 🔍 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/12704682977> > Commit: b62fecb2aeb4f3ebc9a9ed683f5d1d1949a943cc > <a href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=12704682977&attempt=2" target="_blank">Cypress dashboard</a>. > Tags: `@tag.All` > Spec: > <hr>Fri, 10 Jan 2025 09:11:50 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 component with improved grouping capabilities. - Added support for dynamic list rendering with custom children. - Introduced `EntityGroupsList` for more flexible group management. - Added new styled components for better visual representation of lists. - Added `LoadMore` styled component for improved UX in entity groups. - New Storybook examples for `EntityGroupsList` and `EntityGroup` components. - **Improvements** - Refined List component to support more flexible item rendering. - Updated styling for list components. - Improved type safety for list-related components. - Streamlined code structure for better maintainability. - **Changes** - Removed `GroupedList` component. - Updated list rendering across multiple components. - Simplified list item management. - Expanded public API for `EntityExplorer` module with new exports. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
parent
ca265494cf
commit
3d97706da3
|
|
@ -26,39 +26,47 @@ const ListTemplate = (args: ListProps) => {
|
||||||
return <List {...args} />;
|
return <List {...args} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const items = [
|
||||||
|
{
|
||||||
|
startIcon: <Icon name="file-list-2-line" size={"md"} />,
|
||||||
|
title: "Action item 1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startIcon: <Icon name="file-list-2-line" size={"md"} />,
|
||||||
|
title: "Action item 2",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startIcon: <Icon name="file-list-2-line" size={"md"} />,
|
||||||
|
title: "Action item 3",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startIcon: <Icon name="file-list-2-line" size={"md"} />,
|
||||||
|
title: "Action item 4",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startIcon: <Icon name="file-list-2-line" size={"md"} />,
|
||||||
|
title: "Action item 5",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startIcon: <Icon name="file-list-2-line" size={"md"} />,
|
||||||
|
title: "Action item 6",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startIcon: <Icon name="file-list-2-line" size={"md"} />,
|
||||||
|
title: "Action item 7",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
export const ListStory = ListTemplate.bind({}) as StoryObj;
|
export const ListStory = ListTemplate.bind({}) as StoryObj;
|
||||||
ListStory.storyName = "List";
|
ListStory.storyName = "List";
|
||||||
ListStory.args = {
|
ListStory.args = {
|
||||||
items: [
|
children: items.map((item) => (
|
||||||
{
|
<ListItem
|
||||||
startIcon: <Icon name="file-list-2-line" size={"md"} />,
|
key={`item-${item.title}`}
|
||||||
title: "Action item 1",
|
{...item}
|
||||||
},
|
onClick={() => alert("Clicked")}
|
||||||
{
|
/>
|
||||||
startIcon: <Icon name="file-list-2-line" size={"md"} />,
|
)),
|
||||||
title: "Action item 2",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
startIcon: <Icon name="file-list-2-line" size={"md"} />,
|
|
||||||
title: "Action item 3",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
startIcon: <Icon name="file-list-2-line" size={"md"} />,
|
|
||||||
title: "Action item 4",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
startIcon: <Icon name="file-list-2-line" size={"md"} />,
|
|
||||||
title: "Action item 5",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
startIcon: <Icon name="file-list-2-line" size={"md"} />,
|
|
||||||
title: "Action item 6",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
startIcon: <Icon name="file-list-2-line" size={"md"} />,
|
|
||||||
title: "Action item 7",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const ListItemArgTypes = {
|
const ListItemArgTypes = {
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,8 @@ import {
|
||||||
ListItemTextOverflowClassName,
|
ListItemTextOverflowClassName,
|
||||||
ListItemTitleClassName,
|
ListItemTitleClassName,
|
||||||
} from "./List.constants";
|
} from "./List.constants";
|
||||||
|
import { Flex } from "../Flex";
|
||||||
|
import { Text } from "../Text";
|
||||||
|
|
||||||
const Variables = css`
|
const Variables = css`
|
||||||
--listitem-title-font-size: var(--ads-v2-font-size-4);
|
--listitem-title-font-size: var(--ads-v2-font-size-4);
|
||||||
|
|
@ -71,7 +73,6 @@ export const StyledList = styled.div`
|
||||||
padding: var(--ads-v2-spaces-1);
|
padding: var(--ads-v2-spaces-1);
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: var(--ads-v2-spaces-2);
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const StyledListItem = styled.div<{
|
export const StyledListItem = styled.div<{
|
||||||
|
|
@ -159,3 +160,22 @@ export const StyledListItem = styled.div<{
|
||||||
padding-right: var(--ads-v2-spaces-2);
|
padding-right: var(--ads-v2-spaces-2);
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const StyledGroup = styled(Flex)`
|
||||||
|
& .ads-v2-listitem .ads-v2-listitem__idesc {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .ads-v2-listitem:hover .ads-v2-listitem__idesc {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const GroupedList = styled(StyledList)`
|
||||||
|
padding: 0;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const GroupTitle = styled(Text)`
|
||||||
|
padding: var(--ads-v2-spaces-1) 0;
|
||||||
|
color: var(--ads-v2-color-fg-muted);
|
||||||
|
`;
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,11 @@ import clsx from "classnames";
|
||||||
import type { ListItemProps, ListProps } from "./List.types";
|
import type { ListItemProps, ListProps } from "./List.types";
|
||||||
import {
|
import {
|
||||||
BottomContentWrapper,
|
BottomContentWrapper,
|
||||||
|
GroupedList,
|
||||||
|
GroupTitle,
|
||||||
InlineDescriptionWrapper,
|
InlineDescriptionWrapper,
|
||||||
RightControlWrapper,
|
RightControlWrapper,
|
||||||
|
StyledGroup,
|
||||||
StyledList,
|
StyledList,
|
||||||
StyledListItem,
|
StyledListItem,
|
||||||
TooltipTextWrapper,
|
TooltipTextWrapper,
|
||||||
|
|
@ -24,12 +27,15 @@ import {
|
||||||
} from "./List.constants";
|
} from "./List.constants";
|
||||||
import { useEventCallback } from "usehooks-ts";
|
import { useEventCallback } from "usehooks-ts";
|
||||||
|
|
||||||
function List({ className, items, ...rest }: ListProps) {
|
function List({ children, className, groupTitle, ...rest }: ListProps) {
|
||||||
return (
|
return groupTitle ? (
|
||||||
|
<StyledGroup flexDirection="column">
|
||||||
|
<GroupTitle kind="body-s">{groupTitle}</GroupTitle>
|
||||||
|
<GroupedList className={className}>{children}</GroupedList>
|
||||||
|
</StyledGroup>
|
||||||
|
) : (
|
||||||
<StyledList className={clsx(ListClassName, className)} {...rest}>
|
<StyledList className={clsx(ListClassName, className)} {...rest}>
|
||||||
{items.map((item) => {
|
{children}
|
||||||
return <ListItem key={item.title} {...item} />;
|
|
||||||
})}
|
|
||||||
</StyledList>
|
</StyledList>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,8 @@ export interface ListItemProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ListProps {
|
export interface ListProps {
|
||||||
items: ListItemProps[];
|
|
||||||
className?: string;
|
className?: string;
|
||||||
id?: string;
|
id?: string;
|
||||||
|
children: ReactNode | ReactNode[];
|
||||||
|
groupTitle?: string;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,185 @@
|
||||||
|
/* eslint-disable no-console */
|
||||||
|
import React from "react";
|
||||||
|
import type { Meta, StoryObj } from "@storybook/react";
|
||||||
|
|
||||||
|
import { EntityGroupsList, EntityGroup } from "./EntityGroupsList";
|
||||||
|
import type {
|
||||||
|
EntityGroupsListProps,
|
||||||
|
EntityGroupProps,
|
||||||
|
} from "./EntityGroupsList.types";
|
||||||
|
import { Icon } from "../../../Icon";
|
||||||
|
|
||||||
|
const meta: Meta<typeof EntityGroupsList> = {
|
||||||
|
title: "ADS/Templates/Entity Explorer/Entity Groups List",
|
||||||
|
component: EntityGroupsList,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
|
||||||
|
const EntityGroupTemplate = <T,>(props: EntityGroupProps<T>) => {
|
||||||
|
const { addConfig, className, groupTitle, items } = props;
|
||||||
|
|
||||||
|
return <EntityGroup group={{ addConfig, className, groupTitle, items }} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const SingleGroupWithAddNLazyLoad = EntityGroupTemplate.bind(
|
||||||
|
{},
|
||||||
|
) as StoryObj;
|
||||||
|
|
||||||
|
SingleGroupWithAddNLazyLoad.args = {
|
||||||
|
groupTitle: "Datasources",
|
||||||
|
className: "t--from-source-list",
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
startIcon: <Icon name="database-2-line" />,
|
||||||
|
className: "t--datasource-create-option-users",
|
||||||
|
title: "Users",
|
||||||
|
onClick: () => console.log("Users clicked"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startIcon: <Icon name="database-2-line" />,
|
||||||
|
className: "t--datasource-create-option-movies",
|
||||||
|
title: "Movies",
|
||||||
|
onClick: () => console.log("Movies clicked"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startIcon: <Icon name="database-2-line" />,
|
||||||
|
className: "t--datasource-create-option-untitled_datasource_1",
|
||||||
|
title: "Untitled datasource 1",
|
||||||
|
onClick: () => console.log("Untitled datasource 1 clicked"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startIcon: <Icon name="database-2-line" />,
|
||||||
|
className: "t--datasource-create-option-untitled_datasource_2",
|
||||||
|
title: "Untitled datasource 2",
|
||||||
|
onClick: () => console.log("Untitled datasource 2 clicked"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startIcon: <Icon name="database-2-line" />,
|
||||||
|
className: "t--datasource-create-option-untitled_datasource_3",
|
||||||
|
title: "Untitled datasource 3",
|
||||||
|
onClick: () => console.log("Untitled datasource 3 clicked"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startIcon: <Icon name="database-2-line" />,
|
||||||
|
className: "t--datasource-create-option-untitled_datasource_4",
|
||||||
|
title: "Untitled datasource 4",
|
||||||
|
onClick: () => console.log("Untitled datasource 4 clicked"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startIcon: <Icon name="database-2-line" />,
|
||||||
|
className: "t--datasource-create-option-users_(1)",
|
||||||
|
title: "Users (1)",
|
||||||
|
onClick: () => console.log("Users(1) clicked"),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
addConfig: {
|
||||||
|
icon: <Icon name="plus" />,
|
||||||
|
title: "New datasource",
|
||||||
|
onClick: () => console.log("New datasource clicked"),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const EntityGroupsListTemplate = <T,>(props: EntityGroupsListProps<T>) => {
|
||||||
|
const { groups } = props;
|
||||||
|
|
||||||
|
return <EntityGroupsList groups={groups} showDivider />;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const MultipleGroupsWithAddNLazyLoad = EntityGroupsListTemplate.bind(
|
||||||
|
{},
|
||||||
|
) as StoryObj;
|
||||||
|
|
||||||
|
MultipleGroupsWithAddNLazyLoad.args = {
|
||||||
|
groups: [
|
||||||
|
{
|
||||||
|
groupTitle: "Datasources",
|
||||||
|
className: "t--from-source-list",
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
startIcon: <Icon name="database-2-line" />,
|
||||||
|
className: "t--datasource-create-option-users",
|
||||||
|
title: "Users",
|
||||||
|
onClick: () => console.log("Users clicked"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startIcon: <Icon name="database-2-line" />,
|
||||||
|
className: "t--datasource-create-option-movies",
|
||||||
|
title: "Movies",
|
||||||
|
onClick: () => console.log("Movies clicked"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startIcon: <Icon name="database-2-line" />,
|
||||||
|
className: "t--datasource-create-option-untitled_datasource_1",
|
||||||
|
title: "Untitled datasource 1",
|
||||||
|
onClick: () => console.log("Untitled datasource 1 clicked"),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
addConfig: {
|
||||||
|
icon: <Icon name="plus" />,
|
||||||
|
title: "New datasource",
|
||||||
|
onClick: () => console.log("New datasource clicked"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
groupTitle: "Apis",
|
||||||
|
className: "t--from-source-list",
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
startIcon: <Icon name="database-2-line" />,
|
||||||
|
className: "t--datasource-create-option-users",
|
||||||
|
title: "Users",
|
||||||
|
onClick: () => console.log("Users clicked"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startIcon: <Icon name="database-2-line" />,
|
||||||
|
className: "t--datasource-create-option-movies",
|
||||||
|
title: "Movies",
|
||||||
|
onClick: () => console.log("Movies clicked"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startIcon: <Icon name="database-2-line" />,
|
||||||
|
className: "t--datasource-create-option-untitled_datasource_1",
|
||||||
|
title: "Untitled datasource 1",
|
||||||
|
onClick: () => console.log("Untitled datasource 1 clicked"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startIcon: <Icon name="database-2-line" />,
|
||||||
|
className: "t--datasource-create-option-untitled_datasource_2",
|
||||||
|
title: "Untitled datasource 2",
|
||||||
|
onClick: () => console.log("Untitled datasource 2 clicked"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startIcon: <Icon name="database-2-line" />,
|
||||||
|
className: "t--datasource-create-option-untitled_datasource_3",
|
||||||
|
title: "Untitled datasource 3",
|
||||||
|
onClick: () => console.log("Untitled datasource 3 clicked"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startIcon: <Icon name="database-2-line" />,
|
||||||
|
className: "t--datasource-create-option-untitled_datasource_4",
|
||||||
|
title: "Untitled datasource 4",
|
||||||
|
onClick: () => console.log("Untitled datasource 4 clicked"),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
groupTitle: "Apis",
|
||||||
|
className: "t--from-source-list",
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
startIcon: <Icon name="database-2-line" />,
|
||||||
|
className: "t--datasource-create-option-users",
|
||||||
|
title: "Users",
|
||||||
|
onClick: () => console.log("Users clicked"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startIcon: <Icon name="database-2-line" />,
|
||||||
|
className: "t--datasource-create-option-movies",
|
||||||
|
title: "Movies",
|
||||||
|
onClick: () => console.log("Movies clicked"),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
import styled from "styled-components";
|
||||||
|
import { ListItem } from "../../../List";
|
||||||
|
|
||||||
|
export const LoadMore = styled(ListItem)`
|
||||||
|
.ads-v2-listitem__title {
|
||||||
|
color: var(--ads-v2-color-fg-subtle);
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
@ -0,0 +1,80 @@
|
||||||
|
import React, { useMemo } from "react";
|
||||||
|
import { LoadMore } from "./EntityGroupsList.styles";
|
||||||
|
import type {
|
||||||
|
EntityGroupProps,
|
||||||
|
EntityGroupsListProps,
|
||||||
|
} from "./EntityGroupsList.types";
|
||||||
|
import { Flex } from "../../../Flex";
|
||||||
|
import { List, ListItem, type ListItemProps } from "../../../List";
|
||||||
|
import { Divider } from "../../../Divider";
|
||||||
|
|
||||||
|
const EntityGroupsList = <T,>(props: EntityGroupsListProps<T>) => {
|
||||||
|
const { flexProps, groups, showDivider } = 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} />
|
||||||
|
{showDivider && index < groups.length - 1 && (
|
||||||
|
<Divider
|
||||||
|
style={{ borderColor: "var(--ads-v2-color-border-muted)" }}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Flex>
|
||||||
|
))}
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const EntityGroup = <T,>({ group }: { group: EntityGroupProps<T> }) => {
|
||||||
|
const [visibleItemsCount, setVisibleItemsCount] = React.useState(5);
|
||||||
|
|
||||||
|
const lazyLoading = useMemo(() => {
|
||||||
|
return {
|
||||||
|
visibleItemsCount,
|
||||||
|
hasMore: visibleItemsCount < group.items.length,
|
||||||
|
handleLoadMore: () => setVisibleItemsCount(group.items.length),
|
||||||
|
};
|
||||||
|
}, [visibleItemsCount, group.items.length]);
|
||||||
|
|
||||||
|
const updatedGroup = lazyLoading.hasMore
|
||||||
|
? {
|
||||||
|
...group,
|
||||||
|
items: group.items.slice(0, lazyLoading.visibleItemsCount),
|
||||||
|
}
|
||||||
|
: group;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Flex
|
||||||
|
className="entity-group"
|
||||||
|
flexDirection={"column"}
|
||||||
|
key={group.groupTitle}
|
||||||
|
>
|
||||||
|
<List className={group.className} groupTitle={group.groupTitle}>
|
||||||
|
{updatedGroup.items.map((item: T, index) =>
|
||||||
|
group.renderList ? (
|
||||||
|
group.renderList(item)
|
||||||
|
) : (
|
||||||
|
<ListItem
|
||||||
|
key={(item as ListItemProps)?.title || `item-${index}`}
|
||||||
|
{...(item as ListItemProps)}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
)}
|
||||||
|
</List>
|
||||||
|
{lazyLoading?.hasMore && (
|
||||||
|
<LoadMore onClick={lazyLoading?.handleLoadMore} title="Load more..." />
|
||||||
|
)}
|
||||||
|
{group.addConfig && (
|
||||||
|
<ListItem
|
||||||
|
onClick={group.addConfig?.onClick}
|
||||||
|
startIcon={group.addConfig?.icon}
|
||||||
|
title={group.addConfig?.title}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export { EntityGroup, EntityGroupsList };
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
import type { MouseEvent, ReactNode } from "react";
|
||||||
|
import type { FlexProps } from "../../../Flex";
|
||||||
|
export interface EntityGroupProps<T> {
|
||||||
|
groupTitle: string;
|
||||||
|
className: string;
|
||||||
|
items: T[];
|
||||||
|
addConfig?: {
|
||||||
|
icon: ReactNode;
|
||||||
|
title: string;
|
||||||
|
onClick: (e: MouseEvent) => void;
|
||||||
|
};
|
||||||
|
renderList?: (item: T) => React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface EntityGroupsListProps<T> {
|
||||||
|
groups: EntityGroupProps<T>[];
|
||||||
|
flexProps?: FlexProps;
|
||||||
|
showDivider?: boolean;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
export { EntityGroup, EntityGroupsList } from "./EntityGroupsList";
|
||||||
|
export type {
|
||||||
|
EntityGroupProps,
|
||||||
|
EntityGroupsListProps,
|
||||||
|
} from "./EntityGroupsList.types";
|
||||||
|
|
@ -1 +1,2 @@
|
||||||
export { EntityItem } from "./EntityItem";
|
export { EntityItem } from "./EntityItem";
|
||||||
|
export type { EntityItemProps } from "./EntityItem.types";
|
||||||
|
|
|
||||||
|
|
@ -7,3 +7,4 @@ export { NoSearchResults } from "./NoSearchResults";
|
||||||
export * from "./ExplorerContainer";
|
export * from "./ExplorerContainer";
|
||||||
export * from "./EntityItem";
|
export * from "./EntityItem";
|
||||||
export { useEditableText } from "./Editable";
|
export { useEditableText } from "./Editable";
|
||||||
|
export * from "./EntityGroupsList";
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import { IDEHeaderSwitcher } from "./HeaderSwitcher";
|
||||||
import { noop } from "lodash";
|
import { noop } from "lodash";
|
||||||
import { Icon } from "../../Icon";
|
import { Icon } from "../../Icon";
|
||||||
import { Button } from "../../Button";
|
import { Button } from "../../Button";
|
||||||
import { List } from "../../List";
|
import { List, ListItem } from "../../List";
|
||||||
import { Flex } from "../../Flex";
|
import { Flex } from "../../Flex";
|
||||||
import { Text } from "../../Text";
|
import { Text } from "../../Text";
|
||||||
import { ListHeaderContainer } from "../EntityExplorer/styles";
|
import { ListHeaderContainer } from "../EntityExplorer/styles";
|
||||||
|
|
@ -58,6 +58,16 @@ export const WithHeaderTitle = () => {
|
||||||
|
|
||||||
export const WithHeaderDropdown = () => {
|
export const WithHeaderDropdown = () => {
|
||||||
const [open, setOpen] = React.useState(false);
|
const [open, setOpen] = React.useState(false);
|
||||||
|
const items = [
|
||||||
|
{
|
||||||
|
title: "Page1",
|
||||||
|
onClick: noop,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Page2",
|
||||||
|
onClick: noop,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<IDEHeader>
|
<IDEHeader>
|
||||||
|
|
@ -79,18 +89,11 @@ export const WithHeaderDropdown = () => {
|
||||||
<Text kind="heading-xs">Pages</Text>
|
<Text kind="heading-xs">Pages</Text>
|
||||||
<Button isIconButton kind="tertiary" startIcon="plus" />
|
<Button isIconButton kind="tertiary" startIcon="plus" />
|
||||||
</ListHeaderContainer>
|
</ListHeaderContainer>
|
||||||
<List
|
<List>
|
||||||
items={[
|
{items.map((item) => (
|
||||||
{
|
<ListItem key={item.title} {...item} />
|
||||||
title: "Page1",
|
))}
|
||||||
onClick: noop,
|
</List>
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Page2",
|
|
||||||
onClick: noop,
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
</Flex>
|
</Flex>
|
||||||
</IDEHeaderSwitcher>
|
</IDEHeaderSwitcher>
|
||||||
</IDEHeader.Left>
|
</IDEHeader.Left>
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,11 @@ import type { UseRoutes } from "ee/entities/IDE/constants";
|
||||||
import type { AppState } from "ee/reducers";
|
import type { AppState } from "ee/reducers";
|
||||||
import keyBy from "lodash/keyBy";
|
import keyBy from "lodash/keyBy";
|
||||||
import { getPluginEntityIcon } from "pages/Editor/Explorer/ExplorerIcons";
|
import { getPluginEntityIcon } from "pages/Editor/Explorer/ExplorerIcons";
|
||||||
import type { ListItemProps } from "@appsmith/ads";
|
import {
|
||||||
|
type EntityGroupProps,
|
||||||
|
type ListItemProps,
|
||||||
|
type EntityItemProps,
|
||||||
|
} from "@appsmith/ads";
|
||||||
import { createAddClassName } from "pages/Editor/IDE/EditorPane/utils";
|
import { createAddClassName } from "pages/Editor/IDE/EditorPane/utils";
|
||||||
import { getIDEViewMode } from "selectors/ideSelectors";
|
import { getIDEViewMode } from "selectors/ideSelectors";
|
||||||
import { EditorViewMode } from "ee/entities/IDE/constants";
|
import { EditorViewMode } from "ee/entities/IDE/constants";
|
||||||
|
|
@ -71,9 +75,10 @@ export type GroupedAddOperations = Array<{
|
||||||
operations: ActionOperation[];
|
operations: ActionOperation[];
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
export const useGroupedAddQueryOperations = (): GroupedAddOperations => {
|
export const useGroupedAddQueryOperations = () => {
|
||||||
const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled);
|
const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled);
|
||||||
const pagePermissions = useSelector(getPagePermissions);
|
const pagePermissions = useSelector(getPagePermissions);
|
||||||
|
const { getListItems } = useAddQueryListItems();
|
||||||
|
|
||||||
const canCreateActions = getHasCreateActionPermission(
|
const canCreateActions = getHasCreateActionPermission(
|
||||||
isFeatureEnabled,
|
isFeatureEnabled,
|
||||||
|
|
@ -91,6 +96,7 @@ export const useGroupedAddQueryOperations = (): GroupedAddOperations => {
|
||||||
);
|
);
|
||||||
|
|
||||||
const groups: GroupedAddOperations = [];
|
const groups: GroupedAddOperations = [];
|
||||||
|
const groupedItems: EntityGroupProps<ListItemProps | EntityItemProps>[] = [];
|
||||||
|
|
||||||
/** From existing Datasource **/
|
/** From existing Datasource **/
|
||||||
|
|
||||||
|
|
@ -108,7 +114,35 @@ export const useGroupedAddQueryOperations = (): GroupedAddOperations => {
|
||||||
operations: fromNewBlankAPI,
|
operations: fromNewBlankAPI,
|
||||||
});
|
});
|
||||||
|
|
||||||
return groups;
|
groups.map((group) => {
|
||||||
|
const items = getListItems(group.operations);
|
||||||
|
const lastItem = items[items.length - 1];
|
||||||
|
|
||||||
|
if (group.title === "Datasources" && lastItem?.title === "New datasource") {
|
||||||
|
items.splice(items.length - 1);
|
||||||
|
|
||||||
|
const addConfig = {
|
||||||
|
icon: lastItem.startIcon,
|
||||||
|
onClick: lastItem.onClick,
|
||||||
|
title: lastItem.title,
|
||||||
|
};
|
||||||
|
|
||||||
|
groupedItems.push({
|
||||||
|
groupTitle: group.title,
|
||||||
|
className: group.className,
|
||||||
|
items,
|
||||||
|
addConfig,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
groupedItems.push({
|
||||||
|
groupTitle: group.title || "",
|
||||||
|
className: group.className,
|
||||||
|
items,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return groupedItems;
|
||||||
};
|
};
|
||||||
|
|
||||||
const PluginActionEditor = lazy(async () =>
|
const PluginActionEditor = lazy(async () =>
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import ReactJson from "react-json-view";
|
||||||
import {
|
import {
|
||||||
Flex,
|
Flex,
|
||||||
List,
|
List,
|
||||||
|
ListItem,
|
||||||
type ListItemProps,
|
type ListItemProps,
|
||||||
SearchInput,
|
SearchInput,
|
||||||
Text,
|
Text,
|
||||||
|
|
@ -69,7 +70,11 @@ export const StateInspector = () => {
|
||||||
>
|
>
|
||||||
{item.group}
|
{item.group}
|
||||||
</Styled.GroupName>
|
</Styled.GroupName>
|
||||||
<List items={item.items} />
|
<List>
|
||||||
|
{item.items.map((eachItem) => (
|
||||||
|
<ListItem key={eachItem.title} {...eachItem} />
|
||||||
|
))}
|
||||||
|
</List>
|
||||||
</Styled.Group>
|
</Styled.Group>
|
||||||
))}
|
))}
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import {
|
||||||
PopoverTrigger,
|
PopoverTrigger,
|
||||||
PopoverContent,
|
PopoverContent,
|
||||||
List,
|
List,
|
||||||
|
ListItem,
|
||||||
} from "@appsmith/ads";
|
} from "@appsmith/ads";
|
||||||
import styles from "./styles.module.css";
|
import styles from "./styles.module.css";
|
||||||
import type { DebuggerLog } from "../../types";
|
import type { DebuggerLog } from "../../types";
|
||||||
|
|
@ -17,6 +18,41 @@ export default function HelpDropdown(props: DebuggerLog) {
|
||||||
|
|
||||||
const errorMessage = args?.[0]?.message;
|
const errorMessage = args?.[0]?.message;
|
||||||
|
|
||||||
|
const items = [
|
||||||
|
{
|
||||||
|
startIcon: <Icon name="book" size="md" />,
|
||||||
|
title: "Documentation",
|
||||||
|
onClick: () => {
|
||||||
|
window.open(CUSTOM_WIDGET_DOC_URL, "_blank");
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// startIcon: <Icon name="wand" size="md" />,
|
||||||
|
// title: "Troubleshoot with AI",
|
||||||
|
// onClick: noop,
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
startIcon: <Icon name="snippet" size="md" />,
|
||||||
|
title: createMessage(
|
||||||
|
CUSTOM_WIDGET_FEATURE.debugger.helpDropdown.stackoverflow,
|
||||||
|
),
|
||||||
|
onClick: () => {
|
||||||
|
args[0] &&
|
||||||
|
window.open(
|
||||||
|
`https://stackoverflow.com/search?q=${
|
||||||
|
"[javascript] " + encodeURIComponent(errorMessage as string)
|
||||||
|
}}`,
|
||||||
|
"_blank",
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// startIcon: <Icon name="support" size="md" />,
|
||||||
|
// title: "Appsmith Support",
|
||||||
|
// onClick: noop,
|
||||||
|
// },
|
||||||
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Popover>
|
<Popover>
|
||||||
<PopoverTrigger>
|
<PopoverTrigger>
|
||||||
|
|
@ -28,43 +64,11 @@ export default function HelpDropdown(props: DebuggerLog) {
|
||||||
/>
|
/>
|
||||||
</PopoverTrigger>
|
</PopoverTrigger>
|
||||||
<PopoverContent className={styles.consoleItemHelpContent}>
|
<PopoverContent className={styles.consoleItemHelpContent}>
|
||||||
<List
|
<List>
|
||||||
items={[
|
{items.map((item) => (
|
||||||
{
|
<ListItem key={item.title} {...item} />
|
||||||
startIcon: <Icon name="book" size="md" />,
|
))}
|
||||||
title: "Documentation",
|
</List>
|
||||||
onClick: () => {
|
|
||||||
window.open(CUSTOM_WIDGET_DOC_URL, "_blank");
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// {
|
|
||||||
// startIcon: <Icon name="wand" size="md" />,
|
|
||||||
// title: "Troubleshoot with AI",
|
|
||||||
// onClick: noop,
|
|
||||||
// },
|
|
||||||
{
|
|
||||||
startIcon: <Icon name="snippet" size="md" />,
|
|
||||||
title: createMessage(
|
|
||||||
CUSTOM_WIDGET_FEATURE.debugger.helpDropdown.stackoverflow,
|
|
||||||
),
|
|
||||||
onClick: () => {
|
|
||||||
args[0] &&
|
|
||||||
window.open(
|
|
||||||
`https://stackoverflow.com/search?q=${
|
|
||||||
"[javascript] " +
|
|
||||||
encodeURIComponent(errorMessage as string)
|
|
||||||
}}`,
|
|
||||||
"_blank",
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// {
|
|
||||||
// startIcon: <Icon name="support" size="md" />,
|
|
||||||
// title: "Appsmith Support",
|
|
||||||
// onClick: noop,
|
|
||||||
// },
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
</PopoverContent>
|
</PopoverContent>
|
||||||
</Popover>
|
</Popover>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,14 @@ import React, { useCallback, useState } from "react";
|
||||||
import SegmentAddHeader from "../components/SegmentAddHeader";
|
import SegmentAddHeader from "../components/SegmentAddHeader";
|
||||||
import { EDITOR_PANE_TEXTS, createMessage } from "ee/constants/messages";
|
import { EDITOR_PANE_TEXTS, createMessage } from "ee/constants/messages";
|
||||||
import type { ListItemProps } from "@appsmith/ads";
|
import type { ListItemProps } from "@appsmith/ads";
|
||||||
import { Flex, SearchInput, NoSearchResults } from "@appsmith/ads";
|
import {
|
||||||
|
EntityGroupsList,
|
||||||
|
Flex,
|
||||||
|
SearchInput,
|
||||||
|
NoSearchResults,
|
||||||
|
} from "@appsmith/ads";
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import { getCurrentPageId } from "selectors/editorSelectors";
|
import { getCurrentPageId } from "selectors/editorSelectors";
|
||||||
import GroupedList from "../components/GroupedList";
|
|
||||||
import {
|
import {
|
||||||
useGroupedAddJsOperations,
|
useGroupedAddJsOperations,
|
||||||
useJSAdd,
|
useJSAdd,
|
||||||
|
|
@ -54,7 +58,7 @@ const AddJS = () => {
|
||||||
|
|
||||||
const itemGroups = groupedJsOperations.map(
|
const itemGroups = groupedJsOperations.map(
|
||||||
({ className, operations, title }) => ({
|
({ className, operations, title }) => ({
|
||||||
groupTitle: title,
|
groupTitle: title || "",
|
||||||
className: className,
|
className: className,
|
||||||
items: operations.map(getListItems),
|
items: operations.map(getListItems),
|
||||||
}),
|
}),
|
||||||
|
|
@ -94,7 +98,7 @@ const AddJS = () => {
|
||||||
/>
|
/>
|
||||||
<SearchInput onChange={setSearchTerm} value={searchTerm} />
|
<SearchInput onChange={setSearchTerm} value={searchTerm} />
|
||||||
{filteredItemGroups.length > 0 ? (
|
{filteredItemGroups.length > 0 ? (
|
||||||
<GroupedList groups={filteredItemGroups} />
|
<EntityGroupsList groups={filteredItemGroups} showDivider />
|
||||||
) : null}
|
) : null}
|
||||||
{filteredItemGroups.length === 0 && searchTerm !== "" ? (
|
{filteredItemGroups.length === 0 && searchTerm !== "" ? (
|
||||||
<NoSearchResults
|
<NoSearchResults
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,16 @@
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import {
|
import {
|
||||||
|
EntityGroupsList,
|
||||||
Flex,
|
Flex,
|
||||||
SearchInput,
|
SearchInput,
|
||||||
NoSearchResults,
|
NoSearchResults,
|
||||||
type FlexProps,
|
type FlexProps,
|
||||||
|
type ListItemProps,
|
||||||
} from "@appsmith/ads";
|
} from "@appsmith/ads";
|
||||||
|
|
||||||
import { createMessage, EDITOR_PANE_TEXTS } from "ee/constants/messages";
|
import { createMessage, EDITOR_PANE_TEXTS } from "ee/constants/messages";
|
||||||
import SegmentAddHeader from "../components/SegmentAddHeader";
|
import SegmentAddHeader from "../components/SegmentAddHeader";
|
||||||
import GroupedList from "../components/GroupedList";
|
|
||||||
import {
|
import {
|
||||||
useAddQueryListItems,
|
|
||||||
useGroupedAddQueryOperations,
|
useGroupedAddQueryOperations,
|
||||||
useQueryAdd,
|
useQueryAdd,
|
||||||
} from "ee/pages/Editor/IDE/EditorPane/Query/hooks";
|
} from "ee/pages/Editor/IDE/EditorPane/Query/hooks";
|
||||||
|
|
@ -21,21 +21,14 @@ import { filterEntityGroupsBySearchTerm } from "IDE/utils";
|
||||||
|
|
||||||
const AddQuery = () => {
|
const AddQuery = () => {
|
||||||
const [searchTerm, setSearchTerm] = useState("");
|
const [searchTerm, setSearchTerm] = useState("");
|
||||||
const { getListItems } = useAddQueryListItems();
|
const itemGroups = useGroupedAddQueryOperations();
|
||||||
const groupedActionOperations = useGroupedAddQueryOperations();
|
|
||||||
const { closeAddQuery } = useQueryAdd();
|
const { closeAddQuery } = useQueryAdd();
|
||||||
const ideViewMode = useSelector(getIDEViewMode);
|
const ideViewMode = useSelector(getIDEViewMode);
|
||||||
|
|
||||||
const itemGroups = groupedActionOperations.map((group) => ({
|
const filteredItemGroups = filterEntityGroupsBySearchTerm<
|
||||||
groupTitle: group.title,
|
{ groupTitle: string; className: string },
|
||||||
className: group.className,
|
ListItemProps
|
||||||
items: getListItems(group.operations),
|
>(searchTerm, itemGroups);
|
||||||
}));
|
|
||||||
|
|
||||||
const filteredItemGroups = filterEntityGroupsBySearchTerm(
|
|
||||||
searchTerm,
|
|
||||||
itemGroups,
|
|
||||||
);
|
|
||||||
|
|
||||||
const extraPadding: FlexProps =
|
const extraPadding: FlexProps =
|
||||||
ideViewMode === EditorViewMode.FullScreen
|
ideViewMode === EditorViewMode.FullScreen
|
||||||
|
|
@ -66,7 +59,7 @@ const AddQuery = () => {
|
||||||
/>
|
/>
|
||||||
<SearchInput autoFocus onChange={setSearchTerm} value={searchTerm} />
|
<SearchInput autoFocus onChange={setSearchTerm} value={searchTerm} />
|
||||||
{filteredItemGroups.length > 0 ? (
|
{filteredItemGroups.length > 0 ? (
|
||||||
<GroupedList groups={filteredItemGroups} />
|
<EntityGroupsList groups={filteredItemGroups} showDivider />
|
||||||
) : null}
|
) : null}
|
||||||
{filteredItemGroups.length === 0 && searchTerm !== "" ? (
|
{filteredItemGroups.length === 0 && searchTerm !== "" ? (
|
||||||
<NoSearchResults
|
<NoSearchResults
|
||||||
|
|
|
||||||
|
|
@ -1,79 +0,0 @@
|
||||||
import React, { useMemo, useState } from "react";
|
|
||||||
import type { GroupedListProps } from "./types";
|
|
||||||
import { DEFAULT_GROUP_LIST_SIZE } from "./constants";
|
|
||||||
import { Flex, List, Text } from "@appsmith/ads";
|
|
||||||
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 .ads-v2-listitem__idesc {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
& .ads-v2-listitem:hover .ads-v2-listitem__idesc {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const Group: React.FC<GroupProps> = ({ group }) => {
|
|
||||||
const [visibleItemsCount, setVisibleItemsCount] = useState<number>(
|
|
||||||
DEFAULT_GROUP_LIST_SIZE,
|
|
||||||
);
|
|
||||||
const { className, groupTitle, items: groupItems } = group;
|
|
||||||
|
|
||||||
const items = useMemo(() => {
|
|
||||||
const items = groupItems.slice(0, visibleItemsCount);
|
|
||||||
const hasMoreItems = groupItems.length > visibleItemsCount;
|
|
||||||
|
|
||||||
const handleLoadMore = () => {
|
|
||||||
setVisibleItemsCount(groupItems.length);
|
|
||||||
};
|
|
||||||
|
|
||||||
if (hasMoreItems) {
|
|
||||||
items.push({
|
|
||||||
title: "Load more...",
|
|
||||||
onClick: handleLoadMore,
|
|
||||||
className: "ds-load-more",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: try to avoid this
|
|
||||||
if (hasMoreItems && groupTitle === "Datasources") {
|
|
||||||
items.push(groupItems[groupItems.length - 1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return items;
|
|
||||||
}, [groupItems, visibleItemsCount, groupTitle]);
|
|
||||||
|
|
||||||
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="px-0 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 };
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
import React from "react";
|
|
||||||
import type { FlexProps } from "@appsmith/ads";
|
|
||||||
import { Flex } from "@appsmith/ads";
|
|
||||||
import styled from "styled-components";
|
|
||||||
import type { GroupedListProps } from "./types";
|
|
||||||
import { Group } from "./Group";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
groups: GroupedListProps[];
|
|
||||||
flexProps?: FlexProps;
|
|
||||||
}
|
|
||||||
|
|
||||||
const StyledFlex = styled(Flex)`
|
|
||||||
& .groups-list-group:last-child {
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const GroupedList = (props: Props) => {
|
|
||||||
return (
|
|
||||||
<StyledFlex
|
|
||||||
flex="1"
|
|
||||||
flexDirection="column"
|
|
||||||
gap="spaces-4"
|
|
||||||
overflowY="auto"
|
|
||||||
{...props.flexProps}
|
|
||||||
>
|
|
||||||
{props.groups.map((group) => (
|
|
||||||
<Group group={group} key={group.groupTitle} />
|
|
||||||
))}
|
|
||||||
</StyledFlex>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default GroupedList;
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
export const DEFAULT_GROUP_LIST_SIZE = 5;
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { useCallback, useEffect, useMemo, useState } from "react";
|
import React, { useCallback, useEffect, useMemo, useState } from "react";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import { Flex, List, Text } from "@appsmith/ads";
|
import { Flex, List, ListItem, Text } from "@appsmith/ads";
|
||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
import {
|
import {
|
||||||
getDatasourceUsageCountForApp,
|
getDatasourceUsageCountForApp,
|
||||||
|
|
@ -144,23 +144,26 @@ const DataSidePane = (props: DataSidePaneProps) => {
|
||||||
{key}
|
{key}
|
||||||
</Text>
|
</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
<StyledList
|
<StyledList>
|
||||||
items={value.map((data) => ({
|
{value.map((data) => (
|
||||||
className: "t--datasource",
|
<ListItem
|
||||||
title: data.name,
|
className="t--datasource"
|
||||||
onClick: () => goToDatasource(data.id),
|
description={get(dsUsageMap, data.id, "")}
|
||||||
description: get(dsUsageMap, data.id, ""),
|
descriptionType="block"
|
||||||
descriptionType: "block",
|
isSelected={currentSelectedDatasource === data.id}
|
||||||
isSelected: currentSelectedDatasource === data.id,
|
key={data.id}
|
||||||
startIcon: (
|
onClick={() => goToDatasource(data.id)}
|
||||||
<DatasourceIcon
|
startIcon={
|
||||||
src={getAssetUrl(
|
<DatasourceIcon
|
||||||
groupedPlugins[data.pluginId].iconLocation,
|
src={getAssetUrl(
|
||||||
)}
|
groupedPlugins[data.pluginId].iconLocation,
|
||||||
/>
|
)}
|
||||||
),
|
/>
|
||||||
}))}
|
}
|
||||||
/>
|
title={data.name}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</StyledList>
|
||||||
</Flex>
|
</Flex>
|
||||||
))}
|
))}
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,21 @@
|
||||||
import React, { useEffect } from "react";
|
import React, { useEffect } from "react";
|
||||||
import { Modal, ModalContent, ModalHeader, ModalBody } from "@appsmith/ads";
|
import {
|
||||||
|
EntityGroupsList,
|
||||||
|
Modal,
|
||||||
|
ModalContent,
|
||||||
|
ModalHeader,
|
||||||
|
ModalBody,
|
||||||
|
} from "@appsmith/ads";
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
|
|
||||||
import { CREATE_A_NEW_ITEM, createMessage } from "ee/constants/messages";
|
import { CREATE_A_NEW_ITEM, createMessage } from "ee/constants/messages";
|
||||||
import GroupedList from "pages/Editor/IDE/EditorPane/components/GroupedList";
|
import { useGroupedAddQueryOperations } from "ee/pages/Editor/IDE/EditorPane/Query/hooks";
|
||||||
import {
|
|
||||||
useAddQueryListItems,
|
|
||||||
useGroupedAddQueryOperations,
|
|
||||||
} from "ee/pages/Editor/IDE/EditorPane/Query/hooks";
|
|
||||||
import { getShowCreateNewModal } from "selectors/ideSelectors";
|
import { getShowCreateNewModal } from "selectors/ideSelectors";
|
||||||
import { setShowQueryCreateNewModal } from "actions/ideActions";
|
import { setShowQueryCreateNewModal } from "actions/ideActions";
|
||||||
|
|
||||||
const CreateNewQueryModal: React.FC = () => {
|
const CreateNewQueryModal: React.FC = () => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const groupedActionOperations = useGroupedAddQueryOperations();
|
const itemGroups = useGroupedAddQueryOperations();
|
||||||
const { getListItems } = useAddQueryListItems();
|
|
||||||
const showCreateNewModal = useSelector(getShowCreateNewModal);
|
const showCreateNewModal = useSelector(getShowCreateNewModal);
|
||||||
|
|
||||||
const onCloseHandler = (open: boolean) => {
|
const onCloseHandler = (open: boolean) => {
|
||||||
|
|
@ -35,13 +36,7 @@ const CreateNewQueryModal: React.FC = () => {
|
||||||
<ModalContent className="!w-[400px] action-creator-create-new-modal">
|
<ModalContent className="!w-[400px] action-creator-create-new-modal">
|
||||||
<ModalHeader>{createMessage(CREATE_A_NEW_ITEM, "query")}</ModalHeader>
|
<ModalHeader>{createMessage(CREATE_A_NEW_ITEM, "query")}</ModalHeader>
|
||||||
<ModalBody>
|
<ModalBody>
|
||||||
<GroupedList
|
<EntityGroupsList groups={itemGroups} showDivider />
|
||||||
groups={groupedActionOperations.map((group) => ({
|
|
||||||
groupTitle: group.title,
|
|
||||||
className: group.className,
|
|
||||||
items: getListItems(group.operations),
|
|
||||||
}))}
|
|
||||||
/>
|
|
||||||
</ModalBody>
|
</ModalBody>
|
||||||
</ModalContent>
|
</ModalContent>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user