From 837a8eb1e423fbec080a84df14f6d30e433a035c Mon Sep 17 00:00:00 2001 From: olehp Date: Thu, 22 Aug 2024 15:34:02 +0300 Subject: [PATCH 01/11] fix styles of Issues filters --- .../Insights/Issues/IssuesFilter/index.tsx | 9 ++++----- .../Insights/Issues/IssuesFilter/styles.ts | 15 +++++++++++---- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/components/Insights/Issues/IssuesFilter/index.tsx b/src/components/Insights/Issues/IssuesFilter/index.tsx index a94992659..d1e0dee1a 100644 --- a/src/components/Insights/Issues/IssuesFilter/index.tsx +++ b/src/components/Insights/Issues/IssuesFilter/index.tsx @@ -14,7 +14,6 @@ import { WrenchIcon } from "../../../common/icons/12px/WrenchIcon"; import { CrossIcon } from "../../../common/icons/16px/CrossIcon"; import { WarningTriangleIcon } from "../../../common/icons/WarningTriangleIcon"; import { IconProps } from "../../../common/icons/types"; -import { Select } from "../../../common/v3/Select"; import { SelectItem } from "../../../common/v3/Select/types"; import { InsightFilterType } from "../../InsightsCatalog/types"; import { useIssuesFilters } from "../useIssuesFilters"; @@ -202,7 +201,7 @@ export const IssuesFilter = () => { {isServicesFilterEnabled && ( <> Services - { disabled={issueTypesFilterOptions?.length === 0} /> Criticality - handleToggleFilterChange(value, "unread")} diff --git a/src/components/Insights/Issues/IssuesFilter/styles.ts b/src/components/Insights/Issues/IssuesFilter/styles.ts index ef86706eb..7be21cef5 100644 --- a/src/components/Insights/Issues/IssuesFilter/styles.ts +++ b/src/components/Insights/Issues/IssuesFilter/styles.ts @@ -5,14 +5,15 @@ import { } from "../../../common/App/typographies"; import { grayScale } from "../../../common/App/v2colors"; import { NewButton } from "../../../common/v3/NewButton"; +import { Select } from "../../../common/v3/Select"; export const Container = styled.div` display: flex; flex-direction: column; gap: 8px; padding: 8px; - border-radius: 4px; - background: ${({ theme }) => theme.colors.surface.primary}; + border-radius: 8px; + background: ${({ theme }) => theme.colors.surface.brandDark}; box-shadow: 0 2px 4px 0 rgb(0 0 0 / 29%); font-size: 14px; color: ${grayScale[400]}; @@ -29,7 +30,7 @@ export const Header = styled.div` export const FilterCategoryName = styled.div` display: flex; - padding: 4px; + padding-top: 4px; color: ${({ theme }) => theme.colors.v3.text.tertiary}; ${subscriptRegularTypography} `; @@ -50,7 +51,8 @@ export const MenuButtonChevronIconContainer = styled.span` `; export const Footer = styled.div` - padding: 8px 0; + padding-top: 12px; + padding-bottom: 8px; display: flex; justify-content: space-between; align-items: center; @@ -84,4 +86,9 @@ export const CloseButton = styled.button` border: none; height: 14px; color: inherit; + color: ${({ theme }) => theme.colors.v3.icon.tertiary}; +`; + +export const StyledSelect = styled(Select)` + background: ${({ theme }) => theme.colors.surface.brandDark}; `; From 5dc0e391235f216235f18586d74511dd5834d575 Mon Sep 17 00:00:00 2001 From: olehp Date: Thu, 22 Aug 2024 15:34:29 +0300 Subject: [PATCH 02/11] Add helper command --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index e27587cf8..1c8de6fa2 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,8 @@ "build:prod": "webpack --config webpack.prod.ts", "build:prod:web": "webpack --config webpack.prod.ts --env platform=Web", "precommit": "lint-staged", - "prepare": "husky" + "prepare": "husky", + "start": "storybook dev -p 6006" }, "lint-staged": { "*.{js,ts,tsx}": [ From b34b43e26eab6dc0c0d7631a34f05a3511c4de81 Mon Sep 17 00:00:00 2001 From: olehp Date: Thu, 22 Aug 2024 16:43:17 +0300 Subject: [PATCH 03/11] Extracted common filter popup --- src/components/Assets/AssetsFilter/index.tsx | 2 +- .../Insights/Issues/IssuesFilter/index.tsx | 180 ++++++++---------- .../Insights/Issues/IssuesFilter/styles.ts | 68 ------- src/components/common/App/themes/darkTheme.ts | 1 + .../common/App/themes/lightTheme.ts | 3 +- src/components/common/App/v2colors.ts | 4 +- .../FilterPopup/FilterPopup.stories.tsx | 20 ++ src/components/common/FilterPopup/index.tsx | 62 ++++++ src/components/common/FilterPopup/styles.ts | 78 ++++++++ src/components/common/FilterPopup/types.ts | 12 ++ src/styled.d.ts | 1 + 11 files changed, 264 insertions(+), 167 deletions(-) create mode 100644 src/components/common/FilterPopup/FilterPopup.stories.tsx create mode 100644 src/components/common/FilterPopup/index.tsx create mode 100644 src/components/common/FilterPopup/styles.ts create mode 100644 src/components/common/FilterPopup/types.ts diff --git a/src/components/Assets/AssetsFilter/index.tsx b/src/components/Assets/AssetsFilter/index.tsx index 07fb9c1f4..9d07399e2 100644 --- a/src/components/Assets/AssetsFilter/index.tsx +++ b/src/components/Assets/AssetsFilter/index.tsx @@ -53,7 +53,7 @@ const getData = ({ insights, directOnly: Boolean(assetScopeOption?.isDirect), scopedSpanCodeObjectId: assetScopeOption?.scopedSpanCodeObjectId, - ...(searchQuery.length > 0 ? { displayName: searchQuery } : {}) + ...(searchQuery?.length > 0 ? { displayName: searchQuery } : {}) } } }); diff --git a/src/components/Insights/Issues/IssuesFilter/index.tsx b/src/components/Insights/Issues/IssuesFilter/index.tsx index d1e0dee1a..ea4fa7190 100644 --- a/src/components/Insights/Issues/IssuesFilter/index.tsx +++ b/src/components/Insights/Issues/IssuesFilter/index.tsx @@ -1,4 +1,4 @@ -import { useEffect, useMemo, useState } from "react"; +import { useEffect, useMemo } from "react"; import { useGlobalStore } from "../../../../containers/Main/stores/useGlobalStore"; import { useInsightsStore } from "../../../../containers/Main/stores/useInsightsStore"; import { getFeatureFlagValue } from "../../../../featureFlags"; @@ -6,12 +6,10 @@ import { usePrevious } from "../../../../hooks/usePrevious"; import { FeatureFlag } from "../../../../types"; import { sendUserActionTrackingEvent } from "../../../../utils/actions/sendUserActionTrackingEvent"; import { getInsightTypeInfo } from "../../../../utils/getInsightTypeInfo"; -import { FilterButton } from "../../../common/FilterButton"; -import { NewPopover } from "../../../common/NewPopover"; +import { FilterPopup } from "../../../common/FilterPopup"; import { EyeIcon } from "../../../common/icons/12px/EyeIcon"; import { FourPointedStarIcon } from "../../../common/icons/12px/FourPointedStarIcon"; import { WrenchIcon } from "../../../common/icons/12px/WrenchIcon"; -import { CrossIcon } from "../../../common/icons/16px/CrossIcon"; import { WarningTriangleIcon } from "../../../common/icons/WarningTriangleIcon"; import { IconProps } from "../../../common/icons/types"; import { SelectItem } from "../../../common/v3/Select/types"; @@ -21,7 +19,6 @@ import * as s from "./styles"; import { trackingEvents } from "./tracking"; export const IssuesFilter = () => { - const [isOpen, setIsOpen] = useState(false); const filteredInsightTypes = useInsightsStore.use.filteredInsightTypes(); const selectedServices = useGlobalStore.use.selectedServices(); const setFilteredInsightTypes = @@ -111,7 +108,6 @@ export const IssuesFilter = () => { const handleCloseButtonClick = () => { sendUserActionTrackingEvent(trackingEvents.CLOSE_FILTER_DIALOG_CLICKED); - setIsOpen(false); }; const handleToggleFilterChange = ( @@ -187,97 +183,89 @@ export const IssuesFilter = () => { (isCriticalOnly ? 1 : 0) + (isUnreadOnly ? 1 : 0); - return ( - - - Filters - - - - - {isServicesFilterEnabled && ( - <> - Services - 0 ? "Services" : "All"} - multiselect={true} - icon={(props: IconProps) => ( - - - - )} - disabled={issueTypesFilterOptions?.length === 0} - /> - + const filterComponents = [ + { + title: "Issues", + component: ( + 0 ? "Issues" : "All"} + multiselect={true} + icon={(props: IconProps) => ( + + + )} - Issues - 0 ? "Issues" : "All"} - multiselect={true} - icon={(props: IconProps) => ( - - - - )} - disabled={issueTypesFilterOptions?.length === 0} - /> - Criticality - handleToggleFilterChange(value, "criticality")} - placeholder={criticalityFilterPlaceholder} - icon={(props: IconProps) => ( - - - - )} - showSelectedState={isCriticalOnly} - /> - Read/Unread - handleToggleFilterChange(value, "unread")} - placeholder={readStatusFilterPlaceholder} - icon={(props: IconProps) => ( - - - - )} - showSelectedState={isUnreadOnly} - /> - - - - - } - onOpenChange={setIsOpen} - isOpen={isOpen} - placement={"bottom-end"} - > -
- + ) + }, + { + title: "Criticality", + component: ( + handleToggleFilterChange(value, "criticality")} + placeholder={criticalityFilterPlaceholder} + icon={(props: IconProps) => ( + + + + )} + showSelectedState={isCriticalOnly} /> -
-
+ ) + }, + { + title: "Read/Unread", + component: ( + handleToggleFilterChange(value, "unread")} + placeholder={readStatusFilterPlaceholder} + icon={(props: IconProps) => ( + + + + )} + showSelectedState={isUnreadOnly} + /> + ) + } + ]; + + if (isServicesFilterEnabled) { + filterComponents.unshift({ + title: "Services", + component: ( + 0 ? "Services" : "All"} + multiselect={true} + icon={(props: IconProps) => ( + + + + )} + disabled={issueTypesFilterOptions?.length === 0} + /> + ) + }); + } + + return ( + ); }; diff --git a/src/components/Insights/Issues/IssuesFilter/styles.ts b/src/components/Insights/Issues/IssuesFilter/styles.ts index 7be21cef5..f1646ff6c 100644 --- a/src/components/Insights/Issues/IssuesFilter/styles.ts +++ b/src/components/Insights/Issues/IssuesFilter/styles.ts @@ -1,40 +1,6 @@ import styled from "styled-components"; -import { - bodyBoldTypography, - subscriptRegularTypography -} from "../../../common/App/typographies"; -import { grayScale } from "../../../common/App/v2colors"; -import { NewButton } from "../../../common/v3/NewButton"; import { Select } from "../../../common/v3/Select"; -export const Container = styled.div` - display: flex; - flex-direction: column; - gap: 8px; - padding: 8px; - border-radius: 8px; - background: ${({ theme }) => theme.colors.surface.brandDark}; - box-shadow: 0 2px 4px 0 rgb(0 0 0 / 29%); - font-size: 14px; - color: ${grayScale[400]}; -`; - -export const Header = styled.div` - color: ${({ theme }) => theme.colors.v3.text.primary}; - padding: 0 4px; - display: flex; - align-items: center; - justify-content: space-between; - ${bodyBoldTypography} -`; - -export const FilterCategoryName = styled.div` - display: flex; - padding-top: 4px; - color: ${({ theme }) => theme.colors.v3.text.tertiary}; - ${subscriptRegularTypography} -`; - export const MenuButton = styled.button` border: 1px solid ${({ theme }) => theme.colors.stroke.primary}; background: ${({ theme }) => theme.colors.surface.secondary}; @@ -50,45 +16,11 @@ export const MenuButtonChevronIconContainer = styled.span` color: ${({ theme }) => theme.colors.icon.primary}; `; -export const Footer = styled.div` - padding-top: 12px; - padding-bottom: 8px; - display: flex; - justify-content: space-between; - align-items: center; -`; - -export const ClearAllButton = styled(NewButton)` - padding: 0; - - span { - color: ${({ theme }) => theme.colors.v3.status.high}; - } - - &:hover:enabled { - color: ${({ theme }) => theme.colors.v3.status.high}; - - span { - color: ${({ theme }) => theme.colors.v3.status.high}; - } - } -`; - export const InsightIconContainer = styled.div` display: flex; color: ${({ theme }) => theme.colors.v3.icon.tertiary}; `; -export const CloseButton = styled.button` - padding: 0; - cursor: pointer; - background: none; - border: none; - height: 14px; - color: inherit; - color: ${({ theme }) => theme.colors.v3.icon.tertiary}; -`; - export const StyledSelect = styled(Select)` background: ${({ theme }) => theme.colors.surface.brandDark}; `; diff --git a/src/components/common/App/themes/darkTheme.ts b/src/components/common/App/themes/darkTheme.ts index bc42e90f3..ce62c7e1d 100644 --- a/src/components/common/App/themes/darkTheme.ts +++ b/src/components/common/App/themes/darkTheme.ts @@ -217,6 +217,7 @@ export const darkTheme: ThemeColors = { card: grayScale[1100], brand: primaryScale[300], brandDark: primaryScale[700], + brandDarkest: primaryScale[800], secondary: grayScale[1100] }, stroke: { diff --git a/src/components/common/App/themes/lightTheme.ts b/src/components/common/App/themes/lightTheme.ts index 1c4bd8d19..a5fd900d8 100644 --- a/src/components/common/App/themes/lightTheme.ts +++ b/src/components/common/App/themes/lightTheme.ts @@ -215,7 +215,8 @@ export const lightTheme: ThemeColors = { card: grayScale[0], brand: primaryScale[300], brandDark: grayScale[50], - secondary: grayScale[50] + secondary: grayScale[50], + brandDarkest: grayScale[75] }, stroke: { primary: grayScale[300], diff --git a/src/components/common/App/v2colors.ts b/src/components/common/App/v2colors.ts index 92c1a78a0..ad942d635 100644 --- a/src/components/common/App/v2colors.ts +++ b/src/components/common/App/v2colors.ts @@ -1,6 +1,7 @@ export const grayScale = { 0: "#fff", 50: "#f7f8fc", + 75: "#f0f0ff", 100: "#f0f1f7", 150: "#e6e8f2", 200: "#d3d6e5", @@ -25,7 +26,8 @@ export const primaryScale = { 400: "#393cea", 500: "#2628a6", 600: "#22235e", - 700: "#28293e" + 700: "#28293e", + 800: "#242433" }; export const blueScale = { diff --git a/src/components/common/FilterPopup/FilterPopup.stories.tsx b/src/components/common/FilterPopup/FilterPopup.stories.tsx new file mode 100644 index 000000000..39a6f7e4d --- /dev/null +++ b/src/components/common/FilterPopup/FilterPopup.stories.tsx @@ -0,0 +1,20 @@ +import { Meta, StoryObj } from "@storybook/react"; + +import { FilterPopup } from "."; + +// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction +const meta: Meta = { + title: "common/FilterPopup", + component: FilterPopup, + parameters: { + // More on how to position stories at: https://storybook.js.org/docs/react/configure/story-layout + layout: "fullscreen" + } +}; + +export default meta; + +type Story = StoryObj; + +// More on writing stories with args: https://storybook.js.org/docs/react/writing-stories/args +export const Default: Story = {}; diff --git a/src/components/common/FilterPopup/index.tsx b/src/components/common/FilterPopup/index.tsx new file mode 100644 index 000000000..d896d1564 --- /dev/null +++ b/src/components/common/FilterPopup/index.tsx @@ -0,0 +1,62 @@ +import { useState } from "react"; +import { FilterButton } from "../FilterButton"; +import { CrossIcon } from "../icons/16px/CrossIcon"; +import { NewPopover } from "../NewPopover"; +import * as s from "./styles"; +import { FilterPopupProps } from "./types"; + +export const FilterPopup = ({ + onClearAll, + onClose, + title, + selectedFiltersCount, + filters +}: FilterPopupProps) => { + const [isOpen, setIsOpen] = useState(false); + const handleCloseButtonClick = () => { + setIsOpen(false); + onClose(); + }; + return ( + + + {title} + + + + + + {filters.map((x) => ( + + {x.title} + {x.component} + + ))} + + + + + } + onOpenChange={setIsOpen} + isOpen={isOpen} + placement={"bottom-end"} + > +
+ +
+
+ ); +}; diff --git a/src/components/common/FilterPopup/styles.ts b/src/components/common/FilterPopup/styles.ts new file mode 100644 index 000000000..502ba82ad --- /dev/null +++ b/src/components/common/FilterPopup/styles.ts @@ -0,0 +1,78 @@ +import styled from "styled-components"; +import { + bodyBoldTypography, + subscriptRegularTypography +} from "../App/typographies"; +import { NewButton } from "../v3/NewButton"; + +export const Container = styled.div` + display: flex; + flex-direction: column; + gap: 12px; + padding: 8px; + border-radius: 8px; + background: ${({ theme }) => theme.colors.surface.brandDarkest}; + box-shadow: 0 2px 4px 0 rgb(0 0 0 / 29%); + font-size: 14px; + color: ${({ theme }) => theme.colors.v3.text.tertiary}; +`; + +export const Header = styled.div` + color: ${({ theme }) => theme.colors.v3.text.primary}; + display: flex; + align-items: center; + justify-content: space-between; + ${bodyBoldTypography} +`; + +export const Footer = styled.div` + padding: 8px 0; + display: flex; + justify-content: space-between; + align-items: center; +`; + +export const ClearAllButton = styled(NewButton)` + padding: 0; + + span { + color: ${({ theme }) => theme.colors.v3.status.high}; + } + + &:hover:enabled { + color: ${({ theme }) => theme.colors.v3.status.high}; + + span { + color: ${({ theme }) => theme.colors.v3.status.high}; + } + } +`; + +export const CloseButton = styled.button` + padding: 0; + cursor: pointer; + background: none; + border: none; + height: 14px; + color: inherit; + color: ${({ theme }) => theme.colors.v3.icon.tertiary}; +`; + +export const Filter = styled.div` + display: flex; + flex-direction: column; + gap: 8px; + color: ${({ theme }) => theme.colors.v3.text.secondary}; + + button { + span { + color: ${({ theme }) => theme.colors.v3.text.secondary}; + } + } +`; + +export const FilterCategoryName = styled.div` + display: flex; + color: ${({ theme }) => theme.colors.v3.text.tertiary}; + ${subscriptRegularTypography} +`; diff --git a/src/components/common/FilterPopup/types.ts b/src/components/common/FilterPopup/types.ts new file mode 100644 index 000000000..beb3336fa --- /dev/null +++ b/src/components/common/FilterPopup/types.ts @@ -0,0 +1,12 @@ +import { ReactNode } from "react"; + +export interface FilterPopupProps { + onClose: () => void; + title: string; + onClearAll: () => void; + selectedFiltersCount: number; + filters: { + title: string; + component: ReactNode; + }[]; +} diff --git a/src/styled.d.ts b/src/styled.d.ts index d428eaf2f..8abf0617a 100644 --- a/src/styled.d.ts +++ b/src/styled.d.ts @@ -54,6 +54,7 @@ export interface ThemeColors { card: string; brand: string; brandDark: string; + brandDarkest: string; secondary: string; }; stroke: { From f8cf7246a8a2309c29f6e9cfda0831a2711495bb Mon Sep 17 00:00:00 2001 From: olehp Date: Thu, 22 Aug 2024 17:36:05 +0300 Subject: [PATCH 04/11] refactored assets filters --- .vscode/settings.json | 1 + src/components/Assets/AssetsFilter/index.tsx | 119 ++++++++++--------- src/components/Assets/AssetsFilter/styles.ts | 5 + src/components/Assets/tracking.ts | 3 +- src/components/common/FilterPopup/index.tsx | 14 ++- src/components/common/FilterPopup/types.ts | 1 + 6 files changed, 81 insertions(+), 62 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 5386dcb55..e93c83905 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -11,6 +11,7 @@ "digma", "digmathon", "digmo", + "Hotspot", "leaderboard", "undismiss", "zustand" diff --git a/src/components/Assets/AssetsFilter/index.tsx b/src/components/Assets/AssetsFilter/index.tsx index 9d07399e2..683b2108d 100644 --- a/src/components/Assets/AssetsFilter/index.tsx +++ b/src/components/Assets/AssetsFilter/index.tsx @@ -8,11 +8,9 @@ import { isNull } from "../../../typeGuards/isNull"; import { isUndefined } from "../../../typeGuards/isUndefined"; import { InsightType } from "../../../types"; import { sendTrackingEvent } from "../../../utils/actions/sendTrackingEvent"; +import { sendUserActionTrackingEvent } from "../../../utils/actions/sendUserActionTrackingEvent"; import { getInsightTypeInfo } from "../../../utils/getInsightTypeInfo"; -import { FilterButton } from "../../common/FilterButton"; -import { NewButton } from "../../common/NewButton"; -import { NewPopover } from "../../common/NewPopover"; -import { Select } from "../../common/Select"; +import { FilterPopup } from "../../common/FilterPopup"; import { WrenchIcon } from "../../common/icons/12px/WrenchIcon"; import { EndpointIcon } from "../../common/icons/EndpointIcon"; import { SparkleIcon } from "../../common/icons/SparkleIcon"; @@ -20,7 +18,6 @@ import { IconProps } from "../../common/icons/types"; import { AssetScopeOption } from "../AssetsViewScopeConfiguration/types"; import { actions } from "../actions"; import { trackingEvents } from "../tracking"; -import * as s from "./styles"; import { AssetFilterCategory, AssetFilterQuery, @@ -29,6 +26,8 @@ import { GetAssetFiltersDataPayload } from "./types"; +import * as s from "./styles"; + const PERSISTENCE_KEY = "assetsFilters"; const getData = ({ @@ -76,8 +75,7 @@ const renderFilterCategory = ( })) ?? []; return ( -