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 all 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
16 changes: 15 additions & 1 deletion Composer/packages/client/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -123,13 +123,27 @@ const bottomLinks = [
export const App: React.FC = () => {
const { state, actions } = useContext(StoreContext);
const [sideBarExpand, setSideBarExpand] = useState(false);
const { botName, projectId, dialogs, creationFlowStatus, locale, designPageLocation } = state;

const { botName, projectId, dialogs, creationFlowStatus, locale, designPageLocation, announcement } = state;
const { setCreationFlowStatus } = actions;
const mapNavItemTo = x => resolveToBasePath(BASEPATH, x);

const openedDialogId = designPageLocation.dialogId || dialogs.find(({ isRoot }) => isRoot === true)?.id || 'Main';
return (
<Fragment>
<div
role="alert"
aria-live="assertive"
style={{
display: 'block',
position: 'absolute',
top: '-9999px',
height: '1px',
width: '1px',
}}
>
{announcement}
</div>
<Header botName={`${botName}(${locale})`} />
<div css={main}>
<nav css={sideBar(sideBarExpand)}>
Expand Down
2 changes: 2 additions & 0 deletions Composer/packages/client/src/constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ export enum ActionTypes {
SET_USER_SETTINGS = 'SET_USER_SETTINGS',
ADD_SKILL_DIALOG_BEGIN = 'ADD_SKILL_DIALOG_BEGIN',
ADD_SKILL_DIALOG_END = 'ADD_SKILL_DIALOG_END',

SET_MESSAGE = 'SET_MESSAGE',
}

export const Tips = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,16 @@ import { IconButton } from 'office-ui-fabric-react/lib/Button';
import { TooltipHost } from 'office-ui-fabric-react/lib/Tooltip';
import { ScrollablePane, ScrollbarVisibility } from 'office-ui-fabric-react/lib/ScrollablePane';
import { Sticky, StickyPositionType } from 'office-ui-fabric-react/lib/Sticky';
import { FontIcon } from 'office-ui-fabric-react/lib/Icon';
import formatMessage from 'format-message';
import { NeutralColors, FontSizes } from '@uifabric/fluent-theme';
import { RouteComponentProps } from '@reach/router';
import { LgTemplate } from '@bfc/shared';
import { Async } from 'office-ui-fabric-react/lib/Utilities';

import { StoreContext } from '../../store';
import { increaseNameUtilNotExist } from '../../utils/lgUtil';
import { navigateTo } from '../../utils';
import { actionButton, formCell, iconClass } from '../language-understanding/styles';
import { actionButton, formCell } from '../language-understanding/styles';

interface TableViewProps extends RouteComponentProps<{}> {
dialogId: string;
Expand All @@ -35,13 +35,23 @@ const TableView: React.FC<TableViewProps> = props => {
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 setMessage = useRef(debounce(actions.setMessage, 500)).current;
const [templates, setTemplates] = useState<LgTemplate[]>([]);
const listRef = useRef(null);

const activeDialog = dialogs.find(({ id }) => id === dialogId);

const [focusedIndex, setFocusedIndex] = useState(0);

const _async = new Async();

const announce = (message: string) => {
setMessage(message);
_async.setTimeout(() => {
setMessage(undefined);
}, 2000);
Comment on lines +50 to +52
Copy link
Contributor

Choose a reason for hiding this comment

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

How this setTimeout works?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This will reset the message to "undefined" after two seconds. Because the "aria-live" region is only read when it changes, we need to clear the message out after a pause. Otherwise doing the same action multiple times in a row (like deleting two rows from the table) will only be read once.

};

useEffect(() => {
if (!file || isEmpty(file)) return;

Expand Down Expand Up @@ -112,13 +122,15 @@ const TableView: React.FC<TableViewProps> = props => {
key: 'delete',
name: formatMessage('Delete'),
onClick: () => {
announce('item deleted');
onRemoveTemplate(index);
},
},
{
key: 'copy',
name: formatMessage('Make a copy'),
onClick: () => {
announce('item copied');
onCopyTemplate(index);
},
},
Expand Down Expand Up @@ -191,11 +203,9 @@ const TableView: React.FC<TableViewProps> = props => {
data: 'string',
onRender: item => {
return activeDialog?.lgTemplates.find(({ name }) => name === item.name) ? (
<div css={formCell}>
<FontIcon iconName="Accept" aria-label={formatMessage('Used')} className={iconClass} />
</div>
<IconButton iconProps={{ iconName: 'Accept' }} ariaLabel={formatMessage('Used') + ';'} />
) : (
<div aria-label={formatMessage('Unused')} />
<div aria-label={formatMessage('Unused') + ';'} />
);
},
};
Expand Down
7 changes: 7 additions & 0 deletions Composer/packages/client/src/store/action/error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,10 @@ export const setError: ActionCreator = ({ dispatch }, error) => {
payload: error,
});
};

export const setMessage: ActionCreator = ({ dispatch }, message) => {
dispatch({
type: ActionTypes.SET_MESSAGE,
payload: message,
});
};
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 @@ -88,6 +88,7 @@ const initialState: State = {
propertyEditorWidth: 400,
dialogNavWidth: 180,
}),
announcement: undefined,
};

interface StoreContextValue {
Expand Down
6 changes: 6 additions & 0 deletions Composer/packages/client/src/store/reducer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,11 @@ const setCodeEditorSettings: ReducerFunc = (state, settings) => {
return state;
};

const setMessage: ReducerFunc = (state, message) => {
state.announcement = message;
return state;
};

const noOp: ReducerFunc = state => {
return state;
};
Expand Down Expand Up @@ -526,4 +531,5 @@ export const reducer = createReducer({
[ActionTypes.EDITOR_CLIPBOARD]: setClipboardActions,
[ActionTypes.UPDATE_BOTSTATUS]: setBotStatus,
[ActionTypes.SET_USER_SETTINGS]: setCodeEditorSettings,
[ActionTypes.SET_MESSAGE]: setMessage,
});
1 change: 1 addition & 0 deletions Composer/packages/client/src/store/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ export interface State {
publishTypes: string[];
publishTargets: any[];
userSettings: UserSettings;
announcement: string | undefined;
}

export type ReducerFunc<T = any> = (state: State, payload: T) => State;
Expand Down