diff --git a/static/app/components/devtoolbar/components/featureFlags/customOverride.tsx b/static/app/components/devtoolbar/components/featureFlags/customOverride.tsx index c8680ca6bd76c6..6b60507f2efa2e 100644 --- a/static/app/components/devtoolbar/components/featureFlags/customOverride.tsx +++ b/static/app/components/devtoolbar/components/featureFlags/customOverride.tsx @@ -3,13 +3,18 @@ import {useContext, useState} from 'react'; import {Button} from 'sentry/components/button'; import Input from 'sentry/components/input'; import Switch from 'sentry/components/switchButton'; +import {IconAdd} from 'sentry/icons'; import useConfiguration from '../../hooks/useConfiguration'; import {AnalyticsContext} from '../analyticsProvider'; import {useFeatureFlagsContext} from './featureFlagsContext'; -export default function CustomOverride() { +export default function CustomOverride({ + setComponentActive, +}: { + setComponentActive: (value: boolean) => void; +}) { const {eventName, eventKey} = useContext(AnalyticsContext); const {trackAnalytics} = useConfiguration(); const {setOverride} = useFeatureFlagsContext(); @@ -22,7 +27,7 @@ export default function CustomOverride() { css={[ { display: 'grid', - gridTemplateColumns: 'auto max-content auto', + gridTemplateColumns: 'auto max-content max-content', alignItems: 'center', justifyItems: 'space-between', gap: 'var(--space100)', @@ -31,6 +36,7 @@ export default function CustomOverride() { onSubmit={e => { e.preventDefault(); setOverride(name, isActive); + setComponentActive(false); setName(''); setIsActive(false); trackAnalytics?.({ @@ -46,13 +52,15 @@ export default function CustomOverride() { onChange={e => setName(e.target.value.toLowerCase())} /> { setIsActive(!isActive); }} + css={{background: 'white'}} /> - ); diff --git a/static/app/components/devtoolbar/components/featureFlags/featureFlagItem.tsx b/static/app/components/devtoolbar/components/featureFlags/featureFlagItem.tsx index f1617c6e42d3b6..cec42232399052 100644 --- a/static/app/components/devtoolbar/components/featureFlags/featureFlagItem.tsx +++ b/static/app/components/devtoolbar/components/featureFlags/featureFlagItem.tsx @@ -9,7 +9,7 @@ import Switch from 'sentry/components/switchButton'; import useConfiguration from '../../hooks/useConfiguration'; import {inlineLinkCss} from '../../styles/link'; -import {panelInsetContentCss} from '../../styles/panel'; +import {verticalPaddingCss} from '../../styles/panel'; import {smallCss} from '../../styles/typography'; import type {FlagValue} from '../../types'; @@ -23,7 +23,12 @@ export default function FeatureFlagItem({flag}: {flag: FeatureFlag}) { return ( - + {featureFlags?.urlTemplate?.(flag.name) ? ( {flag.name} )} - + diff --git a/static/app/components/devtoolbar/components/featureFlags/featureFlagsPanel.tsx b/static/app/components/devtoolbar/components/featureFlags/featureFlagsPanel.tsx index 867d66426ec27d..abdd671c952c2a 100644 --- a/static/app/components/devtoolbar/components/featureFlags/featureFlagsPanel.tsx +++ b/static/app/components/devtoolbar/components/featureFlags/featureFlagsPanel.tsx @@ -1,11 +1,19 @@ import {type Dispatch, Fragment, type SetStateAction, useState} from 'react'; import {Button} from 'sentry/components/button'; +import {resetButtonCss, resetFlexRowCss} from 'sentry/components/devtoolbar/styles/reset'; import Input from 'sentry/components/input'; import {PanelTable} from 'sentry/components/panels/panelTable'; import {SegmentedControl} from 'sentry/components/segmentedControl'; +import {IconChevron, IconClose} from 'sentry/icons'; -import {panelInsetContentCss, panelSectionCss} from '../../styles/panel'; +import { + buttonRightCss, + panelHeadingRightCss, + panelInsetContentCss, + panelSectionCss, + panelSectionCssNoBorder, +} from '../../styles/panel'; import {smallCss} from '../../styles/typography'; import AnalyticsProvider from '../analyticsProvider'; import PanelLayout from '../panelLayout'; @@ -19,20 +27,54 @@ type Prefilter = 'all' | 'overrides'; export default function FeatureFlagsPanel() { const [prefilter, setPrefilter] = useState('all'); const [searchTerm, setSearchTerm] = useState(''); + const [isAddFlagActive, setIsAddFlagActive] = useState(false); return ( - + setIsAddFlagActive(!isAddFlagActive)} + > + + {isAddFlagActive ? ( + + ) : ( + + )} + Add Flag + + + } + > + {isAddFlagActive && ( +
+ + + +
+ )}
-
- - - -
@@ -67,7 +104,9 @@ function IsDirtyMessage() { const {isDirty} = useFeatureFlagsContext(); return isDirty ? ( -
+
Reload to see changes
) : ( @@ -84,36 +123,26 @@ function Filters({ setPrefilter: Dispatch>; setSearchTerm: Dispatch>; }) { - const {clearOverrides} = useFeatureFlagsContext(); return (
onChange={setPrefilter} size="xs" value={prefilter}> - All Flags - Overrides Only + All + Overrides
- setSearchTerm(e.target.value.toLowerCase())} - placeholder="Search flags" + placeholder="Search" size="xs" />
); } -function FlagTable({prefilter, searchTerm}: {prefilter: string; searchTerm: string}) { - const {featureFlagMap} = useFeatureFlagsContext(); +function FlagTable({prefilter, searchTerm}: {prefilter: Prefilter; searchTerm: string}) { + const {featureFlagMap, clearOverrides} = useFeatureFlagsContext(); const filtered = Object.fromEntries( Object.entries(featureFlagMap)?.filter(([name, {value, override}]) => { @@ -128,32 +157,74 @@ function FlagTable({prefilter, searchTerm}: {prefilter: string; searchTerm: stri const names = Object.keys(filtered).sort(); return ( - :first-child': { - minHeight: 'unset', - padding: 'var(--space50) var(--space150)', + + :first-child': { + minHeight: 'unset', + }, }, - }, - ]} - headers={[ - Name, - Value, - ]} - stickyHeaders - > - {names?.map(name => ( - - - - ))} - + ]} + headers={[undefined, undefined]} + stickyHeaders + > + {names?.map(name => ( + + + + ))} + + {!names.length && ( +
+ No flags to display +
+ )} + {prefilter === 'overrides' && Boolean(names.length) && ( +
+ +
+ )} + ); } diff --git a/static/app/components/devtoolbar/components/feedback/feedbackPanel.tsx b/static/app/components/devtoolbar/components/feedback/feedbackPanel.tsx index 306b2e063b1bb4..1d63ee76ebc552 100644 --- a/static/app/components/devtoolbar/components/feedback/feedbackPanel.tsx +++ b/static/app/components/devtoolbar/components/feedback/feedbackPanel.tsx @@ -21,6 +21,7 @@ import { listItemPlaceholderWrapperCss, } from '../../styles/listItem'; import { + buttonRightCss, panelDescCss, panelHeadingRightCss, panelInsetContentCss, @@ -68,15 +69,7 @@ export default function FeedbackPanel() { ref={buttonRef} title="Submit Feedback" > - + Report Bug diff --git a/static/app/components/devtoolbar/styles/global.ts b/static/app/components/devtoolbar/styles/global.ts index 681a5e519f4793..b353d003b1fd7f 100644 --- a/static/app/components/devtoolbar/styles/global.ts +++ b/static/app/components/devtoolbar/styles/global.ts @@ -54,6 +54,8 @@ export const globalCss = css` --pink200: rgba(249, 26, 138, 0.5); --pink100: rgba(249, 26, 138, 0.09); + --surface200: #faf9fb; + --z-index: 100000; color: var(--gray400); diff --git a/static/app/components/devtoolbar/styles/panel.ts b/static/app/components/devtoolbar/styles/panel.ts index d8c18d5670a9d4..a1ba937291349f 100644 --- a/static/app/components/devtoolbar/styles/panel.ts +++ b/static/app/components/devtoolbar/styles/panel.ts @@ -35,10 +35,19 @@ export const panelSectionCss = css` } `; +export const panelSectionCssNoBorder = css` + position: relative; + padding-block: var(--space150); +`; + export const panelInsetContentCss = css` padding-inline: var(--space150); `; +export const verticalPaddingCss = css` + padding: var(--space150) 0; +`; + export const panelDescCss = css` color: var(--gray300); font-weight: bold; @@ -46,3 +55,11 @@ export const panelDescCss = css` text-align: left; padding-top: var(--space200); `; + +export const buttonRightCss = css` + display: flex; + gap: var(--space75); + align-items: center; + color: var(--purple300); + font-weight: bold; +`; diff --git a/static/app/components/panels/panelTable.tsx b/static/app/components/panels/panelTable.tsx index 649ad24bc5e808..f9b582fc73c4b8 100644 --- a/static/app/components/panels/panelTable.tsx +++ b/static/app/components/panels/panelTable.tsx @@ -24,6 +24,12 @@ type PanelTableProps = { * If true, disables the border-bottom on the header */ disableHeaderBorderBottom?: boolean; + /** + * If true, disables the headers. + * Pass in headers as an array of `undefined` so that the + * columns still display appropriately. + */ + disableHeaders?: boolean; /** * Renders without predefined padding on the header and body cells */ @@ -82,6 +88,7 @@ const PanelTable = forwardRef(function PanelTab loader, stickyHeaders = false, disableHeaderBorderBottom = false, + disableHeaders, ...props }: PanelTableProps, ref: React.Ref @@ -100,11 +107,12 @@ const PanelTable = forwardRef(function PanelTab disableHeaderBorderBottom={disableHeaderBorderBottom} {...props} > - {headers.map((header, i) => ( - - {header} - - ))} + {!disableHeaders && + headers.map((header, i) => ( + + {header} + + ))} {shouldShowLoading && ( {loader || }