Skip to content

Commit 798187f

Browse files
committed
refactor: extract empty state and metrics components from FeaturesPage
- Create FeaturesEmptyState.tsx component (109 lines) - Create FeatureMetricsSection.tsx component (30 lines) - Reduce FeaturesPage.js by ~110 lines - Move feature flag check into component (better encapsulation) - Preserve all E2E test selectors - Zero visual changes Part of incremental FeaturesPage TypeScript migration (PR #1/6)
1 parent c08d4de commit 798187f

File tree

4 files changed

+156
-115
lines changed

4 files changed

+156
-115
lines changed

frontend/web/components/pages/FeaturesPage.js

Lines changed: 15 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ import JSONReference from 'components/JSONReference'
99
import ConfigProvider from 'common/providers/ConfigProvider'
1010
import Constants from 'common/constants'
1111
import PageTitle from 'components/PageTitle'
12-
import { rocket } from 'ionicons/icons'
13-
import { IonIcon } from '@ionic/react'
1412
import TableSortFilter from 'components/tables/TableSortFilter'
1513
import TableSearchFilter from 'components/tables/TableSearchFilter'
1614
import TableTagFilter from 'components/tables/TableTagFilter'
@@ -25,9 +23,9 @@ import classNames from 'classnames'
2523
import ClearFilters from 'components/ClearFilters'
2624
import Button from 'components/base/forms/Button'
2725
import { isEqual } from 'lodash'
28-
import EnvironmentMetricsList from 'components/metrics/EnvironmentMetricsList'
2926
import { withRouter } from 'react-router-dom'
3027
import { useRouteContext } from 'components/providers/RouteContext'
28+
import { FeaturesEmptyState, FeatureMetricsSection } from './features'
3129

3230
const FeaturesPage = class extends Component {
3331
static displayName = 'FeaturesPage'
@@ -227,9 +225,6 @@ const FeaturesPage = class extends Component {
227225
render() {
228226
const { environmentId, projectId } = this.props.match.params
229227
const readOnly = Utils.getFlagsmithHasFeature('read_only_mode')
230-
const environmentMetricsEnabled = Utils.getFlagsmithHasFeature(
231-
'environment_metrics',
232-
)
233228

234229
const environment = ProjectStore.getEnvironment(environmentId)
235230
const params = Utils.fromParam()
@@ -313,13 +308,11 @@ const FeaturesPage = class extends Component {
313308
'features',
314309
featureLimitAlert.percentage,
315310
)}
316-
{environmentMetricsEnabled && (
317-
<EnvironmentMetricsList
318-
environmentApiKey={environment?.api_key}
319-
forceRefetch={this.state.forceMetricsRefetch}
320-
projectId={projectId}
321-
/>
322-
)}
311+
<FeatureMetricsSection
312+
environmentApiKey={environment?.api_key}
313+
forceRefetch={this.state.forceMetricsRefetch}
314+
projectId={projectId}
315+
/>
323316
<PageTitle
324317
title={'Features'}
325318
cta={
@@ -642,108 +635,15 @@ const FeaturesPage = class extends Component {
642635
</div>
643636
) : (
644637
!isLoading &&
645-
this.state.loadedOnce && (
646-
<div>
647-
<h3>Brilliant! Now create your features.</h3>
648-
<FormGroup>
649-
<Panel
650-
icon='ion-ios-settings'
651-
title='1. configuring features per environment'
652-
>
653-
<p>
654-
We've created 2 Environments for you:{' '}
655-
<strong>Development</strong> and{' '}
656-
<strong>Production</strong>. When you create a
657-
Feature it makes copies of them for each
658-
Environment, allowing you to edit the values
659-
separately. You can create more Environments too
660-
if you need to.
661-
</p>
662-
</Panel>
663-
</FormGroup>
664-
<FormGroup>
665-
<Panel
666-
icon='ion-ios-rocket'
667-
title='2. creating a feature'
668-
>
669-
<p>
670-
Features in Flagsmith are made up of two
671-
different data types:
672-
<ul>
673-
<li>
674-
<strong>Booleans</strong>: These allows you
675-
to toggle features on and off:
676-
<p className='faint'>
677-
EXAMPLE: You're working on a new messaging
678-
feature for your app but only want to show
679-
it in your Development Environment.
680-
</p>
681-
</li>
682-
<li>
683-
<strong>String Values</strong>:
684-
configuration for a particular feature
685-
<p className='faint'>
686-
EXAMPLE: This could be absolutely anything
687-
from a font size for a website/mobile app
688-
or an environment variable for a server
689-
</p>
690-
</li>
691-
</ul>
692-
</p>
693-
</Panel>
694-
</FormGroup>
695-
<FormGroup>
696-
<Panel
697-
icon='ion-ios-person'
698-
title='3. configuring features per user'
699-
>
700-
<p>
701-
When users login to your application, you can{' '}
702-
<strong>Identify</strong> them using one of our
703-
SDKs, this will add them to the Identities page.
704-
From there you can configure their Features.
705-
We've created an example user for you which you
706-
can see in the{' '}
707-
<Link
708-
className='btn-link'
709-
to={`/project/${projectId}/environment/${environmentId}/users`}
710-
>
711-
Identities page
712-
</Link>
713-
.
714-
<p className='faint'>
715-
EXAMPLE: You're working on a new messaging
716-
feature for your app but only want to show it
717-
for that Identity.
718-
</p>
719-
</p>
720-
</Panel>
721-
</FormGroup>
722-
{this.createFeaturePermission((perm) => (
723-
<FormGroup className='text-center'>
724-
<Button
725-
disabled={!perm}
726-
className='btn-lg btn-primary'
727-
id='show-create-feature-btn'
728-
data-test='show-create-feature-btn'
729-
onClick={this.newFlag}
730-
>
731-
<div className='flex-row justify-content-center'>
732-
<IonIcon
733-
className='me-1'
734-
icon={rocket}
735-
style={{
736-
contain: 'none',
737-
height: '25px',
738-
}}
739-
/>
740-
<span>Create your first Feature</span>
741-
</div>
742-
</Button>
743-
</FormGroup>
744-
))}
745-
</div>
746-
)
638+
this.state.loadedOnce &&
639+
this.createFeaturePermission((perm) => (
640+
<FeaturesEmptyState
641+
environmentId={environmentId}
642+
projectId={projectId}
643+
onCreateFeature={this.newFlag}
644+
canCreateFeature={perm}
645+
/>
646+
))
747647
)}
748648
</div>
749649
)}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import React, { FC } from 'react'
2+
import EnvironmentMetricsList from 'components/metrics/EnvironmentMetricsList'
3+
import Utils from 'common/utils/utils'
4+
5+
type FeatureMetricsSectionProps = {
6+
environmentApiKey?: string
7+
forceRefetch: boolean
8+
projectId: string
9+
}
10+
11+
export const FeatureMetricsSection: FC<FeatureMetricsSectionProps> = ({
12+
environmentApiKey,
13+
forceRefetch,
14+
projectId,
15+
}) => {
16+
const environmentMetricsEnabled = Utils.getFlagsmithHasFeature(
17+
'environment_metrics',
18+
)
19+
20+
if (!environmentMetricsEnabled) {
21+
return null
22+
}
23+
24+
return (
25+
<EnvironmentMetricsList
26+
environmentApiKey={environmentApiKey}
27+
forceRefetch={forceRefetch}
28+
projectId={projectId}
29+
/>
30+
)
31+
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import React, { FC } from 'react'
2+
import { IonIcon } from '@ionic/react'
3+
import { rocket } from 'ionicons/icons'
4+
import Button from 'components/base/forms/Button'
5+
import Panel from 'components/base/grid/Panel'
6+
import { Link } from 'react-router-dom'
7+
8+
type FeaturesEmptyStateProps = {
9+
environmentId: string
10+
onCreateFeature: () => void
11+
projectId: string
12+
canCreateFeature: boolean
13+
}
14+
15+
export const FeaturesEmptyState: FC<FeaturesEmptyStateProps> = ({
16+
canCreateFeature,
17+
environmentId,
18+
onCreateFeature,
19+
projectId,
20+
}) => {
21+
return (
22+
<div>
23+
<h3>Brilliant! Now create your features.</h3>
24+
<FormGroup>
25+
<Panel
26+
icon='ion-ios-settings'
27+
title='1. configuring features per environment'
28+
>
29+
<p>
30+
We've created 2 Environments for you: <strong>Development</strong>{' '}
31+
and <strong>Production</strong>. When you create a Feature it makes
32+
copies of them for each Environment, allowing you to edit the values
33+
separately. You can create more Environments too if you need to.
34+
</p>
35+
</Panel>
36+
</FormGroup>
37+
<FormGroup>
38+
<Panel icon='ion-ios-rocket' title='2. creating a feature'>
39+
<p>
40+
Features in Flagsmith are made up of two different data types:
41+
<ul>
42+
<li>
43+
<strong>Booleans</strong>: These allows you to toggle features
44+
on and off:
45+
<p className='faint'>
46+
EXAMPLE: You're working on a new messaging feature for your
47+
app but only want to show it in your Development Environment.
48+
</p>
49+
</li>
50+
<li>
51+
<strong>String Values</strong>: configuration for a particular
52+
feature
53+
<p className='faint'>
54+
EXAMPLE: This could be absolutely anything from a font size
55+
for a website/mobile app or an environment variable for a
56+
server
57+
</p>
58+
</li>
59+
</ul>
60+
</p>
61+
</Panel>
62+
</FormGroup>
63+
<FormGroup>
64+
<Panel icon='ion-ios-person' title='3. configuring features per user'>
65+
<p>
66+
When users login to your application, you can{' '}
67+
<strong>Identify</strong> them using one of our SDKs, this will add
68+
them to the Identities page. From there you can configure their
69+
Features. We've created an example user for you which you can see in
70+
the{' '}
71+
<Link
72+
className='btn-link'
73+
to={`/project/${projectId}/environment/${environmentId}/users`}
74+
>
75+
Identities page
76+
</Link>
77+
.
78+
<p className='faint'>
79+
EXAMPLE: You're working on a new messaging feature for your app
80+
but only want to show it for that Identity.
81+
</p>
82+
</p>
83+
</Panel>
84+
</FormGroup>
85+
<FormGroup className='text-center'>
86+
<Button
87+
disabled={!canCreateFeature}
88+
className='btn-lg btn-primary'
89+
id='show-create-feature-btn'
90+
data-test='show-create-feature-btn'
91+
onClick={onCreateFeature}
92+
>
93+
<div className='flex-row justify-content-center'>
94+
<IonIcon
95+
className='me-1'
96+
icon={rocket}
97+
style={{
98+
contain: 'none',
99+
height: '25px',
100+
}}
101+
/>
102+
<span>Create your first Feature</span>
103+
</div>
104+
</Button>
105+
</FormGroup>
106+
</div>
107+
)
108+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export { FeaturesEmptyState } from './FeaturesEmptyState'
2+
export { FeatureMetricsSection } from './FeatureMetricsSection'

0 commit comments

Comments
 (0)