PromucFlow_constructor/app/client/src/pages/Editor/WidgetSidebar.tsx
Dhruvik Neharia a8faba4b86
feat: Widget Discoverability (#24934)
## Description
Grouping the widgets into categories to make it easier for people to
find widgets. This will be behind the feature flag
`release_widgetdiscovery_enabled`

<img
src="https://github.com/appsmithorg/appsmith/assets/22471214/4932a091-1831-4d95-b722-3301580fb6be"
height="300px" />

Project home [here on
Notion](https://www.notion.so/appsmith/Widget-Discoverability-755cf059a1904950888304b90b74106f?d=8bc3059134984787900a69963dd13d90#27967092cfa74505bab55bd163d28c18).

#### PR fixes following issue(s)
#24865
#24867
#24868
#24869

#### Media
> A video or a GIF is preferred. when using Loom, don’t embed because it
looks like it’s a GIF. instead, just link to the video
>
>
#### Type of change
> Please delete options that are not relevant.
- Bug fix (non-breaking change which fixes an issue)
- New feature (non-breaking change which adds functionality)
- Breaking change (fix or feature that would cause existing
functionality to not work as expected)
- Chore (housekeeping or task changes that don't impact user perception)
- This change requires a documentation update
>
>
>
## Testing
>
#### How Has This Been Tested?
> Please describe the tests that you ran to verify your changes. Also
list any relevant details for your test configuration.
> Delete anything that is not relevant
- [x] Manual
- [ ] Jest
- [x] Cypress
>
>
#### Test Plan
> (https://github.com/appsmithorg/TestSmith/issues/2440)
>
>
#### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)
>
>
>
## Checklist:
#### Dev activity
- [ ] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag


#### QA activity:
- [ ] [Speedbreak
features](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#speedbreakers-)
have been covered
- [x] Test plan covers all impacted features and [areas of
interest](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#areas-of-interest-)
- [x] Test plan has been peer reviewed by project stakeholders and other
QA members
- [x] Manually tested functionality on DP
- [ ] We had an implementation alignment call with stakeholders post QA
Round 2
- [x] Cypress test cases have been added and approved by SDET/manual QA
- [ ] Added `Test Plan Approved` label after Cypress tests were reviewed
- [ ] Added `Test Plan Approved` label after JUnit tests were reviewed
2023-07-22 11:27:18 +05:30

100 lines
2.7 KiB
TypeScript

import React, { useEffect, useMemo, useRef, useState } from "react";
import { useSelector } from "react-redux";
import WidgetCard from "./WidgetCard";
import { getWidgetCards } from "selectors/editorSelectors";
import { SearchInput } from "design-system";
import { ENTITY_EXPLORER_SEARCH_ID } from "constants/Explorer";
import { debounce } from "lodash";
import {
createMessage,
WIDGET_SIDEBAR_CAPTION,
} from "@appsmith/constants/messages";
import Fuse from "fuse.js";
import type { WidgetCardProps } from "widgets/BaseWidget";
import AnalyticsUtil from "utils/AnalyticsUtil";
function WidgetSidebar({ isActive }: { isActive: boolean }) {
const cards = useSelector(getWidgetCards);
const [filteredCards, setFilteredCards] = useState(cards);
const searchInputRef = useRef<HTMLInputElement | null>(null);
const fuse = useMemo(() => {
const options = {
keys: [
{
name: "displayName",
weight: 0.9,
},
{
name: "searchTags",
weight: 0.1,
},
],
threshold: 0.2,
distance: 100,
};
return new Fuse(cards, options);
}, [cards]);
const sendWidgetSearchAnalytics = debounce((value: string) => {
if (value !== "") {
AnalyticsUtil.logEvent("WIDGET_SEARCH", { value });
}
}, 1000);
const filterCards = (keyword: string) => {
sendWidgetSearchAnalytics(keyword);
if (keyword.trim().length > 0) {
const searchResult = fuse.search(keyword);
setFilteredCards(searchResult as WidgetCardProps[]);
} else {
setFilteredCards(cards);
}
};
useEffect(() => {
if (isActive) searchInputRef.current?.focus();
}, [isActive]);
const search = debounce((value: string) => {
filterCards(value.toLowerCase());
}, 300);
return (
<div
className={`flex flex-col overflow-hidden ${isActive ? "" : "hidden"}`}
>
<div className="sticky top-0 px-3 mt-0.5">
<SearchInput
autoComplete="off"
autoFocus
id={ENTITY_EXPLORER_SEARCH_ID}
onChange={search}
placeholder="Search widgets"
ref={searchInputRef}
type="text"
/>
</div>
<div
className="flex-grow px-3 mt-3 overflow-y-scroll"
data-testid="widget-sidebar-scrollable-wrapper"
>
<p className="px-3 py-3 text-sm leading-relaxed t--widget-sidebar">
{createMessage(WIDGET_SIDEBAR_CAPTION)}
</p>
<div className="grid items-stretch grid-cols-3 gap-3 justify-items-stretch">
{filteredCards.map((card) => (
<WidgetCard details={card} key={card.key} />
))}
</div>
</div>
</div>
);
}
WidgetSidebar.displayName = "WidgetSidebar";
export default WidgetSidebar;