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

Corrections to creation dialog #154

Merged
merged 4 commits into from
Nov 22, 2017
Merged
Show file tree
Hide file tree
Changes from 2 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 @@ -19,9 +19,9 @@ <h1 class="create-channel__title">{{_ "Requests"}}</h1>
</div>
{{#unless autocomplete 'isShowing'}}
{{#if expertise}}
{{#unless validExpertise}}
{{> AssistifyCreateInputError text="Expertise_does_not_exist"}}
{{/unless}}
{{#if expertiseError}}
{{> AssistifyCreateInputError text=expertiseError}}
{{/if}}
{{/if}}
{{/unless}}
{{#with config}}
Expand All @@ -35,9 +35,9 @@ <h1 class="create-channel__title">{{_ "Requests"}}</h1>
{{/with}}
</label>
</div>
<div class="rc-input {{#if requestTitleError}}rc-input--error{{/if}}">
<div class="rc-input {{#if titleError}}rc-input--error{{/if}}">
<label class="rc-input__label">
<div class="rc-input__title">{{_ "Name"}}</div>
<div class="rc-input__title">{{_ "Title"}}</div>
<div class="rc-input__wrapper">
<div class="rc-input__icon">
<svg class="rc-icon rc-input__icon-svg rc-input__icon-svg--flag" aria-hidden="true">
Expand All @@ -48,11 +48,8 @@ <h1 class="create-channel__title">{{_ "Requests"}}</h1>
placeholder={{_ "New_request_title"}} autocomplete="off">
</div>
</label>
{{#if requestTitleInUse}}
{{> AssistifyCreateInputError text="Request_already_exists"}}
{{/if}}
{{#if invalidTitle}}
{{> AssistifyCreateInputError text="Request_no_special_char"}}
{{#if titleError}}
Copy link
Member Author

Choose a reason for hiding this comment

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

having a container for the actual error reduces 'if's

Choose a reason for hiding this comment

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

@mrsimpson implemented this at first, but having this approach will propagate one message at a time-point. This will prevent highlighting multiple error messages for a input field. In this case, its sufficient to have this approach work as expected.

{{> AssistifyCreateInputError text=titleError}}
{{/if}}
</div>
<div class="rc-input">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,11 @@
import {RocketChat} from 'meteor/rocketchat:lib';
import {FlowRouter} from 'meteor/kadira:flow-router';
import {ReactiveVar} from 'meteor/reactive-var';
import toastr from 'toastr';
Copy link
Member Author

Choose a reason for hiding this comment

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

Moved this to the place where the other validation errors are shown


const validateRequestName = (name) => {
Copy link
Member Author

Choose a reason for hiding this comment

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

moved this to the template instance ('onCreated'), see http://blazejs.org/guide/reusable-components.html#Attach-functions-to-the-instance

if (RocketChat.settings.get('UI_Allow_room_names_with_special_chars')) {
return true;
} else {
const reg = new RegExp(`^${ RocketChat.settings.get('UTF8_Names_Validation') }$`);
return name.length === 0 || reg.test(name);
}
};

const acEvents = {
'click .rc-popup-list__item'(e, t) {
t.ac.onItemClick(this, e);
t.debounceValidateExpertise(this.item.name);
Copy link
Member Author

Choose a reason for hiding this comment

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

validation only needs to happen once an item is selected...

},
'keydown [name="expertise"]'(e, t) {
t.ac.onKeyDown(e);
Expand All @@ -28,6 +19,7 @@ const acEvents = {
},
'blur [name="expertise"]'(e, t) {
t.ac.onBlur(e);
t.debounceValidateExpertise(e.target.value);
Copy link
Member Author

Choose a reason for hiding this comment

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

... or if the autocomplete vanishes (tab, click outside)

}
};

Expand All @@ -41,9 +33,6 @@ Template.AssistifyCreateRequest.helpers({
items() {
return Template.instance().ac.filteredList();
},
errorMessage() {
return Template.instance().errorMessage.get();
},
config() {
const filter = Template.instance().expertise;
return {
Expand All @@ -61,44 +50,24 @@ Template.AssistifyCreateRequest.helpers({
createIsDisabled() {
const instance = Template.instance();

if (!instance.requestTitle.get()) {
if (instance.validExpertise.get()) {
return '';
} else {
return 'disabled';
}
} else if (instance.requestTitle.get()) {
if (instance.validExpertise.get() && !instance.requestTitleInUse.get() && !instance.invalidTitle.get()) {
return '';
} else {
return 'disabled';
}
if (instance.validExpertise.get() && !instance.titleError.get()) {
return '';
} else {
return 'disabled';
}
},
invalidTitle() {
const instance = Template.instance();
return instance.invalidTitle.get();
},
requestTitleInUse() {
const instance = Template.instance();
return instance.requestTitleInUse.get();
},
validExpertise() {
expertiseError() {
const instance = Template.instance();
return instance.validExpertise.get();
return instance.expertiseError.get();
},
expertise() {
const instance = Template.instance();
return instance.expertise.get();
},
requestTitleError() {
titleError() {
const instance = Template.instance();
return instance.invalidTitle.get() || instance.requestTitleInUse.get();
return instance.titleError.get();
}
// noSplCharAllowed() {
// const instance = Template.instance();
// return instance.noSplCharAllowed.get();
// }
});


Expand All @@ -109,53 +78,26 @@ Template.AssistifyCreateRequest.events({
const position = input.selectionEnd || input.selectionStart;
const length = input.value.length;
document.activeElement === input && e && /input/i.test(e.type) && (input.selectionEnd = position + input.value.length - length);
if (input.value) {
t.delaySetExpertise(input.value);
t.checkExpertise(input.value);
} else {
t.delaySetExpertise(false);
t.expertise.set('');
}
if (t.expertise.get() && t.requestTitle.get()) {
const requestName = `${ t.expertise.get() }-${ t.requestTitle.get() }`;
t.invalidTitle.set(!validateRequestName(requestName));
t.requestTitleInUse.set(undefined);
t.checkRequestName(requestName);
}
t.expertise.set(input.value);
Copy link
Member Author

Choose a reason for hiding this comment

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

The copying of the actual value should happen immediately in order to have the value at hand for subsequent calls

t.validExpertise.set(false);
Copy link
Member Author

Choose a reason for hiding this comment

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

Similarly, the invalidation has to happen immediately in order to prevent inconsistent procedure

t.expertiseError.set('');
},
'input #request_title'(e, t) {
const input = e.target;
//const length = input.value.length;
if (input.value !== t.requestTitle.get()) {
t.requestTitle.set(input.value);
if (!input.value) {
t.titleError.set('');
} else {
t.requestTitle.set(false);
}

if (t.expertise.get() && input.value) {
const requestName = `${ input.value }`;
t.invalidTitle.set(!validateRequestName(requestName));
if (RocketChat.settings.get('UI_Allow_room_names_with_special_chars')) {
t.checkRequestDisplayName(requestName);
} else {
t.checkRequestName(requestName);
}
// t.invalidTitle.set(!validateRequestName(requestName));
// t.checkRequestName(requestName);
t.requestTitleInUse.set(undefined);
} else if (!input.value) {
t.invalidTitle.set(false);
t.requestTitleInUse.set(undefined);
t.requestTitle.set(input.value);
t.debounceValidateRequestName(input.value);
Copy link
Member Author

Choose a reason for hiding this comment

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

All the validation should happen inside the validation method - even if it's just about allowing initial values

}

},
'input #first_question'(e, t) {
const input = e.target;
//const length = input.value.length;
if (input.value) {
t.openingQuestion.set(input.value);
} else {
t.openingQuestion.set(false);
t.openingQuestion.set('');
}
},
'submit create-channel__content, click .js-save-request'(event, instance) {
Expand All @@ -164,36 +106,34 @@ Template.AssistifyCreateRequest.events({
const requestTitle = instance.requestTitle.get();
const openingQuestion = instance.openingQuestion.get();
if (expertise) {
instance.errorMessage.set(null);
instance.titleError.set(null);
Meteor.call('createRequest', requestTitle, expertise, openingQuestion, (err, result) => {
if (err) {
console.log(err);
switch (err.error) {
case 'error-invalid-name':
toastr.error(TAPi18n.__('Invalid_room_name', `${ expertise }...`));
instance.titleError.set(TAPi18n.__('Invalid_room_name', `${ expertise }...`));
return;
case 'error-duplicate-channel-name':
toastr.error(TAPi18n.__('Request_already_exists'));
instance.titleError.set(TAPi18n.__('Request_already_exists'));
return;
case 'error-archived-duplicate-name':
toastr.error(TAPi18n.__('Duplicate_archived_channel_name', name));
instance.titleError.set(TAPi18n.__('Duplicate_archived_channel_name', name));
return;
case 'error-invalid-room-name':
console.log('room name slug error');
// toastr.error(TAPi18n.__('Duplicate_archived_channel_name', name));
toastr.error(TAPi18n.__('Invalid_room_name', err.details.channel_name));
instance.titleError.set(TAPi18n.__('Invalid_room_name', err.details.channel_name));
return;
default:
return handleError(err);
}
}
console.log('Room Created');
toastr.success(TAPi18n.__('New_request_created'));
// toastr.success(TAPi18n.__('New_request_created'));
const roomCreated = RocketChat.models.Rooms.findOne({_id: result.rid});
FlowRouter.go('request', {name: roomCreated.name}, FlowRouter.current().queryParams);
});
} else {
instance.validExpertise.set(true);
}
}
});
Expand All @@ -206,7 +146,7 @@ Template.AssistifyCreateRequest.onRendered(function() {
this.ac.$element.on('autocompleteselect', function(e, {item}) {
instance.expertise.set(item.name);
$('input[name="expertise"]').val(item.name);
instance.checkExpertise(item.name);
instance.debounceValidateExpertise(item.name);

return instance.find('.js-save-request').focus();
});
Expand All @@ -217,46 +157,60 @@ Template.AssistifyCreateRequest.onCreated(function() {

instance.expertise = new ReactiveVar(''); //the value of the text field
instance.validExpertise = new ReactiveVar(false);
instance.errorMessage = new ReactiveVar(null);
instance.expertiseError = new ReactiveVar(null);
instance.titleError = new ReactiveVar(null);
instance.requestTitle = new ReactiveVar('');
instance.openingQuestion = new ReactiveVar('');
instance.requestTitleInUse = new ReactiveVar(undefined);
instance.invalidTitle = new ReactiveVar(false);
instance.error = new ReactiveVar(null);
instance.checkRequestName = _.debounce((name) => {
Copy link
Member Author

Choose a reason for hiding this comment

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

Validation methods should have the focus on the object which is validated, not the steps of the validation themselves

if (validateRequestName(name)) {
return Meteor.call('roomNameExists', name, (error, result) => {
if (error) {
return;
}
instance.requestTitleInUse.set(result);
});
}
instance.requestTitleInUse.set(undefined);
}, 500);
instance.checkRequestDisplayName = _.debounce((name) => {
if (validateRequestName(name)) {
return Meteor.call('roomDisplayNameExists', name, (error, result) => {
if (error) {
return;
}
instance.requestTitleInUse.set(result);
});

instance.debounceValidateExpertise = _.debounce((expertise) => {
if (!expertise) {
return false; //expertise is mandatory
}
instance.requestTitleInUse.set(undefined);
}, 500);
instance.checkExpertise = _.debounce((expertise) => {
return Meteor.call('assistify:isValidExpertise', expertise, (error, result) => {
if (error) {
instance.validExpertise.set(false);
} else {
instance.validExpertise.set(result);
if (!result) {
instance.expertiseError.set('Expertise_does_not_exist');
} else {
instance.expertiseError.set('');
}
}
});
}, 500);
instance.delaySetExpertise = _.debounce((expertise) => {
instance.expertise.set(expertise);
}, 200);

instance.debounceValidateRequestName = _.debounce((name) => {
instance.titleError.set('');
if (!name) {
return; //"none" is a valid name
}
if (RocketChat.settings.get('UI_Allow_room_names_with_special_chars')) {
Meteor.call('roomDisplayNameExists', name, (error, result) => {
if (error) {
return;
}
if (result) {
instance.titleError.set('Request_already_exists');
}
});
} else {
const reg = new RegExp(`^${ RocketChat.settings.get('UTF8_Names_Validation') }$`);
const passesRegex = name.length === 0 || reg.test(name);
if (!passesRegex) {
instance.titleError.set('Request_no_special_char');
} else {
Meteor.call('roomNameExists', name, (error, result) => {
if (error) {
return;
}
if (result) {
instance.titleError.set('Request_already_exists');
}
});
}
}
}, 500);

// instance.clearForm = function() {
// instance.requestRoomName.set('');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ Meteor.methods({
if (openingQuestion) {
const msg = openingQuestion;
const msgObject = { _id: Random.id(), rid:roomCreateResult.rid, msg};
RocketChat.sendMessage([Meteor.user().username], msgObject, room);
RocketChat.sendMessage(Meteor.user(), msgObject, room);
Copy link
Member Author

Choose a reason for hiding this comment

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

@vickyokrm I missed that one earlier: You didn't pass a proper user-object, but only its name. Thus, the message was not complete which made the "unread"-bar appear and made the Smarti-adapter fail

}

const helpRequestId = RocketChat.models.HelpRequests.createForSupportArea(expertise, roomCreateResult.rid, '', environment);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ New_request_for_expertise: The topic of the new request
New_request: New request
New_request_created: Request created successfully
New_request_first_question: What do you want to ask
New_request_title: A name helps to find the request later on
New_request_title: A title helps to find the request later on
No_expertise_yet: No topics yet
No_requests_yet: No requests yet
release: Version
Expand Down