Skip to content

Commit

Permalink
chore: Show only a limited set of widgets in the beginning (#34644)
Browse files Browse the repository at this point in the history
## Description

Controls the collapsible sections of the Widget Add pane. This will
ensure we do not show all the widgets for add when a new user is
exploring for the first time. Once the users adds a widget, the other
sections opens up automatically.

Also removes List and JSONForm widgets from the SuggestedWidget tag

Fixes #34386

## Automation

/ok-to-test tags="@tag.Widget, @tag.IDE"

### 🔍 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/9777505836>
> Commit: a604723
> <a
href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=9777505836&attempt=1"
target="_blank">Cypress dashboard</a>.
> Tags: `@tag.Widget, @tag.IDE`
<!-- 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

- **New Features**
- Sidebar and tag groups now dynamically open based on widget presence.
  
- **Improvements**
  - Enhanced initial open state control for tag groups.
- Updated widget tag assignments to prioritize layout and display
widgets.

- **Bug Fixes**
- Corrected widget tag selectors to ensure accurate UI element
targeting.
  
- **Tests**
- Refactored and updated test cases for widget sidebar functionality and
UI consistency.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
  • Loading branch information
hetunandu committed Jul 4, 2024
1 parent ffc09cf commit fe0ccaa
Show file tree
Hide file tree
Showing 8 changed files with 76 additions and 45 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import {
entityExplorer,
agHelper,
locators,
draggableWidgets,
} from "../../../../support/Objects/ObjectsCore";
import { PageLeftPane } from "../../../../support/Pages/EditorNavigation";

describe(
"Entity explorer tests related to widgets and validation",
Expand All @@ -26,16 +28,14 @@ describe(
// Taken from here appsmith/app/client/src/constants/WidgetConstants.tsx
const SUGGESTED_WIDGETS_ORDER: Record<string, number> = {
TABLE_WIDGET_V2: 1,
JSON_FORM_WIDGET: 2,
INPUT_WIDGET_V2: 3,
TEXT_WIDGET: 4,
SELECT_WIDGET: 5,
LIST_WIDGET_V2: 6,
INPUT_WIDGET_V2: 2,
TEXT_WIDGET: 3,
SELECT_WIDGET: 4,
};

// When adding a new widget or tag, we need to manually add it to this list.
const WIDGETS_CATALOG: Record<string, string[]> = {
Suggested: ["Input", "JSON Form", "List", "Select", "Table", "Text"],
Suggested: ["Input", "Select", "Table", "Text"],
Inputs: [
"Currency Input",
"DatePicker",
Expand Down Expand Up @@ -86,7 +86,12 @@ describe(
);
};

it("1. All widget tags should be visible and open by default.", () => {
before(() => {
entityExplorer.DragDropWidgetNVerify(draggableWidgets.INPUT_V2);
PageLeftPane.switchToAddNew();
});

it("1. All widget tags should be visible but only Suggested tag is open.", () => {
agHelper.AssertElementLength(
entityExplorer._widgetTagsList,
Object.keys(WIDGET_TAGS).length,
Expand Down
6 changes: 3 additions & 3 deletions app/client/cypress/support/Pages/EntityExplorer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,12 @@ export class EntityExplorer {
_adsPopup = "div[role='menu']";
_entityExplorerWrapper = ".t--entity-explorer-wrapper";
_widgetTagsList =
"[data-testid='t--widget-sidebar-scrollable-wrapper'] .widget-tag-collapisble";
"[data-testid='t--widget-sidebar-scrollable-wrapper'] .widget-tag-collapsible";
_widgetCards = ".t--widget-card-draggable";
_widgetSearchInput = "#entity-explorer-search";
_widgetCardTitle = ".t--widget-card-draggable span.ads-v2-text";
_widgetTagSuggestedWidgets = ".widget-tag-collapisble-suggested";
_widgetTagBuildingBlocks = ".widget-tag-collapisble-building-blocks";
_widgetTagSuggestedWidgets = ".widget-tag-collapsible-suggested";
_widgetTagBuildingBlocks = ".widget-tag-collapsible-building-blocks";
_widgetSeeMoreButton = "[data-testid='t--explorer-ui-entity-tag-see-more']";

public ActionContextMenuByEntityName({
Expand Down
8 changes: 3 additions & 5 deletions app/client/src/constants/WidgetConstants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -256,11 +256,9 @@ export const initialEntityCountForExplorerTag: Partial<

export const SUGGESTED_WIDGETS_ORDER: Record<WidgetType, number> = {
TABLE_WIDGET_V2: 1,
JSON_FORM_WIDGET: 2,
INPUT_WIDGET_V2: 3,
TEXT_WIDGET: 4,
SELECT_WIDGET: 5,
LIST_WIDGET_V2: 6,
INPUT_WIDGET_V2: 2,
TEXT_WIDGET: 3,
SELECT_WIDGET: 4,
};

// Constant key to show walkthrough for a widget -> stores widget id
Expand Down
22 changes: 19 additions & 3 deletions app/client/src/pages/Editor/widgetSidebar/UIEntitySidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import { useFeatureFlag } from "utils/hooks/useFeatureFlag";
import { groupWidgetCardsByTags } from "../utils";
import UIEntityTagGroup from "./UIEntityTagGroup";
import { useUIExplorerItems } from "./hooks";
import { useSelector } from "react-redux";
import { widgetsExistCurrentPage } from "@appsmith/selectors/entitiesSelector";

function UIEntitySidebar({
focusSearchInput,
Expand All @@ -36,6 +38,7 @@ function UIEntitySidebar({
const isDragDropBuildingBlocksEnabled = useFeatureFlag(
FEATURE_FLAG.release_drag_drop_building_blocks_enabled,
);
const hasWidgets = useSelector(widgetsExistCurrentPage);
const hideSuggestedWidgets = useMemo(
() =>
(isSearching && !areSearchResultsEmpty) ||
Expand Down Expand Up @@ -137,9 +140,7 @@ function UIEntitySidebar({
</Text>
)}
<div>
{Object.keys(filteredCards).map((tag) => {
const cardsForThisTag = filteredCards[tag as WidgetTags];

{Object.entries(filteredCards).map(([tag, cardsForThisTag]) => {
if (!cardsForThisTag?.length && !entityLoading[tag as WidgetTags]) {
return null;
}
Expand All @@ -148,9 +149,24 @@ function UIEntitySidebar({
return null;
}

// Do not expand all the widget tags when the user does not have any
// widgets yet.
// Only show Suggested or Building Blocks
let isInitiallyOpen = false;
if (
hasWidgets ||
[
WIDGET_TAGS.SUGGESTED_WIDGETS as string,
WIDGET_TAGS.BUILDING_BLOCKS as string,
].includes(tag)
) {
isInitiallyOpen = true;
}

return (
<UIEntityTagGroup
cards={cardsForThisTag}
isInitiallyOpen={isInitiallyOpen}
isLoading={!!entityLoading[tag as WidgetTags]}
key={tag}
tag={tag}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,14 @@ const LoadingContainer = styled.div`
`;

interface Props {
isInitiallyOpen: boolean;
tag: string;
cards: WidgetCardProps[];
isLoading: boolean;
}

const UIEntityTagGroup = (props: Props) => {
const [isOpen, setIsOpen] = React.useState(props.isInitiallyOpen);
const [showFullItems, setShowFullItems] = React.useState(false);
const toggleShowFullItems = () => {
setShowFullItems(!showFullItems);
Expand Down Expand Up @@ -77,11 +79,12 @@ const UIEntityTagGroup = (props: Props) => {

return (
<Collapsible
className={`pb-2 widget-tag-collapisble widget-tag-collapisble-${props.tag
className={`pb-2 widget-tag-collapsible widget-tag-collapsible-${props.tag
.toLowerCase()
.replace(/ /g, "-")}`}
isOpen
isOpen={isOpen}
key={props.tag}
onOpenChange={setIsOpen}
>
<CollapsibleHeader arrowPosition="start">
<Text
Expand All @@ -95,6 +98,7 @@ const UIEntityTagGroup = (props: Props) => {
<CollapsibleContent>
<div
className="grid items-stretch grid-cols-3 gap-x-1 gap-y-1 justify-items-stretch"
data-collapsed={!isOpen}
data-testid="ui-entity-tag-group"
>
{props.tag === WIDGET_TAGS.SUGGESTED_WIDGETS
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,15 @@
import React from "react";
import {
UI_ELEMENT_PANEL_SEARCH_TEXT,
createMessage,
} from "@appsmith/constants/messages";
import * as Sentry from "@sentry/react";
import "@testing-library/jest-dom";
import { fireEvent, render, waitFor } from "@testing-library/react";
import { fireEvent, waitFor } from "@testing-library/react";
import { WIDGET_TAGS } from "constants/WidgetConstants";
import { unitTestBaseMockStore } from "layoutSystems/common/dropTarget/unitTestUtils";
import React from "react";
import { Provider } from "react-redux";
import configureStore from "redux-mock-store";
import { lightTheme } from "selectors/themeSelectors";
import { ThemeProvider } from "styled-components";
import UIEntitySidebar from "../UIEntitySidebar";
import { cards, groupedCards } from "./UIEntitySidebar.fixture";

const mockStore = configureStore([]);
import { render } from "test/testUtils";
import { getIDETestState } from "test/factories/AppIDEFactoryUtils";

jest.mock("utils/hooks/useFeatureFlag", () => ({
useFeatureFlag: jest.fn(),
Expand All @@ -32,16 +26,13 @@ describe("UIEntitySidebar", () => {
focusSearchInput: boolean,
) => {
return render(
<Sentry.ErrorBoundary fallback={"An error has occured"}>
<Provider store={mockStore(unitTestBaseMockStore)}>
<ThemeProvider theme={lightTheme}>
<UIEntitySidebar
focusSearchInput={focusSearchInput}
isActive={isActive}
/>
</ThemeProvider>
</Provider>
</Sentry.ErrorBoundary>,
<UIEntitySidebar
focusSearchInput={focusSearchInput}
isActive={isActive}
/>,
{
initialState: getIDETestState({}),
},
);
};

Expand Down Expand Up @@ -104,9 +95,9 @@ describe("UIEntitySidebar", () => {
// Render the UIEntitySidebar component
const { container } = renderUIEntitySidebar(true, true);

// in the mock data we have 12 tags
// in the mock data, we have 12 tags
expect(
container.getElementsByClassName("widget-tag-collapisble").length,
container.getElementsByClassName("widget-tag-collapsible").length,
).toBe(12);
});

Expand All @@ -125,7 +116,7 @@ describe("UIEntitySidebar", () => {
await waitFor(() => {
// one from building blocks and one from normal widgets
expect(
container.getElementsByClassName("widget-tag-collapisble").length,
container.getElementsByClassName("widget-tag-collapsible").length,
).toBe(2);
});
});
Expand All @@ -136,4 +127,21 @@ describe("UIEntitySidebar", () => {
const { queryByText } = renderUIEntitySidebar(true, true);
expect(queryByText(WIDGET_TAGS.SUGGESTED_WIDGETS)).toBeNull();
});

it("6. should have `Building Blocks` section open when no widgets exist", () => {
mockUIExplorerItems();
const { getAllByTestId, getByText } = renderUIEntitySidebar(true, true);
expect(getByText(WIDGET_TAGS.BUILDING_BLOCKS)).not.toBeNull();
const groups = getAllByTestId("ui-entity-tag-group");
for (const group of groups) {
if (
group.getElementsByClassName("t--widget-card-draggable-buildingblock")
.length
) {
expect(group.getAttribute("data-collapsed")).toBe("false");
} else {
expect(group.getAttribute("data-collapsed")).toBe("true");
}
}
});
});
2 changes: 1 addition & 1 deletion app/client/src/widgets/JSONFormWidget/widget/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ class JSONFormWidget extends BaseWidget<
name: "JSON Form",
iconSVG: IconSVG,
thumbnailSVG: ThumbnailSVG,
tags: [WIDGET_TAGS.SUGGESTED_WIDGETS, WIDGET_TAGS.LAYOUT],
tags: [WIDGET_TAGS.LAYOUT],
needsMeta: true,
};
}
Expand Down
2 changes: 1 addition & 1 deletion app/client/src/widgets/ListWidgetV2/widget/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ class ListWidget extends BaseWidget<
name: "List",
iconSVG: IconSVG,
thumbnailSVG: ThumbnailSVG,
tags: [WIDGET_TAGS.SUGGESTED_WIDGETS, WIDGET_TAGS.DISPLAY],
tags: [WIDGET_TAGS.DISPLAY],
needsMeta: true,
isCanvas: true,
};
Expand Down

0 comments on commit fe0ccaa

Please sign in to comment.