-
Notifications
You must be signed in to change notification settings - Fork 4.4k
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
🪟 Per-Stream state new flow #14634
🪟 Per-Stream state new flow #14634
Changes from 13 commits
78c9d6b
efa5c98
6ab269c
654d502
b89cc19
2657d88
6fce4f0
5a9cbcc
13be9e8
7d1fbeb
9266bb5
ee1c329
871df8a
f0515e8
8de44f9
e08d0e5
6fd68b1
9e7fd01
22036c0
4787a78
a0cb0ce
8cbe3fe
7cadda6
f736e2e
4984735
b92807b
1f0b868
5e759ca
95a90b6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,6 +19,7 @@ export const buildConnectionUpdate = ( | |
connection: WebBackendConnectionRead, | ||
connectionUpdate: Partial<WebBackendConnectionUpdate> | ||
): WebBackendConnectionUpdate => ({ | ||
skipReset: true, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm guessing that skipReset is default to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's correct, it defaults to |
||
...toWebBackendConnectionUpdate(connection), | ||
...connectionUpdate, | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import React, { useContext, useMemo, useRef, useState } from "react"; | ||
import { firstValueFrom, Subject } from "rxjs"; | ||
|
||
import { Modal } from "components"; | ||
|
||
import { ModalOptions, ModalResult, ModalServiceContextType } from "./types"; | ||
|
||
const ModalServiceContext = React.createContext<ModalServiceContextType | undefined>(undefined); | ||
timroes marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
export const ModalServiceProvider: React.FC = ({ children }) => { | ||
// The any here is due to the fact, that every call to open a modal might come in with | ||
// a different type, thus we can't type this with unknown or a generic. | ||
// The consuming code of this service though is properly typed, so that this `any` stays | ||
// encapsulated within this component. | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
const [modalOptions, setModalOptions] = useState<ModalOptions<any>>(); | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
const resultSubjectRef = useRef<Subject<ModalResult<any>>>(); | ||
|
||
const service: ModalServiceContextType = useMemo( | ||
() => ({ | ||
openModal: (options) => { | ||
resultSubjectRef.current = new Subject(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ℹ️ Why solving this with an observable here, despite only needing a one time resolved value. The problem is, that we can't control a |
||
setModalOptions(options); | ||
|
||
return firstValueFrom(resultSubjectRef.current).then((reason) => { | ||
setModalOptions(undefined); | ||
resultSubjectRef.current = undefined; | ||
return reason; | ||
}); | ||
}, | ||
closeModal: () => { | ||
resultSubjectRef.current?.next({ type: "canceled" }); | ||
}, | ||
}), | ||
[] | ||
); | ||
|
||
return ( | ||
<ModalServiceContext.Provider value={service}> | ||
{children} | ||
{modalOptions && ( | ||
<Modal | ||
title={modalOptions.title} | ||
size={modalOptions.size} | ||
onClose={() => resultSubjectRef.current?.next({ type: "canceled" })} | ||
> | ||
<modalOptions.content | ||
onCancel={() => resultSubjectRef.current?.next({ type: "canceled" })} | ||
onClose={(reason) => resultSubjectRef.current?.next({ type: "closed", reason })} | ||
/> | ||
</Modal> | ||
)} | ||
</ModalServiceContext.Provider> | ||
); | ||
}; | ||
|
||
export const useModalService = () => { | ||
const context = useContext(ModalServiceContext); | ||
if (!context) { | ||
throw new Error("Can't use ModalService outside ModalServiceProvider"); | ||
} | ||
return context; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from "./ModalService"; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import React from "react"; | ||
|
||
import { ModalProps } from "components/Modal/Modal"; | ||
|
||
export interface ModalOptions<T> { | ||
title: ModalProps["title"]; | ||
size?: ModalProps["size"]; | ||
content: React.ComponentType<ModalContentProps<T>>; | ||
} | ||
|
||
export type ModalResult<T> = { type: "canceled" } | { type: "closed"; reason: T }; | ||
|
||
interface ModalContentProps<T> { | ||
onClose: (reason: T) => void; | ||
onCancel: () => void; | ||
} | ||
|
||
export interface ModalServiceContextType { | ||
openModal: <ResultType>(options: ModalOptions<ResultType>) => Promise<ModalResult<ResultType>>; | ||
closeModal: () => void; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -63,7 +63,7 @@ function useWebConnectionService() { | |
); | ||
} | ||
|
||
function useConnectionService() { | ||
export function useConnectionService() { | ||
const config = useConfig(); | ||
const middlewares = useDefaultRequestMiddlewares(); | ||
return useInitService(() => new ConnectionService(config.apiUrl, middlewares), [config.apiUrl, middlewares]); | ||
|
@@ -190,20 +190,11 @@ const useUpdateConnection = () => { | |
const service = useWebConnectionService(); | ||
const queryClient = useQueryClient(); | ||
|
||
return useMutation( | ||
(connectionUpdate: WebBackendConnectionUpdate) => { | ||
const withRefreshedCatalogCleaned = connectionUpdate.withRefreshedCatalog | ||
? { withRefreshedCatalog: connectionUpdate.withRefreshedCatalog } | ||
: null; | ||
Comment on lines
-195
to
-197
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do you think this was here in the first place? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not really. This was in there since 2 years, so I fear that knowledge is lost. Looking at the old code it seems this was a separate parameter to this hook earlier, and thus spreaded like this into it (trying to preventing actually setting the value when it was undefined), but it's really just guessing. |
||
|
||
return service.update({ ...connectionUpdate, ...withRefreshedCatalogCleaned }); | ||
return useMutation((connectionUpdate: WebBackendConnectionUpdate) => service.update(connectionUpdate), { | ||
onSuccess: (connection) => { | ||
queryClient.setQueryData(connectionsKeys.detail(connection.connectionId), connection); | ||
}, | ||
{ | ||
onSuccess: (connection) => { | ||
queryClient.setQueryData(connectionsKeys.detail(connection.connectionId), connection); | ||
}, | ||
} | ||
); | ||
}); | ||
}; | ||
|
||
const useConnectionList = (): ListConnection => { | ||
|
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
@@ -88,7 +88,6 @@ | |||||||||
"form.noNeed": "No need!", | ||||||||||
"form.reset": "Reset", | ||||||||||
"form.resetData": "Reset your data", | ||||||||||
"form.changedColumns": "You have changed which column is used to detect new records for a stream. You may want to reset the data in your stream.", | ||||||||||
"form.resetDataText": "Resetting your data will delete all the data for this connection in your destination and start syncs from scratch. Are you sure you want to do this?", | ||||||||||
"form.dockerError": "Could not find docker image", | ||||||||||
"form.edit": "Edit", | ||||||||||
|
@@ -106,8 +105,6 @@ | |||||||||
"form.destinationConnector": "Destination connector", | ||||||||||
"form.addItems": "Add", | ||||||||||
"form.items": "Items", | ||||||||||
"form.toSaveSchema": "To save the new schema, click on Save changes.", | ||||||||||
"form.noteStartSync": "Note that it will delete all the data in your destination and start syncing from scratch. ", | ||||||||||
"form.pkSelected": "{count, plural, =0 { } one {{items}} other {# keys selected}}", | ||||||||||
"form.url.error": "field must be a valid URL", | ||||||||||
"form.setupGuide": "Setup Guide", | ||||||||||
|
@@ -317,7 +314,12 @@ | |||||||||
"syncMode.full_refresh": "Full refresh", | ||||||||||
"syncMode.incremental": "Incremental", | ||||||||||
|
||||||||||
"connection.warningUpdateSchema": "WARNING! Updating the schema will delete all the data for this connection in your destination and start syncing from scratch.", | ||||||||||
"connection.resetModalTitle": "Stream configuration changed", | ||||||||||
"connection.streamResetHint": "Due to changes in the stream configuration the affected streams should be resetted. This will delete all data of those streams in the destination and sync it again. Skipping this might lead to unexpected behavior and is discouraged.", | ||||||||||
timroes marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||
"connection.streamFullResetHint": "Due to changes in the stream configuration all streams should be resetted. This will delete all data in the destination and sync it again. Skipping this might lead to unexpected behavior and is discouraged.", | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is 'stream' a term that users understand? I don't think it's necessarily intuitive that 'stream' corresponds to db table or API endpoint. My suggested wording:
timroes marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||
"connection.saveWithReset": "Reset affected streams (recommended)", | ||||||||||
"connection.saveWithFullReset": "Reset all streams (recommended)", | ||||||||||
"connection.save": "Save connection", | ||||||||||
"connection.title": "Connection", | ||||||||||
"connection.description": "<b>Connections</b> link Sources to Destinations.", | ||||||||||
"connection.fromTo": "{source} → {destination}", | ||||||||||
|
@@ -326,12 +328,10 @@ | |||||||||
"connection.testsFailed": "The connection tests failed.", | ||||||||||
"connection.destinationCheckSettings": "Check destination settings", | ||||||||||
"connection.sourceCheckSettings": "Check source settings", | ||||||||||
"connection.saveAndReset": "Save changes & reset data", | ||||||||||
"connection.destinationTestAgain": "Test destination connection again", | ||||||||||
"connection.sourceTestAgain": "Test source connection again", | ||||||||||
"connection.resetData": "Reset your data", | ||||||||||
"connection.updateSchema": "Refresh source schema", | ||||||||||
"connection.updateSchemaText": "WARNING! Updating the schema will delete all the data for this connection in your destination and start syncing from scratch. Are you sure you want to do this?", | ||||||||||
"connection.newConnection": "+ New connection", | ||||||||||
"connection.newConnectionTitle": "New connection", | ||||||||||
"connection.noConnections": "Connection list is empty", | ||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
@use "../../../../../scss/variables" as vars; | ||
|
||
.resetWarningModal { | ||
padding: vars.$spacing-xl; | ||
} | ||
|
||
.resetWarningModalButtons { | ||
display: flex; | ||
justify-content: flex-end; | ||
gap: vars.$spacing-md; | ||
margin-top: vars.$spacing-lg; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
webBackendUpdateConnectionNew
is temporary?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes it is; this endpoint was created so that we could merge backend changes related to this new flow in before the frontend changes were merged. We have a ticket here to remove this temporary endpoint after the launch of per-stream: #14733