Skip to content

Commit cff70ec

Browse files
committed
Display import success banner with deprecated flag count
1 parent 5d205a8 commit cff70ec

7 files changed

Lines changed: 106 additions & 39 deletions

File tree

frontend/common/types/responses.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ export type LaunchDarklyProjectImport = {
186186
status: {
187187
requested_environment_count: number
188188
requested_flag_count: number
189+
deprecated_flag_count?: number
189190
result: string | null
190191
error_message: string | null
191192
}

frontend/web/components/import-export/ImportPage.tsx

Lines changed: 27 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -26,52 +26,45 @@ const ImportPage: FC<ImportPageType> = ({ projectId, projectName }) => {
2626
const history = useHistory()
2727
const [LDKey, setLDKey] = useState<string>('')
2828
const [importId, setImportId] = useState<number>()
29+
const [importSource, setImportSource] = useState<string>('')
2930
const [isLoading, setIsLoading] = useState<boolean>(false)
30-
const [isAppLoading, setAppIsLoading] = useState<boolean>(false)
3131
const [projects, setProjects] = useState<{ key: string; name: string }[]>([])
3232
const [createLaunchDarklyProjectImport, { data, isSuccess }] =
3333
useCreateLaunchDarklyProjectImportMutation()
3434

35-
const {
36-
data: status,
37-
isSuccess: statusLoaded,
38-
isUninitialized,
39-
refetch,
40-
} = useGetLaunchDarklyProjectImportQuery(
35+
const { data: status } = useGetLaunchDarklyProjectImportQuery(
4136
{
4237
import_id: `${importId}`,
4338
project_id: projectId,
4439
},
45-
{ skip: !importId },
40+
{
41+
pollingInterval: importId ? 1000 : 0,
42+
skip: !importId,
43+
},
4644
)
4745

46+
// Set importId when mutation succeeds
4847
useEffect(() => {
49-
const checkImportStatus = async () => {
50-
setAppIsLoading(true)
51-
const intervalId = setInterval(async () => {
52-
await refetch()
53-
54-
if (statusLoaded && status && status.status.result === 'success') {
55-
clearInterval(intervalId)
56-
setAppIsLoading(false)
57-
window.location.reload()
58-
}
59-
}, 1000)
60-
}
61-
62-
if (statusLoaded) {
63-
checkImportStatus()
48+
if (isSuccess && data?.id) {
49+
setImportId(data.id)
50+
setImportSource('LaunchDarkly')
6451
}
65-
}, [statusLoaded, status, refetch])
52+
}, [isSuccess, data])
6653

54+
// Navigate away on import success
6755
useEffect(() => {
68-
if (isSuccess && data?.id) {
69-
setImportId(data.id)
70-
if (!isUninitialized) {
71-
refetch()
72-
}
56+
if (status?.status?.result === 'success') {
57+
const params = new URLSearchParams()
58+
params.set('import_success', '1')
59+
params.set('import_source', importSource)
60+
params.set('import_count', String(status.status.requested_flag_count))
61+
params.set(
62+
'import_deprecated',
63+
String(status.status.deprecated_flag_count ?? 0),
64+
)
65+
history.push(`/project/${projectId}?${params.toString()}`)
7366
}
74-
}, [isSuccess, data, refetch, isUninitialized])
67+
}, [status, projectId, history, importSource])
7568

7669
const getProjectList = (LDKey: string) => {
7770
setIsLoading(true)
@@ -210,11 +203,13 @@ const ImportPage: FC<ImportPageType> = ({ projectId, projectName }) => {
210203
</>
211204
)
212205

206+
const isImporting = !!importId && status?.status?.result !== 'success'
207+
213208
return (
214209
<>
215-
{isAppLoading && (
210+
{isImporting && (
216211
<div className='overlay'>
217-
<div className='title'>Importing Project</div>
212+
<div className='title'>Importing from {importSource}...</div>
218213
<AppLoader />
219214
</div>
220215
)}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { FC, useState } from 'react'
2+
import { useHistory, useLocation, Link } from 'react-router-dom'
3+
import SuccessMessage from 'components/messages/SuccessMessage'
4+
import Utils from 'common/utils/utils'
5+
6+
type ImportSuccessBannerProps = {
7+
projectId: string
8+
environmentId: string
9+
}
10+
11+
const ImportSuccessBanner: FC<ImportSuccessBannerProps> = ({
12+
environmentId,
13+
projectId,
14+
}) => {
15+
const history = useHistory()
16+
const location = useLocation()
17+
const [dismissed, setDismissed] = useState(false)
18+
19+
const params = Utils.fromParam()
20+
const isImportSuccess = params.import_success === '1'
21+
const source = params.import_source
22+
const count = parseInt(params.import_count, 10)
23+
const deprecated = parseInt(params.import_deprecated, 10) || 0
24+
25+
if (!isImportSuccess || !source || !count || dismissed) {
26+
return null
27+
}
28+
29+
const handleDismiss = () => {
30+
setDismissed(true)
31+
history.replace(location.pathname)
32+
}
33+
34+
const archivedLink = `/project/${projectId}/environment/${environmentId}/features?is_archived=true`
35+
36+
return (
37+
<div className='mb-4'>
38+
<SuccessMessage isClosable close={handleDismiss}>
39+
Imported {count} flag{count !== 1 && 's'} from {source}.
40+
{deprecated > 0 && (
41+
<>
42+
{' '}
43+
{deprecated} deprecated flag
44+
{deprecated !== 1 ? 's were' : ' was'}{' '}
45+
<Link to={archivedLink}>archived</Link>.
46+
</>
47+
)}
48+
</SuccessMessage>
49+
</div>
50+
)
51+
}
52+
53+
export default ImportSuccessBanner

frontend/web/components/messages/SuccessMessage.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,12 @@ const SuccessMessage: React.FC<SuccessMessageProps> = ({
3636
const titleDescClass = infoMessageClass ? `${infoMessageClass} body mr-2` : ''
3737

3838
return (
39-
<div className={infoMessageClassName} style={{ ...successStyles }}>
39+
<div className={infoMessageClassName} style={successStyles}>
4040
<span className={`icon-alert ${infoMessageClass} info-icon`}>
4141
<Icon fill='#27AB95' name='checkmark-circle' />
4242
</span>
4343
<div className={titleDescClass}>
44-
<div style={{ fontWeight: 'semi-bold' }}>{title}</div>
44+
<div className='title'>{title}</div>
4545
{children}
4646
</div>
4747
{url && (
@@ -50,8 +50,8 @@ const SuccessMessage: React.FC<SuccessMessageProps> = ({
5050
</Button>
5151
)}
5252
{isClosable && (
53-
<a onClick={close} className='mt-n2 mr-n2 pl-2'>
54-
<span className={`icon ${infoMessageClass} close-btn`}>
53+
<a onClick={close} className='close-btn'>
54+
<span className={`icon ${infoMessageClass}`}>
5555
<IonIcon icon={closeIcon} />
5656
</span>
5757
</a>

frontend/web/components/pages/FeaturesPage.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import FeatureFilters, {
2020
getURLParamsFromFilters,
2121
} from 'components/feature-page/FeatureFilters'
2222
import { FeatureMetricsSection, FeaturesEmptyState } from './features'
23+
import ImportSuccessBanner from 'components/import-export/ImportSuccessBanner'
2324

2425
const FeaturesPage = class extends Component {
2526
static displayName = 'FeaturesPage'
@@ -48,15 +49,20 @@ const FeaturesPage = class extends Component {
4849
componentDidUpdate(prevProps) {
4950
const {
5051
match: { params },
52+
location,
5153
} = this.props
5254
const {
5355
match: { params: oldParams },
56+
location: oldLocation,
5457
} = prevProps
5558
if (
5659
params.environmentId !== oldParams.environmentId ||
5760
params.projectId !== oldParams.projectId
5861
) {
5962
this.setState({ loadedOnce: false }, () => this.filter())
63+
} else if (location.search !== oldLocation.search) {
64+
const newFilters = parseFiltersFromUrlParams(Utils.fromParam())
65+
this.setState({ filters: newFilters }, () => this.filter())
6066
}
6167
}
6268

@@ -226,6 +232,10 @@ const FeaturesPage = class extends Component {
226232
'features',
227233
featureLimitAlert.percentage,
228234
)}
235+
<ImportSuccessBanner
236+
projectId={projectId}
237+
environmentId={environmentId}
238+
/>
229239
<FeatureMetricsSection
230240
environmentApiKey={environment?.api_key}
231241
forceRefetch={this.state.forceMetricsRefetch}

frontend/web/components/pages/ProjectRedirectPage.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import { FC, useEffect } from 'react'
22
import { useGetEnvironmentsQuery } from 'common/services/useEnvironment'
3-
import { useHistory } from 'react-router-dom'
3+
import { useHistory, useLocation } from 'react-router-dom'
44
import Utils from 'common/utils/utils'
55
import ConfigProvider from 'common/providers/ConfigProvider'
66
import { useRouteContext } from 'components/providers/RouteContext'
77

88
const ProjectRedirectPage: FC = () => {
99
const history = useHistory()
10+
const location = useLocation()
1011
const { projectId } = useRouteContext()
1112

1213
const { data, error } = useGetEnvironmentsQuery({
@@ -22,12 +23,12 @@ const ProjectRedirectPage: FC = () => {
2223
const environment = data?.results?.[0]
2324
if (environment) {
2425
history.replace(
25-
`/project/${projectId}/environment/${environment.api_key}/features`,
26+
`/project/${projectId}/environment/${environment.api_key}/features${location.search}`,
2627
)
2728
} else {
2829
history.replace(`/project/${projectId}/environment/create`)
2930
}
30-
}, [data, error, history])
31+
}, [data, error, history, location.search])
3132
return (
3233
<div className='text-center'>
3334
<Loader />

frontend/web/styles/project/_alert.scss

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
}
6767
}
6868
.alert-success {
69+
position: relative;
6970
background-color: $alert-success-bg;
7071
border-color: $alert-success-border-color;
7172
.title {
@@ -81,6 +82,12 @@
8182
font-weight: 500;
8283
color: $body-color;
8384
}
85+
.close-btn {
86+
position: absolute;
87+
top: 0.5rem;
88+
right: 0.5rem;
89+
cursor: pointer;
90+
}
8491
}
8592

8693
.dark {

0 commit comments

Comments
 (0)