Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Prevent "Create Segment" button from disappearing when deleting the last segment #4314

Merged
merged 1 commit into from
Jul 12, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
320 changes: 133 additions & 187 deletions frontend/web/components/pages/SegmentsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import PageTitle from 'components/PageTitle'
import Switch from 'components/Switch'
import { setModalTitle } from 'components/modals/base/ModalDefault'
import classNames from 'classnames'
import InfoMessage from 'components/InfoMessage';

const CodeHelp = require('../../components/CodeHelp')
type SegmentsPageType = {
Expand All @@ -36,23 +37,6 @@ type SegmentsPageType = {
}
}

const HowToUseSegmentsMessage = () => (
<div className='mt-2'>
<p className='alert alert-info'>
In order to use segments, please set the segment_operators remote config
value.{' '}
<Button
theme='text'
target='_blank'
href='https://docs.flagsmith.com/deployment/overview#running-flagsmith-on-flagsmith'
>
Learn about self hosting
</Button>
.
</p>
</div>
)

const SegmentsPage: FC<SegmentsPageType> = (props) => {
const { projectId } = props.match.params
const environmentId =
Expand All @@ -72,7 +56,6 @@ const SegmentsPage: FC<SegmentsPageType> = (props) => {
q: search,
})
const [removeSegment, { isLoading: isRemoving }] = useDeleteSegmentMutation()
const hasHadResults = useRef(false)

const segmentsLimitAlert = Utils.calculateRemainingLimitsPercentage(
ProjectStore.getTotalSegments(),
Expand Down Expand Up @@ -155,11 +138,6 @@ const SegmentsPage: FC<SegmentsPageType> = (props) => {
</Tooltip>
)
}

if (data?.results.length) {
hasHadResults.current = true
}

