Skip to content

Commit

Permalink
Merge branch 'master' into benbrown/docker-memoruy
Browse files Browse the repository at this point in the history
  • Loading branch information
a-b-r-o-w-n committed Dec 1, 2019
2 parents a7ab191 + ae7fa1d commit 7fc13cc
Show file tree
Hide file tree
Showing 82 changed files with 3,754 additions and 524 deletions.
41 changes: 37 additions & 4 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,41 @@
{
"version": "0.2.0",
"configurations": [
{
"type": "chrome",
"request": "attach",
"name": "Attach to Chrome",
"port": 9222,
"webRoot": "${workspaceFolder}"
},
{
"name": "LSP Server",
"type": "node",
"request": "launch",
"args": [
"${workspaceFolder}/Composer/packages/tools/language-servers/language-generation/demo/src/server.ts"
],
"runtimeArgs": [
"--nolazy",
"-r",
"${workspaceFolder}/Composer/node_modules/ts-node/register"
],
"sourceMaps": true,
"cwd": "${workspaceFolder}/Composer/packages/tools/language-servers/language-generation/demo/src",
"protocol": "inspector",
},
{
"type": "node",
"request": "launch",
"name": "Server: Launch",
"args": ["./build/server.js"],
"args": [
"./build/server.js"
],
"preLaunchTask": "server: build",
"restart": true,
"outFiles": ["./build/*"],
"outFiles": [
"./build/*"
],
"envFile": "${workspaceFolder}/Composer/packages/server/.env",
"outputCapture": "std",
"cwd": "${workspaceFolder}/Composer/packages/server"
Expand All @@ -20,8 +47,14 @@
"name": "Jest Debug",
"program": "${workspaceRoot}/Composer/node_modules/jest/bin/jest",
"stopOnEntry": false,
"args": ["--runInBand", "--env=jsdom", "--config=jest.config.js"],
"runtimeArgs": ["--inspect-brk"],
"args": [
"--runInBand",
"--env=jsdom",
"--config=jest.config.js"
],
"runtimeArgs": [
"--inspect-brk"
],
"cwd": "${workspaceRoot}/Composer/packages/server",
"sourceMaps": true,
"console": "integratedTerminal"
Expand Down
13 changes: 7 additions & 6 deletions Composer/cypress/integration/Breadcrumb.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ context('breadcrumb', () => {
});

function hasBreadcrumbItems(cy: Cypress.cy, items: (string | RegExp)[]) {
cy.findByTestId('Breadcrumb')
cy.get('[data-testid="Breadcrumb"]')
.last()
.get('li')
.should($li => {
items.forEach((item, idx) => {
Expand All @@ -37,21 +38,21 @@ context('breadcrumb', () => {
cy.findByText('__TestTodoSample.Main').click();
});

hasBreadcrumbItems(cy, ['__TestTodoSample']);
hasBreadcrumbItems(cy, ['__TestTodoSample.Main']);
});

it('can show event name in breadcrumb', () => {
cy.findByTestId('ProjectTree').within(() => {
cy.findByText('AddToDo').click();
cy.findByText('Dialog started (BeginDialog)').click();
cy.findByText('Dialog started').click();
});

hasBreadcrumbItems(cy, ['AddToDo', 'Dialog started (BeginDialog)']);
hasBreadcrumbItems(cy, ['AddToDo', 'Dialog started']);
});

it('can show action name in breadcrumb', () => {
cy.findByTestId('ProjectTree').within(() => {
cy.findByText('Greeting (ConversationUpdate)').click();
cy.findByText('Greeting').click();
});

// Click on an action
Expand All @@ -61,6 +62,6 @@ context('breadcrumb', () => {
});
});

hasBreadcrumbItems(cy, ['__TestTodoSample.Main', 'Greeting (ConversationUpdate)', 'Send a response']);
hasBreadcrumbItems(cy, ['__TestTodoSample.Main', 'Greeting', 'Send a response']);
});
});
4 changes: 2 additions & 2 deletions Composer/cypress/integration/CreateNewBot.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ context('Creating a new bot', () => {
cy.findByTestId('Create from template').click();
cy.findByTestId('TodoSample').click();
cy.findByTestId('NextStepButton').click();
cy.findByTestId('NewDialogName').type('{selectall}__TestNewProject{enter}');
cy.findByTestId('NewDialogName').type('{selectall}__TestNewProject2{enter}');
cy.findByTestId('ProjectTree').within(() => {
cy.findByText('__TestNewProject.Main').should('exist');
cy.findByText('__TestNewProject2.Main').should('exist');
cy.findByText('AddToDo').should('exist');
cy.findByText('ClearToDos').should('exist');
cy.findByText('DeleteToDo').should('exist');
Expand Down
1 change: 1 addition & 0 deletions Composer/cypress/integration/NotificationPage.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ context('Notification Page', () => {
beforeEach(() => {
cy.visit(Cypress.env('COMPOSER_URL'));
cy.createBot('TodoSample');
cy.visitPage('Notifications');
});

it('can show lg syntax error ', () => {
Expand Down
9 changes: 3 additions & 6 deletions Composer/cypress/integration/VisualDesigner.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,9 @@
// Licensed under the MIT License.

context('Visual Designer', () => {
before(() => {
beforeEach(() => {
cy.visit(Cypress.env('COMPOSER_URL'));
cy.createBot('TodoSample');
});

beforeEach(() => {
// Return to Main.dialog
cy.findByTestId('ProjectTree').within(() => {
cy.findByText('__TestTodoSample.Main').click();
Expand All @@ -16,11 +13,11 @@ context('Visual Designer', () => {

it('can find Visual Designer default trigger in container', () => {
cy.findByTestId('ProjectTree').within(() => {
cy.findByText('Greeting (ConversationUpdate)').click();
cy.findByText('Greeting').click();
});

cy.withinEditor('VisualEditor', () => {
cy.findByText('Trigger').should('exist');
cy.findByText('ConversationUpdate activity').should('exist');
});
});
});
6 changes: 6 additions & 0 deletions Composer/cypress/support/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,10 @@ Cypress.Commands.add('withinEditor', (editorName, cb) => {

Cypress.Commands.add('visitPage', page => {
cy.findByTestId(`LeftNav-CommandBarButton${page}`).click();
cy.wait(3000);
});

Cypress.on('uncaught:exception', (err, runnable) => {
console.log('uncaught exception', err);
return false;
});
1 change: 1 addition & 0 deletions Composer/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,6 @@ module.exports = {
'<rootDir>/packages/extensions/visual-designer',
'<rootDir>/packages/lib/code-editor',
'<rootDir>/packages/lib/shared',
'<rootDir>/packages/tools/language-servers/language-generation',
],
};
12 changes: 8 additions & 4 deletions Composer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,20 @@
"packages/extensions",
"packages/extensions/*",
"packages/lib",
"packages/lib/*"
"packages/lib/*",
"packages/tools",
"packages/tools/language-servers",
"packages/tools/language-servers/*"
],
"scripts": {
"build": "node scripts/begin.js && yarn build:prod",
"build:prod": "yarn build:lib && yarn build:extensions && yarn build:server && yarn build:client",
"build:dev": "yarn build:lib && yarn build:extensions",
"build:prod": "yarn build:dev && yarn build:server && yarn build:client",
"build:dev": "yarn build:tools && yarn build:lib && yarn build:extensions",
"build:lib": "yarn workspace @bfc/libs build:all",
"build:extensions": "yarn workspace @bfc/extensions build:all",
"build:server": "yarn workspace @bfc/server build",
"build:client": "yarn workspace @bfc/client build",
"build:tools": "yarn workspace @bfc/tools build:all",
"start": "cross-env NODE_ENV=production PORT=3000 yarn start:server",
"startall": "concurrently --kill-others-on-fail \"npm:runtime\" \"npm:start\"",
"start:dev": "concurrently \"npm:start:client\" \"npm:start:server:dev\"",
Expand All @@ -34,7 +38,7 @@
"test:coverage": "yarn test --coverage --no-cache --reporters=default",
"test:integration": "cypress run --browser chrome",
"test:integration:open": "cypress open",
"test:integration:clean": "rimraf TestBots/*",
"test:integration:clean": "rimraf ../MyBots/__Test*",
"lint": "wsrun --exclude-missing --collect-logs --report lint",
"lint:fix": "wsrun --exclude-missing --collect-logs --report lint:fix",
"typecheck": "concurrently --kill-others-on-fail \"npm:typecheck:*\"",
Expand Down
6 changes: 5 additions & 1 deletion Composer/packages/client/config/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,10 @@ module.exports = function(webpackEnv) {
// `web` extension prefixes have been added for better support
// for React Native Web.
extensions: paths.moduleFileExtensions.map(ext => `.${ext}`),
alias: {
// Support lsp code editor
vscode: require.resolve('monaco-languageclient/lib/vscode-compatibility'),
},
plugins: [
// Adds support for installing with Plug'n'Play, leading to faster installs and adding
// guards against forgotten dependencies and such.
Expand Down Expand Up @@ -402,7 +406,7 @@ module.exports = function(webpackEnv) {
plugins: [
new MonacoWebpackPlugin({
// available options are documented at https://github.com/Microsoft/monaco-editor-webpack-plugin#options
languages: ['markdown', 'botbuilderlg', 'json'],
languages: ['markdown', 'json'],
}),
// Generates an `index.html` file with the <script> injected.
new HtmlWebpackPlugin(
Expand Down
2 changes: 2 additions & 0 deletions Composer/packages/client/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ module.exports = {
// Any imports of .scss / .css files will instead import styleMock.js which is an empty object
'\\.(jpg|jpeg|png|svg|gif)$': '<rootDir>/__tests__/jestMocks/styleMock.js',
'\\.(s)?css$': '<rootDir>/__tests__/jestMocks/styleMock.js',
// lsp code editor
vscode$: 'monaco-languageclient/lib/vscode-compatibility',

// use commonjs modules for test so they do not need to be compiled
'office-ui-fabric-react/lib/(.*)$': 'office-ui-fabric-react/lib-commonjs/$1',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ export const TriggerCreationModal: React.FC<TriggerCreationModalProps> = props =
)}
{showIntentDropDown && (
<Dropdown
label={formatMessage('Which intent do you want to handle?')}
label={formatMessage('Which intent do you want to handle? (Optional)')}
options={intentOptions}
styles={dropdownStyles}
onChange={onSelectIntent}
Expand Down
106 changes: 87 additions & 19 deletions Composer/packages/client/src/pages/language-generation/code-editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,108 @@
// Licensed under the MIT License.

/* eslint-disable react/display-name */
import React, { useState, useEffect } from 'react';
import { LgEditor } from '@bfc/code-editor';
import React, { useState, useEffect, useMemo, useContext } from 'react';
import { LgEditor, LGOption } from '@bfc/code-editor';
import get from 'lodash/get';
import debounce from 'lodash/debounce';
import isEmpty from 'lodash/isEmpty';
import { CodeRange, LgFile } from '@bfc/shared';
import { Diagnostic } from 'botbuilder-lg';
import { LgFile } from '@bfc/shared';

import { StoreContext } from '../../store';
import * as lgUtil from '../../utils/lgUtil';

interface CodeEditorProps {
file: LgFile;
onChange: (value: string) => void;
codeRange?: Partial<CodeRange> | null;
template: lgUtil.Template | null;
}

// lsp server port should be same with composer/server port.
const lspServerPort = process.env.NODE_ENV === 'production' ? process.env.PORT || 3000 : 5000;
const lspServerPath = '/lg-language-server';

export default function CodeEditor(props: CodeEditorProps) {
const { file, codeRange } = props;
const onChange = debounce(props.onChange, 500);
const { actions } = useContext(StoreContext);
const { file, template } = props;
const [diagnostics, setDiagnostics] = useState(get(file, 'diagnostics', []));
const [content, setContent] = useState(get(file, 'content', ''));

const [content, setContent] = useState('');
const [errorMsg, setErrorMsg] = useState('');
const fileId = file && file.id;
const inlineMode = !!template;
useEffect(() => {
// reset content with file.content's initial state
if (isEmpty(file)) return;
setContent(file.content);
}, [fileId]);
const value = template ? get(template, 'Body', '') : get(file, 'content', '');
setContent(value);
}, [fileId, template]);

useEffect(() => {
const isInvalid = !lgUtil.isValid(diagnostics);
const text = isInvalid ? lgUtil.combineMessage(diagnostics) : '';
setErrorMsg(text);
}, [diagnostics]);

const updateLgTemplate = useMemo(
() =>
debounce((body: string) => {
const templateName = get(template, 'Name');
if (!templateName) return;
const payload = {
file,
templateName,
template: {
Name: templateName,
Parameters: get(template, 'Parameters'),
Body: body,
},
};
actions.updateLgTemplate(payload);
}, 500),
[file, template]
);

const updateLgFile = useMemo(
() =>
debounce((content: string) => {
const payload = {
id: file.id,
content,
};
actions.updateLgFile(payload);
}, 500),
[file]
);

// local content maybe invalid and should always sync real-time
// file.content assume to be load from server
const _onChange = value => {
setContent(value);
onChange(value);
const diagnostics = lgUtil.check(value);

let diagnostics: Diagnostic[] = [];
if (inlineMode) {
const content = get(file, 'content', '');
const templateName = get(template, 'Name', '');
try {
const newContent = lgUtil.updateTemplate(content, templateName, {
Name: templateName,
Parameters: get(template, 'Parameters'),
Body: value,
});
diagnostics = lgUtil.check(newContent);
updateLgTemplate(value);
} catch (error) {
setErrorMsg(error.message);
}
} else {
diagnostics = lgUtil.check(value);
updateLgFile(value);
}
setDiagnostics(diagnostics);
};

const isInvalid = !lgUtil.isValid(diagnostics);
const errorMsg = isInvalid ? lgUtil.combineMessage(diagnostics) : '';
const lgOption: LGOption = {
inline: inlineMode,
content: get(file, 'content', ''),
template: template ? template : undefined,
};

return (
<LgEditor
Expand All @@ -53,9 +116,14 @@ export default function CodeEditor(props: CodeEditorProps) {
lineDecorationsWidth: undefined,
lineNumbersMinChars: false,
}}
codeRange={codeRange || -1}
errorMsg={errorMsg}
hidePlaceholder={inlineMode}
value={content}
errorMsg={errorMsg}
lgOption={lgOption}
languageServer={{
port: Number(lspServerPort),
path: lspServerPath,
}}
onChange={_onChange}
/>
);
Expand Down
Loading

0 comments on commit 7fc13cc

Please sign in to comment.