@@ -69,6 +69,16 @@ export default function Toolbar({
6969 return bucketClient . onFeaturesUpdated ( updateFeatures ) ;
7070 } , [ bucketClient ] ) ;
7171
72+ const [ search , setSearch ] = useState < string | null > ( null ) ;
73+ const onSearch = ( val : string ) => {
74+ setSearch ( val === "" ? null : val ) ;
75+ } ;
76+
77+ const searchedFeatures =
78+ search === null ? features : features . filter ( ( f ) => f . key . includes ( search ) ) ;
79+
80+ const appBaseUrl = bucketClient . getConfig ( ) . appBaseUrl ;
81+
7282 return (
7383 < div id = "toolbarRoot" >
7484 < style dangerouslySetInnerHTML = { { __html : styles } } > </ style >
@@ -88,11 +98,13 @@ export default function Toolbar({
8898 } }
8999 onClose = { closeToolbar }
90100 >
101+ < FeatureSearch onSearch = { onSearch } />
91102 < FeatureTable
92- features = { features }
103+ features = { searchedFeatures }
93104 setEnabledOverride = { bucketClient . setFeatureOverride . bind (
94105 bucketClient ,
95106 ) }
107+ appBaseUrl = { appBaseUrl }
96108 />
97109 </ Dialog >
98110 </ div >
@@ -130,6 +142,18 @@ function ToolbarToggle({
130142 ) ;
131143}
132144
145+ function FeatureSearch ( { onSearch } : { onSearch : ( val : string ) => void } ) {
146+ return (
147+ < input
148+ type = "search"
149+ placeholder = "Search"
150+ onInput = { ( s ) => onSearch ( s . currentTarget . value ) }
151+ autoFocus
152+ class = "search-input"
153+ />
154+ ) ;
155+ }
156+
133157function Reset ( {
134158 setEnabledOverride,
135159 featureKey,
@@ -154,49 +178,53 @@ function Reset({
154178function FeatureTable ( {
155179 features,
156180 setEnabledOverride,
181+ appBaseUrl,
157182} : {
158183 features : {
159184 key : string ;
160185 localOverride : boolean | null ;
161186 isEnabled : boolean ;
162187 } [ ] ;
163188 setEnabledOverride : ( key : string , value : boolean | null ) => void ;
189+ appBaseUrl : string ;
164190} ) {
191+ if ( features . length === 0 ) {
192+ return < div style = { { color : "var(--gray500)" } } > No features found</ div > ;
193+ }
165194 return (
166195 < table class = "table" >
167196 < tbody >
168- { features . map ( ( feat ) => {
197+ { features . map ( ( feature ) => {
169198 return (
170- < tr key = { feat ! . key } >
171- < td
172- style = { {
173- whiteSpace : "nowrap" ,
174- overflow : "hidden" ,
175- textOverflow : "ellipsis" ,
176- width : "auto" ,
177- } }
178- >
179- { feat ! . key }
199+ < tr key = { feature . key } >
200+ < td class = "feature-name-cell" >
201+ < a
202+ href = { `${ appBaseUrl } /envs/current/features/by-key/${ feature . key } ` }
203+ target = "_blank"
204+ class = "feature-link"
205+ >
206+ { feature . key }
207+ </ a >
180208 </ td >
181- < td style = { { minWidth : "38px" } } >
182- { feat ? .localOverride !== null ? (
209+ < td class = "feature-reset-cell" >
210+ { feature . localOverride !== null ? (
183211 < Reset
184212 setEnabledOverride = { setEnabledOverride }
185- featureKey = { feat ! . key }
213+ featureKey = { feature . key }
186214 />
187215 ) : null }
188216 </ td >
189217 < td >
190218 < Switch
191219 isOn = {
192- ( feat ? .localOverride === null && feat ! . isEnabled ) ||
193- feat ? .localOverride === true
220+ ( feature . localOverride === null && feature . isEnabled ) ||
221+ feature . localOverride === true
194222 }
195223 onChange = { ( e ) => {
196224 const isChecked = e . currentTarget . checked ;
197- const isOverridden = isChecked !== feat ! . isEnabled ;
225+ const isOverridden = isChecked !== feature . isEnabled ;
198226 setEnabledOverride (
199- feat ! . key ,
227+ feature . key ,
200228 isOverridden ? isChecked : null ,
201229 ) ;
202230 } }
0 commit comments