const segments = data?.results
return (
<div
Expand All @@ -169,26 +147,23 @@ const SegmentsPage: FC<SegmentsPageType> = (props) => {
>
<PageTitle
cta={
segments && (segments.length || searchInput) ? (
<>
{renderWithPermission(
manageSegmentsPermission,
'Manage segments',
<Button
disabled={
hasNoOperators ||
!manageSegmentsPermission ||
segmentsLimitAlert.percentage >= 100
}
id='show-create-segment-btn'
data-test='show-create-segment-btn'
onClick={newSegment}
>
Create Segment
</Button>,
)}
</>
) : null
<>
{renderWithPermission(
manageSegmentsPermission,
'Manage segments',
<Button
disabled={
!manageSegmentsPermission ||
segmentsLimitAlert.percentage >= 100
}
id='show-create-segment-btn'
data-test='show-create-segment-btn'
onClick={newSegment}
>
Create Segment
</Button>,
)}
</>
}
title={'Segments'}
>
Expand All @@ -212,164 +187,135 @@ const SegmentsPage: FC<SegmentsPageType> = (props) => {
</Button>
</PageTitle>
<div className='segments-page'>
{isLoading && !hasHadResults.current && !segments && !searchInput && (
{isLoading && !segments && !searchInput && (
<div className='centered-container'>
<Loader />
</div>
)}
{(!isLoading || segments || searchInput) && (
<div>
{Utils.displayLimitAlert('segments', segmentsLimitAlert.percentage)}
{hasHadResults.current ||
(segments && (segments.length || searchInput)) ? (
<div>
{hasNoOperators && <HowToUseSegmentsMessage />}

<FormGroup className={classNames({ 'opacity-50': isRemoving })}>
<PanelSearch
filterElement={
<div className='text-right me-2'>
<label className='me-2'>Include Feature-Specific</label>
<Switch onChange={setShowFeatureSpecific} />
</div>
<div>
<FormGroup className={classNames({ 'opacity-50': isRemoving })}>
<PanelSearch
filterElement={
<div className='text-right me-2'>
<label className='me-2'>Include Feature-Specific</label>
<Switch onChange={setShowFeatureSpecific} />
</div>
}
renderSearchWithNoResults
className='no-pad'
id='segment-list'
title=' '
renderFooter={() => (
<JSONReference
className='mx-2 mt-4'
title={'Segments'}
json={segments}
/>
)}
items={sortBy(segments, (v) => {
return `${v.feature ? 'a' : 'z'}${v.name}`
})}
renderRow={(
{ description, feature, id, name }: Segment,
i: number,
) => {
if (preselect.current === `${id}`) {
editSegment(preselect.current, !manageSegmentsPermission)
preselect.current = null
}
renderSearchWithNoResults
className='no-pad'
id='segment-list'
title='Segments'
renderFooter={() => (
<JSONReference
className='mx-2 mt-4'
title={'Segments'}
json={segments}
/>
)}
items={sortBy(segments, (v) => {
return `${v.feature ? 'a' : 'z'}${v.name}`
})}
renderRow={(
{ description, feature, id, name }: Segment,
i: number,
) => {
if (preselect.current === `${id}`) {
editSegment(
preselect.current,
!manageSegmentsPermission,
)
preselect.current = null
}

// TODO: remove this check
// I'm leaving this here for now so that we can deploy the FE and
// API independently, but we should remove this once PR #3430 is
// merged and released.
if (feature && !showFeatureSpecific) {
return null
}
// TODO: remove this check
// I'm leaving this here for now so that we can deploy the FE and
// API independently, but we should remove this once PR #3430 is
// merged and released.
if (feature && !showFeatureSpecific) {
return null
}

return renderWithPermission(
manageSegmentsPermission,
'Manage segments',
<Row className='list-item clickable' key={id} space>
<Flex
className='table-column px-3'
onClick={
manageSegmentsPermission
? () =>
editSegment(id, !manageSegmentsPermission)
: undefined
}
return renderWithPermission(
manageSegmentsPermission,
'Manage segments',
<Row className='list-item clickable' key={id} space>
<Flex
className='table-column px-3'
onClick={
manageSegmentsPermission
? () => editSegment(id, !manageSegmentsPermission)
: undefined
}
>
<Row
data-test={`segment-${i}-name`}
className='font-weight-medium'
>
<Row
data-test={`segment-${i}-name`}
className='font-weight-medium'
>
{name}
{feature && (
<div className='chip chip--xs ml-2'>
Feature-Specific
</div>
)}
</Row>
<div className='list-item-subtitle mt-1'>
{description || 'No description'}
</div>
</Flex>
<div className='table-column'>
<Button
disabled={!manageSegmentsPermission}
data-test={`remove-segment-btn-${i}`}
onClick={() => {
const segment = find(segments, { id })
if (segment) {
confirmRemove(segment, () => {
removeSegment({ id, projectId }).then(
(res) => {
toast(
<div>
Removed Segment:{' '}
<strong>{segment.name}</strong>
</div>,
)
},
)
})
}
}}
className='btn btn-with-icon'
>
<Icon name='trash-2' width={20} fill='#656D7B' />
</Button>
{name}
{feature && (
<div className='chip chip--xs ml-2'>
Feature-Specific
</div>
)}
</Row>
<div className='list-item-subtitle mt-1'>
{description || 'No description'}
</div>
</Row>,
)
}}
paging={data}
nextPage={() => setPage(page + 1)}
prevPage={() => setPage(page - 1)}
goToPage={(page: number) => setPage(page)}
search={searchInput}
onChange={(e: any) => {
setSearchInput(Utils.safeParseEventValue(e))
}}
renderNoResults={<div className='text-center' />}
filterRow={() => true}
/>
</FormGroup>
</Flex>
<div className='table-column'>
<Button
disabled={!manageSegmentsPermission}
data-test={`remove-segment-btn-${i}`}
onClick={() => {
const segment = find(segments, { id })
if (segment) {
confirmRemove(segment, () => {
removeSegment({ id, projectId }).then(
(res) => {
toast(
<div>
Removed Segment:{' '}
<strong>{segment.name}</strong>
</div>,
)
},
)
})
}
}}
className='btn btn-with-icon'
>
<Icon name='trash-2' width={20} fill='#656D7B' />
</Button>
</div>
</Row>,
)
}}
paging={data}
nextPage={() => setPage(page + 1)}
prevPage={() => setPage(page - 1)}
goToPage={(page: number) => setPage(page)}
search={searchInput}
onChange={(e: any) => {
setSearchInput(Utils.safeParseEventValue(e))
}}
filterRow={() => true}
/>
</FormGroup>

<p>
Segments require you to identitfy users, setting traits will
add users to segments.
</p>
<FormGroup className='mt-4'>
<CodeHelp
title='Using segments'
snippets={Constants.codeHelp.USER_TRAITS(
environmentId || 'ENVIRONMENT_KEY',
)}
/>
</FormGroup>
</div>
) : (
<div>
<FormGroup className='text-center'>
{renderWithPermission(
manageSegmentsPermission,
'Manage segments',
<Button
disabled={!manageSegmentsPermission || hasNoOperators}
className='btn-lg btn-primary'
id='show-create-segment-btn'
data-test='show-create-segment-btn'
onClick={newSegment}
>
Create your first Segment
</Button>,
<InfoMessage>
Segments require you to identitfy users, setting traits will add
users to segments.
</InfoMessage>
<FormGroup className='mt-4'>
<CodeHelp
title='Using segments'
snippets={Constants.codeHelp.USER_TRAITS(
environmentId || 'ENVIRONMENT_KEY',
)}
</FormGroup>
{hasNoOperators && <HowToUseSegmentsMessage />}
</div>
)}
/>
</FormGroup>
</div>
</div>
)}
<FormGroup>
Expand Down
Loading