diff --git a/Composer/packages/client/src/pages/form-dialog/FormDialogPage.tsx b/Composer/packages/client/src/pages/form-dialog/FormDialogPage.tsx index 943f073b14..ef7fb1f8e7 100644 --- a/Composer/packages/client/src/pages/form-dialog/FormDialogPage.tsx +++ b/Composer/packages/client/src/pages/form-dialog/FormDialogPage.tsx @@ -27,10 +27,10 @@ const EmptyView = styled(Stack)({ opacity: 0.5, }); -type Props = RouteComponentProps<{ projectId: string; schemaId: string }>; +type Props = RouteComponentProps<{ projectId: string; skillId: string; schemaId: string }>; const FormDialogPage: React.FC = React.memo((props: Props) => { - const { projectId = '', schemaId = '' } = props; + const { projectId = '', skillId = '', schemaId = '' } = props; const formDialogSchemaIds = useRecoilValue(formDialogSchemaIdsState(projectId)); const formDialogLibraryTemplates = useRecoilValue(formDialogLibraryTemplatesState); const formDialogGenerationProgressing = useRecoilValue(formDialogGenerationProgressingState); @@ -90,7 +90,7 @@ const FormDialogPage: React.FC = React.memo((props: Props) => { const viewDialog = React.useCallback( (schemaId: string) => { if (schemaId) { - navigateToGeneratedDialog({ projectId, schemaId }); + navigateToGeneratedDialog({ projectId, skillId, schemaId }); } }, [navigateToGeneratedDialog, projectId] diff --git a/Composer/packages/client/src/pages/form-dialog/VisualFormDialogSchemaEditor.tsx b/Composer/packages/client/src/pages/form-dialog/VisualFormDialogSchemaEditor.tsx index 302931e36b..e5b0e3f9f5 100644 --- a/Composer/packages/client/src/pages/form-dialog/VisualFormDialogSchemaEditor.tsx +++ b/Composer/packages/client/src/pages/form-dialog/VisualFormDialogSchemaEditor.tsx @@ -3,6 +3,7 @@ import { JsonEditor } from '@bfc/code-editor'; import { FormDialogSchemaEditor } from '@bfc/form-dialogs'; +import { FileExtensions } from '@bfc/shared'; import styled from '@emotion/styled'; import { NeutralColors } from '@uifabric/fluent-theme'; import formatMessage from 'format-message'; @@ -113,7 +114,7 @@ export const VisualFormDialogSchemaEditor = React.memo((props: Props) => { editorId={`${projectId}:${schema.id}`} isGenerating={generationInProgress} schema={schema} - schemaExtension=".form-dialog" + schemaExtension={FileExtensions.FormDialogSchema} templates={templates} onGenerateDialog={onGenerate} onSchemaUpdated={onSchemaUpdated} diff --git a/Composer/packages/client/src/recoilModel/dispatchers/formDialogs.ts b/Composer/packages/client/src/recoilModel/dispatchers/formDialogs.ts index 65830803ab..5c6625bd00 100644 --- a/Composer/packages/client/src/recoilModel/dispatchers/formDialogs.ts +++ b/Composer/packages/client/src/recoilModel/dispatchers/formDialogs.ts @@ -110,8 +110,9 @@ export const formDialogsDispatcher = () => { } ); - const navigateToGeneratedDialog = ({ projectId, schemaId }) => { - navigate(`/bot/${projectId}/dialogs/${schemaId}`); + const navigateToGeneratedDialog = ({ projectId, skillId, schemaId }) => { + skillId = skillId || projectId; + navigate(`/bot/${projectId}/skill/${skillId}/dialogs/${schemaId}`); }; const navigateToFormDialogSchema = ({ projectId, schemaId }) => { diff --git a/Composer/packages/client/src/recoilModel/persistence/FilePersistence.ts b/Composer/packages/client/src/recoilModel/persistence/FilePersistence.ts index edc826e0e7..bf8f60b0f0 100644 --- a/Composer/packages/client/src/recoilModel/persistence/FilePersistence.ts +++ b/Composer/packages/client/src/recoilModel/persistence/FilePersistence.ts @@ -247,7 +247,7 @@ class FilePersistence { private getFormDialogSchemaFileChanges(current: FormDialogSchema[], previous: FormDialogSchema[]) { const changeItems = this.getDifferenceItems(current, previous); - const changes = this.getFileChanges(FileExtensions.FormDialog, changeItems); + const changes = this.getFileChanges(FileExtensions.FormDialogSchema, changeItems); return changes; } diff --git a/Composer/packages/client/src/recoilModel/persistence/types.ts b/Composer/packages/client/src/recoilModel/persistence/types.ts index 72d30086b9..329441d251 100644 --- a/Composer/packages/client/src/recoilModel/persistence/types.ts +++ b/Composer/packages/client/src/recoilModel/persistence/types.ts @@ -9,7 +9,7 @@ export enum ChangeType { export enum FileExtensions { Dialog = '.dialog', - FormDialog = '.form-dialog', + FormDialogSchema = '.form', DialogSchema = '.dialog.schema', Manifest = '.json', Lu = '.lu', diff --git a/Composer/packages/client/src/utils/pageLinks.ts b/Composer/packages/client/src/utils/pageLinks.ts index 6ddd0e3084..87b18fb3d9 100644 --- a/Composer/packages/client/src/utils/pageLinks.ts +++ b/Composer/packages/client/src/utils/pageLinks.ts @@ -77,7 +77,7 @@ export const topLinks = ( { to: `/bot/${projectId}/forms`, iconName: 'Table', - labelName: formatMessage('Forms'), + labelName: formatMessage('Forms (preview)'), exact: false, disabled: !botLoaded, }, diff --git a/Composer/packages/form-dialogs/src/components/property/FormDialogSchemaDetails.tsx b/Composer/packages/form-dialogs/src/components/property/FormDialogSchemaDetails.tsx index 3563efb2e0..916764b691 100644 --- a/Composer/packages/form-dialogs/src/components/property/FormDialogSchemaDetails.tsx +++ b/Composer/packages/form-dialogs/src/components/property/FormDialogSchemaDetails.tsx @@ -37,6 +37,11 @@ export const FormDialogSchemaDetails = () => { const lifetime = new Lifetime(); const clickOutsideLists = (e: MouseEvent) => { + const selection = window.getSelection(); + + // If click outside is the continuation of text select within the card, don't dismiss the card. + if (selection && selection.toString()) return; + const { x, y } = e; const elms = Array.prototype.slice.call( containerRef.current.querySelectorAll(`.${jsPropertyListClassName}`) || [] diff --git a/Composer/packages/form-dialogs/src/demo/DemoApp.tsx b/Composer/packages/form-dialogs/src/demo/DemoApp.tsx index a290485d27..7b63209f02 100644 --- a/Composer/packages/form-dialogs/src/demo/DemoApp.tsx +++ b/Composer/packages/form-dialogs/src/demo/DemoApp.tsx @@ -258,7 +258,7 @@ const InternalDemoApp = () => { allowUndo editorId={selectedItemId} schema={selectedItem} - schemaExtension=".form-dialog" + schemaExtension=".form" templates={templates} // eslint-disable-next-line no-console onGenerateDialog={() => {}} diff --git a/Composer/packages/lib/indexers/src/index.ts b/Composer/packages/lib/indexers/src/index.ts index 3b159c1ed0..b10cda85cf 100644 --- a/Composer/packages/lib/indexers/src/index.ts +++ b/Composer/packages/lib/indexers/src/index.ts @@ -30,7 +30,7 @@ class Indexer { { [FileExtensions.lg]: [], [FileExtensions.Lu]: [], - [FileExtensions.FormDialog]: [], + [FileExtensions.FormDialogSchema]: [], [FileExtensions.QnA]: [], [FileExtensions.Dialog]: [], [FileExtensions.DialogSchema]: [], @@ -95,7 +95,7 @@ class Indexer { skills: skillIndexer.index(skillContent, settings.skill), botProjectSpaceFiles: botProjectSpaceIndexer.index(result[FileExtensions.BotProjectSpace]), jsonSchemaFiles: jsonSchemaFileIndexer.index(result[FileExtensions.Json]), - formDialogSchemas: formDialogSchemaIndexer.index(result[FileExtensions.FormDialog]), + formDialogSchemas: formDialogSchemaIndexer.index(result[FileExtensions.FormDialogSchema]), recognizers: recognizerIndexer.index(recognizers), crossTrainConfig: crossTrainConfigIndexer.index(crossTrainConfigs), }; diff --git a/Composer/packages/lib/indexers/src/utils/fileExtensions.ts b/Composer/packages/lib/indexers/src/utils/fileExtensions.ts index ab08fc5259..45d6516e0d 100644 --- a/Composer/packages/lib/indexers/src/utils/fileExtensions.ts +++ b/Composer/packages/lib/indexers/src/utils/fileExtensions.ts @@ -3,7 +3,7 @@ export enum FileExtensions { Dialog = '.dialog', - FormDialog = '.form-dialog', + FormDialogSchema = '.form', DialogSchema = '.schema', Lu = '.lu', QnA = '.qna', diff --git a/Composer/packages/lib/shared/src/featureFlagUtils/index.ts b/Composer/packages/lib/shared/src/featureFlagUtils/index.ts index a624678f6a..2666de4076 100644 --- a/Composer/packages/lib/shared/src/featureFlagUtils/index.ts +++ b/Composer/packages/lib/shared/src/featureFlagUtils/index.ts @@ -28,7 +28,7 @@ export const getDefaultFeatureFlags = (): FeatureFlagMap => ({ FORM_DIALOG: { displayName: formatMessage('Show Form Dialog'), description: formatMessage('Show form dialog editor in the canvas'), - isHidden: true, + isHidden: false, enabled: false, }, REMOTE_TEMPLATE_CREATION_EXPERIENCE: { diff --git a/Composer/packages/server/src/locales/en-US.json b/Composer/packages/server/src/locales/en-US.json index c2c78404c6..8a3438d858 100644 --- a/Composer/packages/server/src/locales/en-US.json +++ b/Composer/packages/server/src/locales/en-US.json @@ -41,9 +41,6 @@ "a_valid_url_should_start_with_http_or_https_327b1a30": { "message": "A valid URL should start with http:// or https://" }, - "a_valid_url_should_start_with_http_or_https_d24b3591": { - "message": "A valid url should start with http:// or https://" - }, "about_70c18bba": { "message": "About" }, @@ -131,9 +128,6 @@ "add_a_welcome_message_9e1480b2": { "message": "Add a welcome message" }, - "add_additional_url_bdfac25d": { - "message": "Add additional URL" - }, "add_alternative_phrasing_17e0304c": { "message": "+ Add alternative phrasing" }, @@ -233,9 +227,6 @@ "any_string_f22dc2e1": { "message": "any string" }, - "append_choices_35c45a2d": { - "message": "Append choices" - }, "application_language_87691b6": { "message": "Application Language" }, @@ -389,6 +380,9 @@ "bot_configured_for_text_a67eca78": { "message": "Bot Configured for Text" }, + "bot_content_was_successfully_imported_5a07ae64": { + "message": "Bot content was successfully imported." + }, "bot_framework_composer_enables_developers_and_mult_ce0e42a9": { "message": "Bot Framework Composer enables developers and multi-disciplinary teams to build all kinds of conversational experiences, using the latest components from the Bot Framework: SDK, LG, LU, and declarative file formats, all without writing code." }, @@ -599,6 +593,12 @@ "connect_to_qna_knowledgebase_4b324132": { "message": "Connect to QnA Knowledgebase" }, + "connecting_to_b_source_b_to_import_bot_content_106cf675": { + "message": "Connecting to { source } to import bot content..." + }, + "connecting_to_b_targetname_b_to_import_bot_content_65d8db95": { + "message": "Connecting to { targetName } to import bot content..." + }, "content_1440204b": { "message": "Content" }, @@ -620,12 +620,12 @@ "copy_content_for_translation_7affbcbb": { "message": "Copy content for translation" }, + "copy_project_location_to_clipboard_eb85c474": { + "message": "Copy project location to clipboard" + }, "could_not_connect_to_storage_50411de0": { "message": "Could not connect to storage." }, - "could_not_init_plugin_1f1c29cd": { - "message": "Could not init plugin" - }, "couldn_t_complete_the_update_a337a359": { "message": "Couldn''t complete the update:" }, @@ -698,9 +698,6 @@ "create_kb_from_url_or_file_49ad6671": { "message": "Create KB from URL or file" }, - "create_knowledge_base_db6d66c4": { - "message": "Create knowledge base" - }, "create_knowledge_base_from_scratch_afe4d2a2": { "message": "Create knowledge base from scratch" }, @@ -752,6 +749,9 @@ "data_loading_4c9bb9f6": { "message": "Data loading..." }, + "data_transferring_between_services_c0971544": { + "message": "Data transferring between services" + }, "date_ee500367": { "message": "Date" }, @@ -887,6 +887,9 @@ "display_lines_that_extends_beyond_the_width_of_the_9e500f3c": { "message": "Display lines that extends beyond the width of the editor on the next line." }, + "do_you_want_to_update_b_existingprojectname_b_c34014f": { + "message": "Do you want to update { existingProjectName }" + }, "do_you_wish_to_continue_96469eaf": { "message": "Do you wish to continue?" }, @@ -1283,15 +1286,27 @@ "if_this_problem_persists_please_file_an_issue_on_6fbc8e2b": { "message": "If this problem persists, please file an issue on" }, + "if_turned_on_then_externally_stored_templates_will_3f487651": { + "message": "If turned on then externally stored templates will be selectable in the new bot flow template list" + }, "if_you_already_have_a_luis_account_provide_the_inf_bede07a4": { "message": "If you already have a LUIS account, provide the information below. If you do not have an account yet, create a (free) account first." }, "if_you_already_have_a_qna_account_provide_the_info_466d6a4b": { "message": "If you already have a QNA account, provide the information below. If you do not have an account yet, create a (free) account first." }, + "import_as_new_35630827": { + "message": "Import as new" + }, "import_schema_75659c5f": { "message": "Import schema" }, + "importing_b_botname_b_from_sourcename_f7410826": { + "message": "Importing { botName } from { sourceName }..." + }, + "importing_bot_content_from_targetname_6da78f15": { + "message": "Importing bot content from { targetName }..." + }, "in_production_5a70b8b4": { "message": "In production" }, @@ -1418,9 +1433,6 @@ "learn_more_about_knowledge_base_sources_24369b09": { "message": "Learn more about knowledge base sources. " }, - "learn_more_about_qna_maker_skus_998c567": { - "message": "Learn more about QnA Maker SKUs." - }, "learn_more_about_title_d1d3edbe": { "message": "Learn more about { title }" }, @@ -1907,8 +1919,8 @@ "please_select_an_activity_type_92f4a8a1": { "message": "Please select an activity type" }, - "populate_your_knowledge_base_bb2d3605": { - "message": "Populate your Knowledge Base" + "powervirtualagents_logo_11858924": { + "message": "PowerVirtualAgents Logo" }, "press_enter_to_add_this_item_or_tab_to_move_to_the_6beb8a14": { "message": "press Enter to add this item or Tab to move to the next interactive element" @@ -1922,6 +1934,9 @@ "previous_bd2ac015": { "message": "Previous" }, + "previous_bot_content_has_been_backed_up_to_d6d23960": { + "message": " Previous bot content has been backed up to:" + }, "previous_folder_e7eeb306": { "message": "previous folder" }, @@ -2021,6 +2036,9 @@ "publishing_d63a8f2d": { "message": "Publishing" }, + "pull_from_selected_profile_b5c635ec": { + "message": "Pull from selected profile" + }, "qna_28ee5e26": { "message": "QnA" }, @@ -2090,9 +2108,6 @@ "regex_intent_is_already_defined_df095c1f": { "message": "RegEx { intent } is already defined" }, - "regular_expression_855557bf": { - "message": "Regular Expression" - }, "regular_expression_recognizer_44664557": { "message": "Regular expression recognizer" }, @@ -2102,6 +2117,9 @@ "reloading_49d2f661": { "message": "Reloading" }, + "remote_templates_a23c242d": { + "message": "Remote templates" + }, "remove_f47dc62a": { "message": "Remove" }, @@ -2285,6 +2303,9 @@ "set_up_your_bot_75009578": { "message": "Set up your bot" }, + "setting_things_up_8022afe8": { + "message": "Setting things up..." + }, "settings_5aa0fd0c": { "message": "Settings" }, @@ -2339,8 +2360,11 @@ "skills_49cccd6a": { "message": "Skills" }, - "skip_this_step_to_add_questions_and_answers_manual_ed1b9f80": { - "message": "Skip this step to add questions and answers manually after creation. The number of sources and file size you can add depends on the QnA service SKU you choose. " + "something_happened_while_attempting_to_pull_e_952c7afe": { + "message": "Something happened while attempting to pull: { e }" + }, + "something_went_wrong_d238c551": { + "message": "Something went wrong" }, "sorry_something_went_wrong_with_connecting_bot_run_7d6785e3": { "message": "Sorry, something went wrong with connecting bot runtime" @@ -2357,12 +2381,12 @@ "spaces_and_special_characters_are_not_allowed_20d47684": { "message": "Spaces and special characters are not allowed." }, - "spaces_and_special_characters_are_not_allowed_use__2a61c454": { - "message": "Spaces and special characters are not allowed. Use letters, numbers, -, or _ and don''t use number at the beginning." - }, "spaces_and_special_characters_are_not_allowed_use__48acec3c": { "message": "Spaces and special characters are not allowed. Use letters, numbers, -, or _." }, + "spaces_and_special_characters_are_not_allowed_use__d24a8636": { + "message": "Spaces and special characters are not allowed. Use letters, numbers, -, or _, and begin the name with a letter." + }, "specify_a_name_and_description_for_your_new_dialog_86eb3130": { "message": "Specify a name and description for your new dialog." }, @@ -2498,6 +2522,12 @@ "there_was_an_error_74ed3c58": { "message": "There was an error" }, + "there_was_an_unexpected_error_importing_bot_conten_cac97236": { + "message": "There was an unexpected error importing bot content to { botName }" + }, + "there_was_an_unexpected_error_pulling_from_publish_c3fbefa4": { + "message": "There was an unexpected error pulling from publish profile { selectedTargetName }" + }, "there_was_error_creating_your_kb_53b31ff3": { "message": "There was error creating your KB" }, @@ -2543,9 +2573,6 @@ "this_trigger_type_is_not_supported_by_the_regex_re_dc3eefa2": { "message": "This trigger type is not supported by the RegEx recognizer. To ensure this trigger is fired, change the recognizer type." }, - "this_url_is_duplicated_a0768f44": { - "message": "This url is duplicated" - }, "this_version_of_the_content_is_out_of_date_and_you_5e878f29": { "message": "This version of the content is out of date, and your last change was rejected. The content will be automatically refreshed." }, @@ -2657,9 +2684,6 @@ "typing_activity_6b634ae": { "message": "Typing activity" }, - "unable_to_determine_recognizer_type_from_data_valu_2960f526": { - "message": "Unable to determine recognizer type from data: { value }" - }, "undo_a7be8fef": { "message": "Undo" }, @@ -2684,6 +2708,9 @@ "unused_8d193e3": { "message": "Unused" }, + "update_4d8ee62": { + "message": "Update" + }, "update_a_an_activity_previously_sent_during_the_co_f0619cca": { "message": "Update a an activity previously sent during the conversation" }, @@ -2711,12 +2738,12 @@ "update_scripts_c58771a2": { "message": "Update Scripts" }, + "updating_existingprojectname_will_overwrite_the_cu_1e649e50": { + "message": "Updating { existingProjectName } will overwrite the current bot content and create a backup." + }, "updating_scripts_e17a5722": { "message": "Updating scripts... " }, - "url_22a5f3b8": { - "message": "URL" - }, "url_8c4ff7d2": { "message": "Url" }, diff --git a/Composer/packages/server/src/models/bot/botProject.ts b/Composer/packages/server/src/models/bot/botProject.ts index 7ea594b0c9..061814e8b6 100644 --- a/Composer/packages/server/src/models/bot/botProject.ts +++ b/Composer/packages/server/src/models/bot/botProject.ts @@ -107,7 +107,7 @@ export class BotProject implements IBotProject { public get formDialogSchemaFiles() { const files: FileInfo[] = []; this.files.forEach((file) => { - if (file.name.endsWith('.form-dialog')) { + if (file.name.endsWith(FileExtensions.FormDialogSchema)) { files.push(file); } }); @@ -567,11 +567,22 @@ export class BotProject implements IBotProject { console.log(`${type} - ${message}`); }; + // fix casing for case-sensitive schema paths + const schemaLocale = defaultLocale + .replace(/en-us/i, 'en-US') + .replace(/en-us-pseudo/i, 'en-US-pseudo') + .replace(/zh-hans/i, 'zh-Hans') + .replace(/zh-hant/i, 'zh-Hant') + .replace(/pt-br/i, 'pt-BR') + .replace(/pt-pt/i, 'pt-PT'); + + const metaSchema = `https://raw.githubusercontent.com/microsoft/BotFramework-Composer/main/Composer/packages/server/schemas/sdk.${schemaLocale}.schema`; + const generateParams = { schemaPath, prefix: name, outDir, - metaSchema: undefined, + metaSchema: metaSchema, allLocales: undefined, templateDirs: templateDirs || [], force: false, @@ -757,7 +768,7 @@ export class BotProject implements IBotProject { const patterns = [ '**/*.dialog', '**/*.dialog.schema', - '**/*.form-dialog', + '**/*.form', '**/*.lg', '**/*.lu', '**/*.qna', @@ -778,7 +789,14 @@ export class BotProject implements IBotProject { // deployment process const root = this.dataDir; const paths = await this.fileStorage.glob( - [pattern, '!(generated/**)', '!(runtime/**)', '!(scripts/**)', '!(settings/appsettings.json)'], + [ + pattern, + '!(generated/**)', + '!(runtime/**)', + '!(scripts/**)', + '!(settings/appsettings.json)', + '!(**/luconfig.json)', + ], root ); diff --git a/Composer/packages/types/src/indexers.ts b/Composer/packages/types/src/indexers.ts index 538d0d9bea..39d7522f58 100644 --- a/Composer/packages/types/src/indexers.ts +++ b/Composer/packages/types/src/indexers.ts @@ -10,13 +10,13 @@ import { DialogSetting } from './index'; export enum FileExtensions { Dialog = '.dialog', DialogSchema = '.schema', + FormDialogSchema = '.form', Manifest = '.json', Lu = '.lu', Lg = '.lg', Qna = '.qna', SourceQnA = '.source.qna', Setting = 'appsettings.json', - FormDialogSchema = '.form-dialog', BotProject = '.botproj', Json = '.json', }