-
Notifications
You must be signed in to change notification settings - Fork 375
feat: detect "old" bots and migrate them to new runtime #6526
Changes from 15 commits
d68993e
460453c
a5c8bfc
000b342
4f9808e
024868d
b27254e
7843021
b8addeb
7e26b4a
3658147
1a9cb5a
47fae76
fe8b9b2
bb59d34
68dc4fc
b5abb69
2479d54
e8169cc
d9e71f5
093811e
f5a89e0
f600dd6
d3f4e9e
414b47c
f187daf
42540e5
db140f0
11dbdb2
f3d0ced
9bf1a4f
2d0b8ad
e347d8a
1cf91c1
37294ae
b64606f
f8a6765
962d5de
9a64f2b
75b562b
92ae67f
6284c35
a4c1ff1
efb2418
ae55b50
66751eb
00deeef
4aef551
000eca2
541c45c
0ae895e
a114bd3
fe68602
cd36b16
21db3d7
f8d699f
be877bb
f342b87
23f938a
f9f3f86
a5c1f45
35f6696
0d26615
6e97e42
8549d11
ad59967
6278bab
88bc8a8
3aad038
0b340bb
c836d9d
6e6ea91
e15fde5
c4a87d6
cfb39a2
8399207
4b940d9
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 |
|---|---|---|
|
|
@@ -18,6 +18,7 @@ import { | |
| userSettingsState, | ||
| templateProjectsState, | ||
| } from '../../../recoilModel'; | ||
| import { localBotsDataSelector } from '../../../recoilModel/selectors/project'; | ||
| import Home from '../../../pages/home/Home'; | ||
| import { useProjectIdCache } from '../../../utils/hooks'; | ||
| import { ImportModal } from '../../ImportModal/ImportModal'; | ||
|
|
@@ -42,6 +43,7 @@ const CreationFlowV2: React.FC<CreationFlowProps> = () => { | |
| fetchRecentProjects, | ||
| openProject, | ||
| saveProjectAs, | ||
| migrateProjectTo, | ||
| fetchProjectById, | ||
| createNewBotV2, | ||
| fetchReadMe, | ||
|
|
@@ -51,6 +53,8 @@ const CreationFlowV2: React.FC<CreationFlowProps> = () => { | |
| const creationFlowStatus = useRecoilValue(creationFlowStatusState); | ||
| const projectId = useRecoilValue(currentProjectIdState); | ||
| const storages = useRecoilValue(storagesState); | ||
| const botProjects = useRecoilValue(localBotsDataSelector); | ||
| const botProject = botProjects.find((b) => b.projectId === projectId); | ||
| const focusedStorageFolder = useRecoilValue(focusedStorageFolderState); | ||
| const { appLocale } = useRecoilValue(userSettingsState); | ||
| const cachedProjectId = useProjectIdCache(); | ||
|
|
@@ -146,13 +150,21 @@ const CreationFlowV2: React.FC<CreationFlowProps> = () => { | |
| saveProjectAs(projectId, formData.name, formData.description, formData.location); | ||
| }; | ||
|
|
||
| const handleMigrate = (formData) => { | ||
| handleDismiss(); | ||
| setCreationFlowStatus(CreationFlowStatus.MIGRATE); | ||
| migrateProjectTo(projectId, formData.name, formData.description, formData.location); | ||
|
Member
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. If formData has type any, do you want to check name, description, and/or location have values before calling migrateProjectTo? |
||
| }; | ||
|
|
||
| const handleSubmit = async (formData, templateId: string) => { | ||
| handleDismiss(); | ||
| switch (creationFlowStatus) { | ||
| case CreationFlowStatus.SAVEAS: | ||
| handleSaveAs(formData); | ||
| break; | ||
|
|
||
| case CreationFlowStatus.MIGRATE: | ||
| handleMigrate(formData); | ||
| break; | ||
| default: | ||
| saveTemplateId(templateId); | ||
| await handleCreateNew(formData, templateId); | ||
|
|
@@ -205,6 +217,16 @@ const CreationFlowV2: React.FC<CreationFlowProps> = () => { | |
| onDismiss={handleDismiss} | ||
| onOpen={openBot} | ||
| /> | ||
| <DefineConversationV2 | ||
| createFolder={createFolder} | ||
| focusedStorageFolder={focusedStorageFolder} | ||
| path="migrate/:projectId" | ||
|
Member
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 not sure what the path is for but do you need to add a route to router.tsx for migration?
Contributor
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. Since this is is inside the creation flow I think this would take the creation route as prefix followed by migrate/:projectId as a sub routes |
||
| templateId={botProject?.name || 'migrated_project'} // templateId is used for default project name | ||
| updateFolder={updateFolder} | ||
| onCurrentPathUpdate={updateCurrentPath} | ||
| onDismiss={handleDismiss} | ||
| onSubmit={handleMigrate} | ||
| /> | ||
| <ImportModal path="import" /> | ||
| </Router> | ||
| </Fragment> | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,6 +5,7 @@ | |
| import formatMessage from 'format-message'; | ||
| import findIndex from 'lodash/findIndex'; | ||
| import { QnABotTemplateId, RootBotManagedProperties } from '@bfc/shared'; | ||
| import { OpenConfirmModal } from '@bfc/ui-shared'; | ||
| import get from 'lodash/get'; | ||
| import { CallbackInterface, useRecoilCallback } from 'recoil'; | ||
|
|
||
|
|
@@ -59,6 +60,7 @@ import { | |
| removeRecentProject, | ||
| resetBotStates, | ||
| saveProject, | ||
| migrateToV2, | ||
| } from './utils/project'; | ||
|
|
||
| export const projectDispatcher = () => { | ||
|
|
@@ -225,7 +227,28 @@ export const projectDispatcher = () => { | |
| set(botOpeningState, true); | ||
|
|
||
| await flushExistingTasks(callbackHelpers); | ||
| const { projectId, mainDialog } = await openRootBotAndSkillsByPath(callbackHelpers, path, storageId); | ||
| const { projectId, mainDialog, requiresMigrate } = await openRootBotAndSkillsByPath( | ||
| callbackHelpers, | ||
| path, | ||
| storageId | ||
| ); | ||
|
|
||
| if (requiresMigrate) { | ||
| if ( | ||
| await OpenConfirmModal( | ||
| formatMessage('Convert your project to the latest format'), | ||
| formatMessage( | ||
| 'This project was created in an older version of Composer. To open this project in Composer 2.0, we must copy your project and convert it to the latest format. Your original project will not be changed.' | ||
| ), | ||
| { confirmText: formatMessage('Convert') } | ||
| ) | ||
| ) { | ||
| navigateTo(`/v2/projects/migrate/${projectId}`); | ||
| } else { | ||
| navigateTo(`/home`); | ||
| } | ||
| return; | ||
| } | ||
|
|
||
| // ABS open Flow, update publishProfile & set alias for project after open project | ||
| if (absData) { | ||
|
|
@@ -281,8 +304,23 @@ export const projectDispatcher = () => { | |
| try { | ||
| await flushExistingTasks(callbackHelpers); | ||
| set(botOpeningState, true); | ||
| await openRootBotAndSkillsByProjectId(callbackHelpers, projectId); | ||
|
|
||
| const { requiresMigrate } = await openRootBotAndSkillsByProjectId(callbackHelpers, projectId); | ||
|
Member
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. can the
Contributor
Author
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. The reason I had this handled externally is that navigating inside these methods causes issues with the calling function. That is, where we call openRootBot*, we are doing lots of stuff AFTER it resolves. So if we navigate half-way, the remainder of that stuff is left in a weird place. Hence, returning this status allows us to STOP the process and navigate rather than continue... |
||
| if (requiresMigrate) { | ||
|
benbrown marked this conversation as resolved.
|
||
| if ( | ||
| await OpenConfirmModal( | ||
| formatMessage('Convert your project to the latest format'), | ||
| formatMessage( | ||
| 'This project was created in an older version of Composer. To open this project in Composer 2.0, we must copy your project and convert it to the latest format. Your original project will not be changed.' | ||
| ), | ||
| { confirmText: formatMessage('Convert') } | ||
| ) | ||
| ) { | ||
| navigateTo(`/v2/projects/migrate/${projectId}`); | ||
| } else { | ||
| navigateTo(`/home`); | ||
| } | ||
| return; | ||
| } | ||
| // Post project creation | ||
| set(projectMetaDataState(projectId), { | ||
| isRootBot: true, | ||
|
|
@@ -444,6 +482,27 @@ export const projectDispatcher = () => { | |
| } | ||
| ); | ||
|
|
||
| const migrateProjectTo = useRecoilCallback( | ||
| (callbackHelpers: CallbackInterface) => async (oldProjectId, name, description, location) => { | ||
| const { set, snapshot } = callbackHelpers; | ||
| try { | ||
| const dispatcher = await snapshot.getPromise(dispatcherState); | ||
| set(botOpeningState, true); | ||
|
|
||
| // starts the creation process and stores the jobID in state for tracking | ||
| const response = await migrateToV2(callbackHelpers, oldProjectId, name, description, location); | ||
|
|
||
| if (response.data.jobId) { | ||
| dispatcher.updateCreationMessage(response.data.jobId, '', '', '', ''); | ||
|
benbrown marked this conversation as resolved.
Outdated
|
||
| } | ||
| } catch (ex) { | ||
| set(botProjectIdsState, []); | ||
| handleProjectFailure(callbackHelpers, ex); | ||
| navigateTo('/home'); | ||
| } | ||
| } | ||
| ); | ||
|
|
||
| const deleteBot = useRecoilCallback((callbackHelpers: CallbackInterface) => async (projectId: string) => { | ||
| try { | ||
| const { reset } = callbackHelpers; | ||
|
|
@@ -611,6 +670,7 @@ export const projectDispatcher = () => { | |
| createNewBotV2, | ||
| deleteBot, | ||
| saveProjectAs, | ||
| migrateProjectTo, | ||
| fetchProjectById, | ||
| fetchRecentProjects, | ||
| setBotStatus, | ||
|
|
||
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.
handleDismiss sets the creation flow to CLOSE and then navigates home. Is that all synchronous? This then sets the status to MIGRATE. Do you want to only set the status to one state or does this need to go through the CLOSE state?