Skip to content

Commit c85c940

Browse files
author
Bogdan Tsechoev
committed
Merge branch 'full-refresh-button-ui' into 'dle-4-0'
feat(ui): add full-refresh button See merge request postgres-ai/database-lab!1025
2 parents e84125f + 4e94b1f commit c85c940

File tree

6 files changed

+183
-1
lines changed

6 files changed

+183
-1
lines changed

ui/packages/ce/src/App/Instance/Page/index.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import { getBranches } from 'api/branches/getBranches'
2222
import { getSnapshotList } from 'api/branches/getSnapshotList'
2323
import { deleteBranch } from 'api/branches/deleteBranch'
2424
import { destroySnapshot } from 'api/snapshots/destroySnapshot'
25+
import { fullRefresh } from 'api/instances/fullRefresh'
2526

2627
export const Page = ({ renderCurrentTab }: { renderCurrentTab?: number }) => {
2728
const routes = {
@@ -57,7 +58,8 @@ export const Page = ({ renderCurrentTab }: { renderCurrentTab?: number }) => {
5758
getBranches,
5859
getSnapshotList,
5960
deleteBranch,
60-
destroySnapshot
61+
destroySnapshot,
62+
fullRefresh,
6163
}
6264

6365
const elements = {
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*--------------------------------------------------------------------------
2+
* Copyright (c) 2019-2021, Postgres.ai, Nikolay Samokhvalov nik@postgres.ai
3+
* All Rights Reserved. Proprietary and confidential.
4+
* Unauthorized copying of this file, via any medium is strictly prohibited
5+
*--------------------------------------------------------------------------
6+
*/
7+
8+
import { request } from 'helpers/request'
9+
import { FullRefresh } from "@postgres.ai/shared/types/api/endpoints/fullRefresh";
10+
11+
export const fullRefresh: FullRefresh = async () => {
12+
const response = await request('/full-refresh', {
13+
method: "POST",
14+
})
15+
16+
const result = response.ok ? await response.json() : null
17+
18+
return {
19+
response: result,
20+
error: response.ok ? null : response,
21+
}
22+
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import { useState } from 'react'
2+
import { makeStyles } from '@material-ui/core'
3+
4+
import { Modal } from '@postgres.ai/shared/components/Modal'
5+
import { Text } from '@postgres.ai/shared/components/Text'
6+
import { SimpleModalControls } from '@postgres.ai/shared/components/SimpleModalControls'
7+
import { useStores } from '@postgres.ai/shared/pages/Instance/context'
8+
9+
type Props = {
10+
isOpen: boolean
11+
onClose: () => void
12+
instanceId: string
13+
}
14+
15+
interface ErrorResponse {
16+
error?: {
17+
message?: string
18+
details?: string
19+
}
20+
}
21+
22+
const useStyles = makeStyles(
23+
{
24+
errorMessage: {
25+
color: 'red',
26+
marginTop: '10px',
27+
wordBreak: 'break-all',
28+
},
29+
checkboxRoot: {
30+
padding: '9px 10px',
31+
},
32+
grayText: {
33+
color: '#8a8a8a',
34+
fontSize: '12px',
35+
wordBreak: 'break-word',
36+
},
37+
marginTop: {
38+
marginTop: '6px',
39+
},
40+
},
41+
{ index: 1 },
42+
)
43+
44+
export const ConfirmFullRefreshModal = ({
45+
isOpen,
46+
onClose,
47+
instanceId,
48+
}: Props) => {
49+
const classes = useStyles()
50+
const stores = useStores()
51+
52+
const { fullRefresh } = stores.main
53+
54+
const [fullRefreshError, setFullRefreshError] = useState<ErrorResponse | null>(null)
55+
56+
const handleClose = () => {
57+
onClose()
58+
}
59+
60+
const handleConfirm = async () => {
61+
const result = await fullRefresh(instanceId);
62+
if (!result) {
63+
setFullRefreshError({ error: { message: 'Unexpected error occurred.' } });
64+
return;
65+
}
66+
const { response, error } = result;
67+
if (error) {
68+
setFullRefreshError({
69+
error: {
70+
message: error.message,
71+
},
72+
})
73+
return
74+
}
75+
if (response) {
76+
onClose()
77+
}
78+
}
79+
80+
81+
return (
82+
<Modal
83+
title={'Confirmation'}
84+
onClose={handleClose}
85+
isOpen={isOpen}
86+
size="sm"
87+
>
88+
<Text>
89+
Are you sure you want to perform a full refresh of the instance?
90+
This action cannot be undone.
91+
</Text>
92+
{fullRefreshError && <p className={classes.errorMessage}>{fullRefreshError.error?.message}</p>}
93+
<SimpleModalControls
94+
items={[
95+
{
96+
text: 'Cancel',
97+
onClick: handleClose,
98+
},
99+
{
100+
text: 'Confirm',
101+
variant: 'primary',
102+
onClick: handleConfirm,
103+
isDisabled: fullRefreshError !== null,
104+
},
105+
]}
106+
/>
107+
</Modal>
108+
)
109+
}

ui/packages/shared/pages/Instance/Info/Retrieval/index.tsx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { RefreshFailedAlert } from './RefreshFailedAlert'
1515

1616
import { getTypeByStatus, isRetrievalUnknown } from './utils'
1717
import { RetrievalModal } from './RetrievalModal'
18+
import { ConfirmFullRefreshModal } from './ConfirmFullRefreshModal'
1819

1920
const useStyles = makeStyles(
2021
() => ({
@@ -26,6 +27,9 @@ const useStyles = makeStyles(
2627
},
2728
detailsButton: {
2829
marginLeft: '8px',
30+
'@media (max-width: 600px)': {
31+
marginTop: '4px',
32+
},
2933
},
3034
}),
3135
{ index: 1 },
@@ -35,6 +39,7 @@ export const Retrieval = observer(() => {
3539
const stores = useStores()
3640
const classes = useStyles()
3741
const [isModalOpen, setIsModalOpen] = useState<boolean>(false)
42+
const [isFullRefreshModalOpen, setIsFullRefreshModalOpen] = useState<boolean>(false)
3843

3944
const { instance, instanceRetrieval } = stores.main
4045
if (!instance) return null
@@ -43,9 +48,12 @@ export const Retrieval = observer(() => {
4348
if (!retrieving) return null
4449

4550
if (!instanceRetrieval) return null
51+
4652
const { mode, status, activity } = instanceRetrieval
53+
4754
const isVisible = mode !== 'physical' && !isRetrievalUnknown(mode)
4855
const isActive = mode === 'logical' && status === 'refreshing'
56+
const canCallFullRefresh = retrieving.status === 'finished' || retrieving.status === 'failed'
4957

5058
return (
5159
<Section title="Retrieval">
@@ -64,6 +72,14 @@ export const Retrieval = observer(() => {
6472
</Button>
6573
</>
6674
)}
75+
<Button
76+
theme="secondary"
77+
onClick={() => setIsFullRefreshModalOpen(true)}
78+
isDisabled={!canCallFullRefresh}
79+
className={classes.detailsButton}
80+
>
81+
Full refresh
82+
</Button>
6783
</Status>
6884
</Property>
6985
<Property name="Mode">{retrieving.mode}</Property>
@@ -83,6 +99,11 @@ export const Retrieval = observer(() => {
8399
isOpen={isModalOpen}
84100
onClose={() => setIsModalOpen(false)}
85101
/>
102+
<ConfirmFullRefreshModal
103+
isOpen={isFullRefreshModalOpen}
104+
onClose={() => setIsFullRefreshModalOpen(false)}
105+
instanceId={instance.id}
106+
/>
86107
</Section>
87108
)
88109
})

ui/packages/shared/pages/Instance/stores/Main.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import { GetBranches } from '@postgres.ai/shared/types/api/endpoints/getBranches
3131
import { DeleteBranch } from '@postgres.ai/shared/types/api/endpoints/deleteBranch'
3232
import { GetSeImages } from '@postgres.ai/shared/types/api/endpoints/getSeImages'
3333
import { DestroySnapshot } from '@postgres.ai/shared/types/api/endpoints/destroySnapshot'
34+
import { FullRefresh } from "../../../types/api/endpoints/fullRefresh";
3435

3536
const UNSTABLE_CLONE_STATUS_CODES = ['CREATING', 'RESETTING', 'DELETING']
3637

@@ -54,6 +55,7 @@ export type Api = {
5455
getSnapshotList?: GetSnapshotList
5556
deleteBranch?: DeleteBranch
5657
destroySnapshot?: DestroySnapshot
58+
fullRefresh?: FullRefresh
5759
}
5860

5961
type Error = {
@@ -445,4 +447,24 @@ export class MainStore {
445447
error: error ? await error.json().then((err) => err) : null,
446448
}
447449
}
450+
451+
fullRefresh = async (instanceId: string): Promise<{ response: string | null, error: Error | null } | undefined> => {
452+
if (!this.api.fullRefresh) return
453+
454+
const { response, error } = await this.api.fullRefresh({
455+
instanceId,
456+
})
457+
458+
if (error) {
459+
const parsedError = await error.json().then((err) => ({
460+
message: err.message || 'An unknown error occurred',
461+
}));
462+
463+
return { response: null, error: parsedError }
464+
} else if (this.instance?.state?.retrieving) {
465+
this.instance.state.retrieving.status = 'refreshing';
466+
}
467+
468+
return { response: response ? String(response) : null, error: null }
469+
}
448470
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export type FullRefresh = (args: {
2+
instanceId: string
3+
}) => Promise<{
4+
response: true | null
5+
error: Response | null
6+
}>

0 commit comments

Comments
 (0)