UX: Improve assign modal design (#403)

Implements a new design that improves the user experience:

- add a clear cancel button
- add an indication the note is optional
- change the plus icon to a search icon
- show an error when the user tries to assign without choosing an assignee
- move suggestions to default search results
- focus search input when modal is displayed
This commit is contained in:
Bianca Nenciu 2022-12-21 14:49:24 +02:00 committed by GitHub
parent 700dfe551b
commit a4ce90e855
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 71 additions and 71 deletions

View File

@ -15,10 +15,13 @@ export default Controller.extend(ModalFunctionality, {
taskActions: service(), taskActions: service(),
autofocus: not("capabilities.touch"), autofocus: not("capabilities.touch"),
assigneeName: or("model.username", "model.group_name"), assigneeName: or("model.username", "model.group_name"),
assigneeError: false,
init() { init() {
this._super(...arguments); this._super(...arguments);
this.allowedGroups = [];
this.set("allowedGroups", []);
this.set("assigneeError", false);
ajax("/assign/suggestions").then((data) => { ajax("/assign/suggestions").then((data) => {
if (this.isDestroying || this.isDestroyed) { if (this.isDestroying || this.isDestroyed) {
@ -77,6 +80,11 @@ export default Controller.extend(ModalFunctionality, {
return this.bulkAction(this.model.username); return this.bulkAction(this.model.username);
} }
if (!this.assigneeName) {
this.set("assigneeError", true);
return;
}
let path = "/assign/assign"; let path = "/assign/assign";
if (isEmpty(this.get("model.username"))) { if (isEmpty(this.get("model.username"))) {
@ -136,6 +144,7 @@ export default Controller.extend(ModalFunctionality, {
}, },
setGroupOrUser(name) { setGroupOrUser(name) {
this.set("assigneeError", false);
if (this.allowedGroupsForAssignment.includes(name)) { if (this.allowedGroupsForAssignment.includes(name)) {
this.setProperties({ this.setProperties({
"model.username": null, "model.username": null,

View File

@ -924,10 +924,7 @@ export default {
actions: { actions: {
showReAssign() { showReAssign() {
this.set("assignUser.isBulkAction", true); this.set("assignUser.isBulkAction", true);
this.set("assignUser.model", { this.set("assignUser.model", { username: "" });
username: "",
description: "discourse_assign.assign_bulk_modal.description",
});
this.send("changeBulkTemplate", "modal/assign-user"); this.send("changeBulkTemplate", "modal/assign-user");
}, },
unassignTopics() { unassignTopics() {

View File

@ -29,10 +29,6 @@ export default Service.extend({
this.i18nSuffix(options.targetType) + this.i18nSuffix(options.targetType) +
`.${options.isAssigned ? "reassign_title" : "title"}`, `.${options.isAssigned ? "reassign_title" : "title"}`,
model: { model: {
description:
`discourse_assign.${options.isAssigned ? "reassign" : "assign"}` +
this.i18nSuffix(options.targetType) +
".description",
reassign: options.isAssigned, reassign: options.isAssigned,
username: target.assigned_to_user?.username, username: target.assigned_to_user?.username,
group_name: target.assigned_to_group?.name, group_name: target.assigned_to_group?.name,

View File

@ -1,31 +1,32 @@
{{#d-modal-body class="assign"}} {{#d-modal-body class="assign"}}
<div> <div>
<p>{{i18n model.description}}</p> <div class="control-group {{if this.assigneeError "assignee-error"}}">
{{email-group-user-chooser <label>{{i18n "discourse_assign.assign_modal.assignee_label"}}</label>
autocomplete="off" {{email-group-user-chooser
value=assigneeName autocomplete="off"
onChange=(action "assignUsername") value=assigneeName
autofocus="autofocus" onChange=(action "assignUsername")
showUserStatus=true autofocus="autofocus"
options=(hash showUserStatus=true
mobilePlacementStrategy="absolute" caretIcon="search"
filterPlaceholder=placeholderKey options=(hash
includeGroups=true mobilePlacementStrategy="absolute"
customSearchOptions=(hash assignableGroups=true) filterPlaceholder=placeholderKey
groupMembersOf=allowedGroups includeGroups=true
maximum=1 customSearchOptions=(hash assignableGroups=true defaultSearchResults=this.assignSuggestions)
autofocus=autofocus groupMembersOf=allowedGroups
tabindex=1 maximum=1
) autofocus=autofocus
}} tabindex=1
<div class="assign-suggestions"> )
{{#each assignSuggestions as |user|}} }}
<a href {{action "assignUser" user.username }}> {{#if this.assigneeError}}
{{avatar user imageSize="small"}} <span class="error-label">
{{decorate-username-selector user.username}} {{d-icon "exclamation-triangle"}} {{i18n "discourse_assign.assign_modal.choose_assignee"}}
</a> </span>
{{/each}} {{/if}}
</div> </div>
{{#if this.statusEnabled}} {{#if this.statusEnabled}}
<div class="control-group assign-status"> <div class="control-group assign-status">
<label>{{i18n "discourse_assign.assign_modal.status_label"}}</label> <label>{{i18n "discourse_assign.assign_modal.status_label"}}</label>
@ -37,8 +38,11 @@
}} }}
</div> </div>
{{/if}} {{/if}}
<div class="control-group assign-status"> <div class="control-group assign-status">
<label>{{i18n "discourse_assign.assign_modal.note_label"}}</label> <label>
{{i18n "discourse_assign.assign_modal.note_label"}}&nbsp;<span class="label-optional">{{i18n "discourse_assign.assign_modal.optional_label"}}</span>
</label>
{{textarea id="assign-modal-note" value=model.note key-down=(action "handleTextAreaKeydown")}} {{textarea id="assign-modal-note" value=model.note key-down=(action "handleTextAreaKeydown")}}
</div> </div>
</div> </div>
@ -52,4 +56,5 @@
class="btn-primary" class="btn-primary"
disabled=disabled disabled=disabled
}} }}
<DModalCancel @close={{route-action "closeModal"}} />
</div> </div>

View File

@ -66,37 +66,37 @@
margin-left: 5px; margin-left: 5px;
} }
.assign.modal-body .email-group-user-chooser { .assign-user-modal {
display: block; .modal-inner-container {
width: 300px; width: 400px;
margin-top: 5px;
}
.assign-user-modal p {
margin-top: 0;
}
.assign-suggestions {
margin-top: 15px;
margin-bottom: 15px;
img {
margin-right: 5px;
cursor: pointer;
} }
.groups { label {
margin-top: 5px; font-weight: bold;
a {
margin-right: 5px; .label-optional {
color: var(--primary-medium);
font-weight: normal;
} }
} }
.on-holiday { .email-group-user-chooser {
position: absolute; width: 100%;
margin-left: -18px;
margin-top: 14px; .caret-icon {
color: var(--primary-medium); color: var(--primary-medium);
}
}
.control-group.assignee-error {
.select-kit-header {
border-color: var(--danger);
}
.error-label {
color: var(--danger);
font-size: var(--font-down-1);
}
} }
} }

View File

@ -50,19 +50,17 @@ en:
help: "Edit assignment details" help: "Edit assignment details"
reassign_modal: reassign_modal:
title: "Reassign Topic" title: "Reassign Topic"
description: "Enter the name of the user you'd like to Reassign this topic"
assign_modal: assign_modal:
title: "Assign Topic" title: "Assign Topic"
reassign_title: "Reassign Topic" reassign_title: "Reassign Topic"
description: "Enter the name of the user you'd like to assign this topic"
assign: "Assign" assign: "Assign"
assignee_label: Assignee
choose_assignee: Choose a user to assign.
note_label: Note note_label: Note
optional_label: "(optional)"
status_label: Status status_label: Status
assign_post_modal: assign_post_modal:
title: "Assign Post" title: "Assign Post"
description: "Enter the name of the user you'd like to assign this post"
assign_bulk_modal:
description: "Enter the name of the user you'd like to assign these topics"
claim: claim:
title: "claim" title: "claim"
help: "Assign topic to yourself" help: "Assign topic to yourself"

View File

@ -46,8 +46,6 @@ acceptance("Discourse Assign | Assign mobile", function (needs) {
assert.ok(menu.rowByValue("assign").exists()); assert.ok(menu.rowByValue("assign").exists());
await menu.selectRowByValue("assign"); await menu.selectRowByValue("assign");
assert.ok(exists(".assign.modal-body"), "assign modal opens"); assert.ok(exists(".assign.modal-body"), "assign modal opens");
await click(".assign-suggestions .avatar");
}); });
}); });
@ -102,8 +100,6 @@ acceptance("Discourse Assign | Assign desktop", function (needs) {
await click("#topic-footer-button-assign"); await click("#topic-footer-button-assign");
assert.ok(exists(".assign.modal-body"), "assign modal opens"); assert.ok(exists(".assign.modal-body"), "assign modal opens");
await click(".assign-suggestions .avatar");
}); });
}); });

View File

@ -21,7 +21,6 @@ discourseModule("Unit | Service | task-actions", function () {
assert.deepEqual(modalCall[1], { assert.deepEqual(modalCall[1], {
title: "discourse_assign.assign_modal.title", title: "discourse_assign.assign_modal.title",
model: { model: {
description: "discourse_assign.assign_modal.description",
reassign: false, reassign: false,
username: "tomtom", username: "tomtom",
group_name: "cats", group_name: "cats",