Skip to content
This repository was archived by the owner on Jul 9, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
1cf8239
per slot dialog settings with optional obfucate
hailiu2586 Oct 16, 2019
ea33bf1
switch to choice group instead of dropdown
hailiu2586 Oct 16, 2019
9e95a79
use createPortal to project show-keys toggle
hailiu2586 Oct 17, 2019
62fd08b
Merge branch 'master' into hailiu/settings-ui
hailiu2586 Oct 17, 2019
13067b8
fix integration test for breadcrumb
hailiu2586 Oct 17, 2019
1b55347
use formatMessage for textual content
hailiu2586 Oct 17, 2019
9df430b
change text content
hailiu2586 Oct 17, 2019
f305d61
hide settings by default
hailiu2586 Oct 18, 2019
2b03f41
fix typo
hailiu2586 Oct 18, 2019
a833af3
Merge branch 'master' into hailiu/settings-ui
hailiu2586 Oct 18, 2019
5f030e6
fix lint and test:coverage
hailiu2586 Oct 18, 2019
3ce4433
fix test:coerage
hailiu2586 Oct 18, 2019
de09379
fix build
hailiu2586 Oct 18, 2019
c060771
Merge branch 'master' into hailiu/settings-ui
hailiu2586 Oct 18, 2019
8ed0bd9
udpate copy text
hailiu2586 Oct 18, 2019
84dd0c4
Update Composer/packages/client/src/utils/objUtil.ts
hailiu2586 Oct 18, 2019
5b9ee8e
fix hosted routes
hailiu2586 Oct 18, 2019
7f55036
fix open bot emulator
hailiu2586 Oct 19, 2019
5559c59
refactor cross frame state data
hailiu2586 Oct 21, 2019
197ebe7
Merge branch 'master' into hailiu/settings-ui
hailiu2586 Oct 21, 2019
f4d7231
fix setDialogSettingsSlot
hailiu2586 Oct 21, 2019
55d2db0
fix args order'
hailiu2586 Oct 21, 2019
1840d7a
add save button to hosted settings edit UI
hailiu2586 Oct 21, 2019
9fc9500
clean up obfuscate
hailiu2586 Oct 21, 2019
49df0fb
remove code-mirror
hailiu2586 Oct 21, 2019
6538362
Merge branch 'master' into hailiu/settings-ui
a-b-r-o-w-n Oct 22, 2019
18c141e
convert to css-in-js
a-b-r-o-w-n Oct 22, 2019
2505026
Merge branch 'master' into hailiu/settings-ui
a-b-r-o-w-n Oct 22, 2019
e8c8892
add hosted to ShellData type
a-b-r-o-w-n Oct 22, 2019
ac699c5
fix lint issue
hailiu2586 Oct 22, 2019
d52d698
add emotion babel plugin for test
a-b-r-o-w-n Oct 23, 2019
d8b0942
require jsx pragma
a-b-r-o-w-n Oct 23, 2019
5bcc37e
Merge branch 'master' into hailiu/settings-ui
hailiu2586 Oct 23, 2019
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
2 changes: 1 addition & 1 deletion Composer/cypress/integration/Breadcrumb.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ context('breadcrumb', () => {
it('can show action name in breadcrumb', () => {
cy.wait(100);
cy.get('[data-testid="ProjectTree"]').within(() => {
cy.getByText('Handle ConversationUpdate').click();
cy.getByText('Handle an Event: BeginDialog').click();
cy.wait(500);
});

Expand Down
3 changes: 3 additions & 0 deletions Composer/packages/client/src/ShellApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import * as lgUtil from './utils/lgUtil';
import { StoreContext } from './store';
import ApiClient from './messenger/ApiClient';
import { getDialogData, setDialogData, sanitizeDialogData } from './utils';
import { isAbsHosted } from './utils/envUtil';
import { OpenAlertModal, DialogStyle } from './components/Modal';
import { getFocusPath, navigateTo } from './utils/navigation';
import { DialogInfo, LgFile, LuFile, BotSchemas } from './store/types';
Expand All @@ -28,6 +29,7 @@ export interface ShellData {
dialogId: string;
focusedEvent: string;
focusedSteps: string[];
hosted: boolean;
focusedTab?: string;
}

Expand Down Expand Up @@ -181,6 +183,7 @@ export const ShellApi: React.FC = () => {
focusedEvent: selected,
focusedSteps: focused ? [focused] : selected ? [selected] : [],
focusedTab: promptTab,
hosted: !!isAbsHosted(),
};
}

Expand Down
3 changes: 1 addition & 2 deletions Composer/packages/client/src/TestController.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { bot, botButton, calloutLabel, calloutDescription, calloutContainer } fr
import { BotStatus, LuisConfig, Text } from './constants';
import { PublishLuisDialog } from './publishDialog';
import { OpenAlertModal, DialogStyle } from './components/Modal';
import { isAbsHosted } from './utils/envUtil';
import { getReferredFiles } from './utils/luUtil';
import { DialogInfo } from './store/types';

Expand All @@ -37,8 +38,6 @@ const STATE = {
SUCCESS: 2,
};

const isAbsHosted = () => process.env.COMPOSER_AUTH_PROVIDER === 'abs-h';

export const TestController: React.FC = () => {
const { state, actions } = useContext(StoreContext);
const [modalOpen, setModalOpen] = useState(false);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import formatMessage from 'format-message';
import { ChoiceGroup } from 'office-ui-fabric-react/lib/ChoiceGroup';
import { Link } from 'office-ui-fabric-react/lib/Link';
import { Toggle } from 'office-ui-fabric-react/lib/Toggle';
import React, { useState, useContext, useEffect } from 'react';
import { Controlled as CodeMirror } from 'react-codemirror2';
import jsonlint from 'jsonlint-webpack';
Expand All @@ -7,10 +11,11 @@ import 'codemirror/theme/neat.css';
import 'codemirror/mode/javascript/javascript';
import 'codemirror/addon/lint/lint';
import 'codemirror/addon/lint/json-lint';

import './style.css';

import { StoreContext } from './../../../store';
import { isAbsHosted } from './../../../utils/envUtil';
import { obfuscate } from './../../../utils/objUtil';

window.jsonlint = jsonlint;

Expand All @@ -28,21 +33,40 @@ const cmOptions = {
smartIndent: true,
};

const hostControlLabels = {
showKeys: formatMessage('Show keys'),
productionSlot: formatMessage('In production'),
integrationSlot: formatMessage('In test'),
botSettings: formatMessage('Settings'),
botSettingDescription: formatMessage(
'Settings contains detailed information about your bot. For security reasons, they are hidden by default. To test your bot or publish to Azure, you may need to provide these settings.'
),
learnMore: formatMessage('Learn more.'),
};

export const DialogSettings = () => {
const { state, actions } = useContext(StoreContext);
const { botName, settings } = state;
const [value, setValue] = useState(JSON.stringify(settings, null, 2));
const { botName, settings: origSettings, botEnvironment } = state;
const absHosted = isAbsHosted();
const { luis, MicrosoftAppPassword, MicrosoftAppId, ...settings } = origSettings;
const managedSettings = { luis, MicrosoftAppPassword, MicrosoftAppId };
const visibleSettings = absHosted ? settings : origSettings;
const [value, setValue] = useState(JSON.stringify(visibleSettings, null, 2));
const [editing, setEditing] = useState(false);
const [slot, setSlot] = useState(botEnvironment === 'editing' ? 'integration' : botEnvironment);
const options = { ...cmOptions, readOnly: !editing };

useEffect(() => {
setValue(JSON.stringify(settings, null, 2));
}, [settings]);
setValue(JSON.stringify(editing ? visibleSettings : obfuscate(visibleSettings), null, 2));
}, [origSettings, editing]);

const updateFormData = (editor, data, newValue) => {
try {
setValue(newValue);
const result = JSON.parse(newValue);
try {
actions.setSettings(botName, result);
const mergedResult = absHosted ? { ...managedSettings, ...result } : result;
actions.setSettings(botName, mergedResult, absHosted ? slot : undefined);
} catch (err) {
console.error(err.message);
}
Expand All @@ -51,9 +75,57 @@ export const DialogSettings = () => {
}
};

const changeEditing = (_, on) => {
setEditing(on);
actions.setEditDialogSettings(on, absHosted ? slot : undefined);
};

const slots = [
{ key: 'production', text: hostControlLabels.productionSlot, checked: slot === 'production' },
{ key: 'integration', text: hostControlLabels.integrationSlot, checked: slot === 'integration' },
];

const changeSlot = (_, option) => {
setSlot(option.key);
actions.setDialogSettingsSlot(editing, option.key);
};

const hostedControl = () => (
<div className="hosted-controls">
<h1>{hostControlLabels.botSettings}</h1>
<p>
{hostControlLabels.botSettingDescription}
&nbsp;
<Link href="//aka.ms/absh/docs/settings" target="_blank">
{hostControlLabels.learnMore}
</Link>
</p>
{absHosted ? (
<ChoiceGroup options={slots} onChange={changeSlot} className="slot-choice" selectedKey={slot} />
) : null}
</div>
);

const hostedToggle = () => (
<div className="hosted-toggle">
<Toggle label={hostControlLabels.showKeys} inlineLabel onChange={changeEditing} defaultChecked={editing} />
</div>
);

return botName ? (
<CodeMirror value={value} onBeforeChange={updateFormData} options={cmOptions} />
<div className="hosted-settings">
{hostedControl()}
{hostedToggle()}
<div className="hosted-code-mirror">
<CodeMirror
value={value}
onBeforeChange={updateFormData}
options={options}
className={absHosted ? 'CodeMirror-Hosted' : undefined}
/>
Comment thread
a-b-r-o-w-n marked this conversation as resolved.
Outdated
</div>
</div>
) : (
<div>Data Loading...</div>
<div>{formatMessage('Data loading...')}</div>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,35 @@
height: auto;
overflow: hidden;
}

.hosted-settings {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
height: auto;
overflow: hidden;
display: flex;
flex-direction: column;
padding: 1rem;
}

.hosted-controls {
margin-bottom: 18px;
}

.hosted-controls h1 {
margin-top: 0;
}

.hosted-code-mirror {
position: relative;
flex-grow: 1;
border: 1px solid #B3B0AD;
}

#toolbar-portal {
display: flex;
align-items: center;
}
20 changes: 12 additions & 8 deletions Composer/packages/client/src/pages/setting/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Link } from '@reach/router';

import { ToolBar } from '../../components/ToolBar';
import { navigateTo } from '../../utils';
import { isAbsHosted } from '../../utils/envUtil';

import Routes from './router';
import { Tree } from './../../components/Tree/index';
Expand All @@ -13,19 +14,22 @@ import { title, fileList, contentEditor, linkItem } from './styles';
import { MainContent } from './../../components/MainContent/index';
import { TestController } from './../../TestController';

const settingLabels = {
title: formatMessage('Configuration'),
publish: formatMessage('Publish'),
settings: formatMessage('Settings'),
};

const absHosted = isAbsHosted();

const links = [
{ key: '/setting/dialog-settings', name: formatMessage('Dialog settings') },
{ key: '/setting/dialog-settings', name: settingLabels.settings },
{ key: `/setting/${absHosted ? 'remote-publish' : 'deployment'}`, name: settingLabels.publish },
// { key: 'services', name: formatMessage('Services') },
// { key: 'composer-configuration', name: formatMessage('Composer configuration'), disabled: true },
// { key: 'publishing-staging', name: formatMessage('Publishing and staging'), disabled: true },
];

if (process.env.COMPOSER_AUTH_PROVIDER === 'abs-h' || process.env.MOCKHOSTED) {
links.push({ key: '/setting/remote-publish', name: formatMessage('Publish') });
} else {
links.push({ key: '/setting/deployment', name: formatMessage('Deployment') });
}

export const SettingPage = () => {
const [active, setActive] = useState();

Expand Down Expand Up @@ -63,7 +67,7 @@ export const SettingPage = () => {
<div css={fileList}>
<Tree variant="large">
<div>
<div css={title}>{formatMessage('Settings')}</div>
<div css={title}>{settingLabels.title}</div>
<Nav
groups={[{ links }]}
onRenderLink={onRenderLink}
Expand Down
43 changes: 41 additions & 2 deletions Composer/packages/client/src/store/action/setting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,14 @@ import settingsStorage from '../../utils/dialogSettingStorage';
import { SensitiveProperties } from '../../constants';

import { BASEURL, ActionTypes } from './../../constants/index';
import { BotEnvironments } from './../../utils/envUtil';

export const setSettings: ActionCreator = async ({ dispatch }, botName: string, settings: DialogSetting) => {
export const setSettings: ActionCreator = async (
{ dispatch },
botName: string,
settings: DialogSetting,
slot?: BotEnvironments

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BotEnvironments [](start = 9, length = 15)

these are just strings, not an enum

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ts enum can have string values

) => {
try {
// set value to store
dispatch({
Expand All @@ -22,7 +28,8 @@ export const setSettings: ActionCreator = async ({ dispatch }, botName: string,
settingsStorage.setField(botName, property, propertyValue ? propertyValue : '');
}
// set value to server
await axios.post(`${BASEURL}/projects/opened/settings`, { settings });
const suffix = slot ? `/${slot}` : '';
await axios.post(`${BASEURL}/projects/opened/settings${suffix}`, { settings });
} catch (err) {
dispatch({
type: ActionTypes.SET_ERROR,
Expand All @@ -33,3 +40,35 @@ export const setSettings: ActionCreator = async ({ dispatch }, botName: string,
});
}
};

export const setDialogSettingsSlot = async ({ dispatch }, editing: boolean, slot?: BotEnvironments) => {
const suffix = slot ? `/${slot}` : '';
const query = editing ? '' : '?obfuscate=true';
const url = `${BASEURL}/projects/opened/settings${suffix}${query}`;

try {
const response = await axios.get(`${BASEURL}/projects/opened/settings${suffix}`);
const settings = response.data;
dispatch({
type: ActionTypes.SYNC_ENV_SETTING,
payload: {
settings,
},
});
} catch (err) {
dispatch({
type: ActionTypes.SET_ERROR,
payload: {
message: err.response && err.response.data.message ? err.reponse.data.message : err,
summary: 'DLG SETTINGS ERROR',
},
});
}
};

export const setEditDialogSettings: ActionCreator = async (store, editing: boolean, slot?: BotEnvironments) => {
if (editing) {
// fetch the real settings for editing
await setDialogSettingsSlot(store, editing, slot);
}
};
1 change: 1 addition & 0 deletions Composer/packages/client/src/store/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { useReducer, useRef } from 'react';
import once from 'lodash.once';

import { prepareAxios } from '../utils/auth';
import { isAbsHosted } from '../utils/envUtil';

import { reducer } from './reducer';
import bindActions from './action/bindActions';
Expand Down
5 changes: 5 additions & 0 deletions Composer/packages/client/src/utils/envUtil.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export const isAbsHosted = () => process.env.COMPOSER_AUTH_PROVIDER === 'abs-h' || process.env.MOCKHOSTED;
export enum BotEnvironments {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BotEnvironments [](start = 12, length = 15)

there is a way to get the 'slot' names from the backend, and the default slot name

PRODUCTION = 'production',
INTEGRATION = 'integration',
}
15 changes: 15 additions & 0 deletions Composer/packages/client/src/utils/objUtil.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/**
* obfuscate object member values to '*****'
* @param obj
*/
export const obfuscate = (obj: Record<string, any> | string | number | boolean) => {
const OBFUSCATED_VALUE = '*****';
if (typeof obj !== 'object') {
Comment thread
hailiu2586 marked this conversation as resolved.
Outdated
return OBFUSCATED_VALUE;
}
if (Array.isArray(obj)) {
return obj.map(obfuscate);
}

return obj ? Object.keys(obj).reduce((prev, k) => ({ ...prev, [k]: obfuscate(obj[k]) }), {}) : OBFUSCATED_VALUE;
};
Loading