Skip to content
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

chore: refactor lg page route & url #1756

Merged
merged 18 commits into from
Dec 20, 2019
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@

/* eslint-disable react/display-name */
import React, { useState, useEffect, useMemo, useContext, useCallback } from 'react';
import { LgEditor, LGOption } from '@bfc/code-editor';
import { LgEditor } from '@bfc/code-editor';
import get from 'lodash/get';
import debounce from 'lodash/debounce';
import isEmpty from 'lodash/isEmpty';
import { editor } from '@bfcomposer/monaco-editor/esm/vs/editor/editor.api';
import { lgIndexer, Diagnostic } from '@bfc/indexers';
import { lgIndexer, combineMessage, isValid } from '@bfc/indexers';
import { RouteComponentProps } from '@reach/router';
import querystring from 'query-string';

import { StoreContext } from '../../store';
import * as lgUtil from '../../utils/lgUtil';
Expand All @@ -25,28 +26,28 @@ interface CodeEditorProps extends RouteComponentProps<{}> {
const CodeEditor: React.FC<CodeEditorProps> = props => {
const { actions, state } = useContext(StoreContext);
const { lgFiles } = state;
const file = lgFiles.length ? lgFiles[0] : null;
const { fileId } = props;
const file = lgFiles?.find(({ id }) => id === 'common');
const [diagnostics, setDiagnostics] = useState(get(file, 'diagnostics', []));
const [content, setContent] = useState('');
const [errorMsg, setErrorMsg] = useState('');
const [lgEditor, setLgEditor] = useState<editor.IStandaloneCodeEditor | null>(null);

const search = props.location ? props.location.search : '';
const templateMatched = /^\?t=([-\w]+)/.exec(search);
const templateId = templateMatched ? decodeURIComponent(templateMatched[1]) : undefined;
const template = templateId && file ? file.templates.find(({ name }) => name === templateId) : undefined;
const search = props?.location?.search ?? '';
zhixzhan marked this conversation as resolved.
Show resolved Hide resolved
const searchTemplateName = querystring.parse(search).t;
const templateId = Array.isArray(searchTemplateName) ? searchTemplateName[0] : searchTemplateName;
const template = templateId && file && file.templates.find(({ name }) => name === templateId);

const hash = props.location ? props.location.hash : '';
const lineMatched = /L(\d+)/g.exec(hash);
const hash = props?.location?.hash;
const lineMatched = hash && /L(\d+)/g.exec(hash);
zhixzhan marked this conversation as resolved.
Show resolved Hide resolved
const line = lineMatched ? +lineMatched[1] : undefined;

const fileId = (file && file.id) || 'common';
const inlineMode = !!template;

useEffect(() => {
// reset content with file.content's initial state
if (isEmpty(file)) return;
const value = template ? get(template, 'body', '') : get(file, 'content', '');
if (!file || isEmpty(file)) return;
const value = template ? template.body : file.content;
setContent(value);
}, [fileId, templateId]);

Expand All @@ -56,6 +57,7 @@ const CodeEditor: React.FC<CodeEditorProps> = props => {
? diagnostics.filter(d => {
return (
d.range &&
template.range &&
d.range.start.line >= template.range.startLineNumber &&
d.range.end.line <= template.range.endLineNumber
);
Expand All @@ -67,9 +69,9 @@ const CodeEditor: React.FC<CodeEditorProps> = props => {
setErrorMsg(text);
}, [diagnostics]);

const editorDidMount = useCallback((lgEditor: editor.IStandaloneCodeEditor) => {
const editorDidMount = (lgEditor: editor.IStandaloneCodeEditor) => {
setLgEditor(lgEditor);
}, []);
};

useEffect(() => {
if (lgEditor && line !== undefined) {
Expand All @@ -84,14 +86,14 @@ const CodeEditor: React.FC<CodeEditorProps> = props => {
const updateLgTemplate = useMemo(
() =>
debounce((body: string) => {
const templateName = get(template, 'name');
if (!templateName) return;
if (!file || !template) return;
const { name, parameters } = template;
const payload = {
file,
templateName,
templateName: name,
template: {
name: templateName,
parameters: get(template, 'parameters'),
name,
parameters,
body,
},
};
Expand All @@ -103,8 +105,10 @@ const CodeEditor: React.FC<CodeEditorProps> = props => {
const updateLgFile = useMemo(
() =>
debounce((content: string) => {
if (!file) return;
const { id } = file;
const payload = {
id: fileId,
id,
content,
};
actions.updateLgFile(payload);
Expand All @@ -115,36 +119,38 @@ const CodeEditor: React.FC<CodeEditorProps> = props => {
const _onChange = useCallback(
value => {
setContent(value);

let diagnostics: Diagnostic[] = [];
if (!file) return;
const { id } = file;
if (inlineMode) {
const content = get(file, 'content', '');
const templateName = get(template, 'name', '');
if (!template) return;
const { name, parameters } = template;
const { content } = file;
try {
const newContent = lgUtil.updateTemplate(content, templateName, {
name: templateName,
parameters: get(template, 'parameters'),
const newContent = lgUtil.updateTemplate(content, name, {
name,
parameters,
body: value,
});
diagnostics = check(newContent, fileId);
setDiagnostics(check(newContent, id));
updateLgTemplate(value);
} catch (error) {
setErrorMsg(error.message);
}
} else {
diagnostics = check(value, fileId);
setDiagnostics(check(value, id));
updateLgFile(value);
}
setDiagnostics(diagnostics);
},
[file, template]
);

const lgOption: LGOption = {
inline: inlineMode,
content: get(file, 'content', ''),
template,
};
const lgOption = template
? {
inline: inlineMode,
content: file?.content ?? '',
zhixzhan marked this conversation as resolved.
Show resolved Hide resolved
template,
}
: undefined;

return (
<LgEditor
Expand Down
25 changes: 13 additions & 12 deletions Composer/packages/client/src/pages/language-generation/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

/** @jsx jsx */
import { jsx } from '@emotion/core';
import React, { useContext, Fragment, useMemo, useCallback, Suspense } from 'react';
import React, { useContext, Fragment, useMemo, useCallback, Suspense, useEffect } from 'react';
import formatMessage from 'format-message';
import { Toggle } from 'office-ui-fabric-react/lib/Toggle';
import { Nav, INavLinkGroup, INavLink } from 'office-ui-fabric-react/lib/Nav';
Expand Down Expand Up @@ -35,7 +35,12 @@ const LGPage: React.FC<RouteComponentProps> = props => {
const matched = /^\/language-generation\/(\w+)/.exec(path.replace(/edit(\/)*$/, ''));
const fileId = matched ? matched[1] : '';
const edit = /edit(\/)*$/.test(path);
zhixzhan marked this conversation as resolved.
Show resolved Hide resolved
const lgFile = lgFiles.length ? lgFiles[0] : null;
const file = lgFiles?.find(({ id }) => id === 'common');

useEffect(() => {
// fileId not found, redirect to common
if (!fileId) navigateTo('/language-generation/common');
zhixzhan marked this conversation as resolved.
Show resolved Hide resolved
}, [fileId]);

const navLinks = useMemo<INavLinkGroup[]>(() => {
const subLinks = dialogs.reduce<INavLink>((result, file) => {
Expand Down Expand Up @@ -63,8 +68,8 @@ const LGPage: React.FC<RouteComponentProps> = props => {
{
links: [
{
id: '_all',
key: '_all',
id: 'common',
key: 'common',
name: 'All',
url: '',
isExpanded: true,
Expand All @@ -77,8 +82,7 @@ const LGPage: React.FC<RouteComponentProps> = props => {

const onSelect = useCallback(
id => {
let url = '/language-generation';
if (id !== '_all') url += `/${id}`;
let url = `/language-generation/${id}`;
if (edit) url += `/edit`;
navigateTo(url);
},
Expand All @@ -87,8 +91,7 @@ const LGPage: React.FC<RouteComponentProps> = props => {

const onToggleEditMode = useCallback(
(_e, checked) => {
let url = '/language-generation';
if (fileId) url += `/${fileId}`;
let url = `/language-generation/${fileId}`;
if (checked) url += `/edit`;
navigateTo(url);
},
Expand Down Expand Up @@ -144,22 +147,20 @@ const LGPage: React.FC<RouteComponentProps> = props => {
backgroundColor: 'transparent',
},
}}
selectedKey={fileId ? fileId : '_all'}
selectedKey={fileId}
groups={navLinks}
className={'dialogNavTree'}
data-testid={'dialogNavTree'}
/>
</div>
</Tree>
</div>
{lgFile && (
{file && (
<div css={contentEditor}>
<Suspense fallback={<LoadingSpinner />}>
<Router primary={false} component={Fragment}>
<CodeEditor path="edit" />
<CodeEditor path=":fileId/edit" />
a-b-r-o-w-n marked this conversation as resolved.
Show resolved Hide resolved
<TableView path=":fileId" />
<TableView default />
</Router>
</Suspense>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,8 @@ import { ScrollablePane, ScrollbarVisibility } from 'office-ui-fabric-react/lib/
import { Sticky, StickyPositionType } from 'office-ui-fabric-react/lib/Sticky';
import formatMessage from 'format-message';
import { NeutralColors, FontSizes } from '@uifabric/fluent-theme';
import { LGTemplate, LGParser } from 'botbuilder-lg';
import get from 'lodash/get';
import { RouteComponentProps } from '@reach/router';
import { LgTemplate } from '@bfc/indexers';

import { StoreContext } from '../../store';
import { increaseNameUtilNotExist } from '../../utils/lgUtil';
Expand All @@ -32,29 +31,23 @@ const TableView: React.FC<TableViewProps> = props => {
const { state, actions } = useContext(StoreContext);
const { dialogs, lgFiles } = state;
const { fileId } = props;
const file = lgFiles?.find(({ id }) => id === 'common');
const createLgTemplate = useRef(debounce(actions.createLgTemplate, 500)).current;
const copyLgTemplate = useRef(debounce(actions.copyLgTemplate, 500)).current;
const removeLgTemplate = useRef(debounce(actions.removeLgTemplate, 500)).current;
const [templates, setTemplates] = useState<LGTemplate[]>([]);
const [templates, setTemplates] = useState<LgTemplate[]>([]);
const listRef = useRef(null);

const lgFile = lgFiles.length ? lgFiles[0] : null;
const activeDialog = dialogs.find(({ id }) => id === fileId);

useEffect(() => {
if (!lgFile || isEmpty(lgFile)) return;
let allTemplates: LGTemplate[] = [];
try {
const resource = LGParser.parse(lgFile.content, '');
allTemplates = get(resource, 'templates', []);
} catch (err) {
// err already be handled in diagnostics
}
if (!file || isEmpty(file)) return;
const allTemplates = file.templates;

if (!activeDialog) {
setTemplates(allTemplates);
} else {
const dialogsTemplates: LGTemplate[] = [];
const dialogsTemplates: LgTemplate[] = [];
activeDialog.lgTemplates.forEach(item => {
const template = allTemplates.find(t => t.name === item);
if (template) {
Expand All @@ -63,55 +56,52 @@ const TableView: React.FC<TableViewProps> = props => {
});
setTemplates(dialogsTemplates);
}
}, [lgFile, activeDialog]);
}, [file, activeDialog]);

const onClickEdit = useCallback(
(template: LGTemplate) => {
(template: LgTemplate) => {
const { name } = template;
let url = '/language-generation';
if (fileId) url += `/${fileId}`;
url += `/edit?t=${encodeURIComponent(name)}`;
navigateTo(url);
navigateTo(`/language-generation/${fileId}/edit?t=${encodeURIComponent(name)}`);
},
[fileId]
);

const onCreateNewTemplate = useCallback(() => {
const newName = increaseNameUtilNotExist(templates, 'TemplateName');
const payload = {
file: lgFile,
file,
template: {
name: newName,
body: '-TemplateValue',
},
};
createLgTemplate(payload);
}, [templates, lgFile]);
}, [templates, file]);

const onRemoveTemplate = useCallback(
index => {
const payload = {
file: lgFile,
file,
templateName: templates[index].name,
};

removeLgTemplate(payload);
},
[templates, lgFile]
[templates, file]
);

const onCopyTemplate = useCallback(
index => {
const name = templates[index].name;
const resolvedName = increaseNameUtilNotExist(templates, `${name}_Copy`);
const payload = {
file: lgFile,
file,
fromTemplateName: name,
toTemplateName: resolvedName,
};
copyLgTemplate(payload);
},
[templates, lgFile]
[templates, file]
);

const getTemplatesMoreButtons = useCallback(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { convertDialogDiagnosticToUrl } from './../../utils/navigation';

const navigations = {
lg: (item: INotification) => {
navigateTo(`/language-generation/edit#L${item.diagnostic.range?.start.line || 0}`);
navigateTo(`/language-generation/${item.id}/edit#L${item.diagnostic.range?.start.line || 0}`);
},
lu: (item: INotification) => {
navigateTo(`/dialogs/${item.id}`);
Expand Down
Loading