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
4 changes: 2 additions & 2 deletions Composer/packages/form-dialogs/src/FormDialogSchemaEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ const InternalFormDialogSchemaEditor = React.memo((props: FormDialogSchemaEditor
}, [editorId]);

const startOver = React.useCallback(() => {
reset({ name: editorId });
}, [reset, editorId]);
reset({ name: schema.id });
}, [reset, editorId, schema]);

useRecoilTransactionObserver_UNSTABLE(async ({ snapshot, previousSnapshot }) => {
const content = await snapshot.getPromise(formDialogSchemaJsonSelector);
Expand Down
5 changes: 3 additions & 2 deletions Composer/packages/form-dialogs/src/atoms/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,16 @@ import formatMessage from 'format-message';
import {
builtInStringFormats,
FormDialogProperty,
FormDialogPropertyKind,
FormDialogPropertyPayload,
IntegerPropertyPayload,
NumberPropertyPayload,
RefPropertyPayload,
FormDialogPropertyKind,
StringPropertyPayload,
TypedPropertyPayload,
} from 'src/atoms/types';
import { generateId } from 'src/utils/base';
import { nameRegex } from 'src/utils/constants';

export const getDefaultPayload = (kind: FormDialogPropertyKind) => {
switch (kind) {
Expand Down Expand Up @@ -261,7 +262,7 @@ export const validateSchemaPropertyStore = (property: FormDialogProperty) => {
}
}

return !!(payloadValid && property.name);
return !!(payloadValid && property.name && nameRegex.test(property.name));
};

export const getPropertyTypeDisplayName = (property: FormDialogProperty) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,18 @@ import { DraggableProvidedDragHandleProps } from 'react-beautiful-dnd';
import {
ArrayPropertyPayload,
FormDialogProperty,
FormDialogPropertyKind,
FormDialogPropertyPayload,
IntegerPropertyPayload,
NumberPropertyPayload,
FormDialogPropertyKind,
StringPropertyPayload,
} from 'src/atoms/types';
import { FieldLabel } from 'src/components/common/FieldLabel';
import { NumberPropertyContent } from 'src/components/property/NumberPropertyContent';
import { PropertyTypeSelector } from 'src/components/property/PropertyTypeSelector';
import { RequiredPriorityIndicator } from 'src/components/property/RequiredPriorityIndicator';
import { StringPropertyContent } from 'src/components/property/StringPropertyContent';
import { nameRegex } from 'src/utils/constants';

const ContentRoot = styled.div(({ isValid }: { isValid: boolean }) => ({
width: 720,
Expand Down Expand Up @@ -163,18 +164,30 @@ export const FormDialogPropertyCard = React.memo((props: FormDialogPropertyCardP
[]
);

const validateName = React.useCallback(
(value: string) =>
!value
? formatMessage('Property name is required!')
: !nameRegex.test(value)
? formatMessage('Spaces and special characters are not allowed. Use letters, numbers, -, or _.')
: '',
[]
);

return (
<FocusZone>
<ContentRoot {...dragHandleProps} ref={rootElmRef} isValid={valid}>
<Stack horizontal tokens={{ childrenGap: 16 }} verticalAlign="center">
<TextField
aria-describedby={propertyNameTooltipId}
autoComplete="off"
deferredValidationTime={300}
label={formatMessage('Property name')}
placeholder={formatMessage('Name of the property')}
styles={{ root: { flex: 1 } }}
value={name}
onChange={changeName}
onGetErrorMessage={validateName}
onRenderLabel={onRenderLabel(
formatMessage(
`A property is a piece of information that your bot will collect. The property name is the name used in Composer; it is not necessarily the same text that will appear in your bot's messages.`
Expand Down
2 changes: 2 additions & 0 deletions Composer/packages/form-dialogs/src/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@
// Licensed under the MIT License.

export const jsPropertyListClassName = 'jsPropertyListClassName';

export const nameRegex = /^[a-zA-Z0-9-_]+$/;

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.

I see this in the SDK schema for AgeEntityRecognizer. I wonder if the sdk schema should define a pattern for a valid property name rather than string? Or maybe this is too meta for a JSON schema.

"$kind": {
"title": "Kind of dialog object",
"description": "Defines the valid properties for the component you are configuring (from a dialog .schema file)",
"type": "string",
"pattern": "^[a-zA-Z][a-zA-Z0-9.]*$",
"const": "Microsoft.ActivityTemplate"
},

3 changes: 3 additions & 0 deletions Composer/packages/server/src/locales/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -1955,6 +1955,9 @@
"property_name_914371f5": {
"message": "Property name"
},
"property_name_is_required_5bc57d97": {
"message": "Property name is required!"
},
"property_title_f2b443b7": {
"message": "Property title"
},
Expand Down