diff options
author | Lauri Ojansivu <x@xet7.org> | 2019-01-04 09:23:54 +0200 |
---|---|---|
committer | Lauri Ojansivu <x@xet7.org> | 2019-01-04 09:23:54 +0200 |
commit | 2b53fae16f07c3614ee9e9d54cd17f8102218fea (patch) | |
tree | f4c2066ff4ab269f78091690fd0d377f76dac083 /client/components | |
parent | 1683bcb3e5980d3af4a07c4bb22e534b98eff862 (diff) | |
parent | 4d8b2029d266843dc0eb376a0bf752c46e440a13 (diff) | |
download | wekan-2b53fae16f07c3614ee9e9d54cd17f8102218fea.tar.gz wekan-2b53fae16f07c3614ee9e9d54cd17f8102218fea.tar.bz2 wekan-2b53fae16f07c3614ee9e9d54cd17f8102218fea.zip |
Merge branch 'feature-rules' of https://github.com/Angtrim/wekan into Angtrim-feature-rules
Diffstat (limited to 'client/components')
-rw-r--r-- | client/components/rules/actions/boardActions.jade | 28 | ||||
-rw-r--r-- | client/components/rules/actions/boardActions.js | 46 | ||||
-rw-r--r-- | client/components/rules/actions/checklistActions.jade | 19 | ||||
-rw-r--r-- | client/components/rules/actions/checklistActions.js | 23 | ||||
-rw-r--r-- | client/components/rules/rules.styl | 16 | ||||
-rw-r--r-- | client/components/rules/rulesMain.js | 31 | ||||
-rw-r--r-- | client/components/rules/triggers/boardTriggers.jade | 99 | ||||
-rw-r--r-- | client/components/rules/triggers/boardTriggers.js | 81 | ||||
-rw-r--r-- | client/components/rules/triggers/cardTriggers.jade | 35 | ||||
-rw-r--r-- | client/components/rules/triggers/checklistTriggers.jade | 42 |
10 files changed, 350 insertions, 70 deletions
diff --git a/client/components/rules/actions/boardActions.jade b/client/components/rules/actions/boardActions.jade index 768d77cf..6034184c 100644 --- a/client/components/rules/actions/boardActions.jade +++ b/client/components/rules/actions/boardActions.jade @@ -36,7 +36,33 @@ template(name="boardActions") div.trigger-text | {{_'r-card'}} div.trigger-button.js-add-arch-action.js-goto-rules - i.fa.fa-plus + i.fa.fa-plus + + div.trigger-item + div.trigger-content + div.trigger-text + | {{_'r-add-swimlane'}} + div.trigger-dropdown + input(id="swimlane-name",type=text,placeholder="{{_'r-name'}}") + div.trigger-button.js-add-swimlane-action.js-goto-rules + i.fa.fa-plus + + div.trigger-item + div.trigger-content + div.trigger-text + | {{_'r-create-card'}} + div.trigger-dropdown + input(id="card-name",type=text,placeholder="{{_'r-name'}}") + div.trigger-text + | {{_'r-in-list'}} + div.trigger-dropdown + input(id="list-name",type=text,placeholder="{{_'r-name'}}") + div.trigger-text + | {{_'r-in-swimlane'}} + div.trigger-dropdown + input(id="swimlane-name2",type=text,placeholder="{{_'r-name'}}") + div.trigger-button.js-create-card-action.js-goto-rules + i.fa.fa-plus diff --git a/client/components/rules/actions/boardActions.js b/client/components/rules/actions/boardActions.js index 95771fce..e0b8edc9 100644 --- a/client/components/rules/actions/boardActions.js +++ b/client/components/rules/actions/boardActions.js @@ -5,6 +5,52 @@ BlazeComponent.extendComponent({ events() { return [{ + 'click .js-create-card-action' (event) { + const ruleName = this.data().ruleName.get(); + const trigger = this.data().triggerVar.get(); + const cardName = this.find('#card-name').value; + const listName = this.find('#list-name').value; + const swimlaneName = this.find('#swimlane-name2').value; + const boardId = Session.get('currentBoard'); + const desc = Utils.getTriggerActionDesc(event, this); + const triggerId = Triggers.insert(trigger); + const actionId = Actions.insert({ + actionType: 'createCard', + swimlaneName, + cardName, + listName, + boardId, + desc, + }); + Rules.insert({ + title: ruleName, + triggerId, + actionId, + boardId, + }); + + }, + 'click .js-add-swimlane-action' (event) { + const ruleName = this.data().ruleName.get(); + const trigger = this.data().triggerVar.get(); + const swimlaneName = this.find('#swimlane-name').value; + const boardId = Session.get('currentBoard'); + const desc = Utils.getTriggerActionDesc(event, this); + const triggerId = Triggers.insert(trigger); + const actionId = Actions.insert({ + actionType: 'addSwimlane', + swimlaneName, + boardId, + desc, + }); + Rules.insert({ + title: ruleName, + triggerId, + actionId, + boardId, + }); + + }, 'click .js-add-spec-move-action' (event) { const ruleName = this.data().ruleName.get(); const trigger = this.data().triggerVar.get(); diff --git a/client/components/rules/actions/checklistActions.jade b/client/components/rules/actions/checklistActions.jade index 8414a1a5..94c63557 100644 --- a/client/components/rules/actions/checklistActions.jade +++ b/client/components/rules/actions/checklistActions.jade @@ -43,6 +43,25 @@ template(name="checklistActions") div.trigger-button.js-add-check-item-action.js-goto-rules i.fa.fa-plus + div.trigger-item + div.trigger-content + div.trigger-text + | {{{_'r-add-checklist'}}} + div.trigger-dropdown + input(id="checklist-name-3",type=text,placeholder="{{{_'r-name'}}}") + div.trigger-text + | {{{_'r-with-items'}}} + div.trigger-dropdown + input(id="checklist-items",type=text,placeholder="{{{_'r-items-list'}}}") + div.trigger-button.js-add-checklist-items-action.js-goto-rules + i.fa.fa-plus + + div.trigger-item + div.trigger-content + div.trigger-text + | {{{_'r-checklist-note'}}} + + diff --git a/client/components/rules/actions/checklistActions.js b/client/components/rules/actions/checklistActions.js index 4b70f959..3e79b075 100644 --- a/client/components/rules/actions/checklistActions.js +++ b/client/components/rules/actions/checklistActions.js @@ -4,6 +4,29 @@ BlazeComponent.extendComponent({ }, events() { return [{ + 'click .js-add-checklist-items-action' (event) { + const ruleName = this.data().ruleName.get(); + const trigger = this.data().triggerVar.get(); + const checklistName = this.find('#checklist-name-3').value; + const checklistItems = this.find('#checklist-items').value; + const boardId = Session.get('currentBoard'); + const desc = Utils.getTriggerActionDesc(event, this); + const triggerId = Triggers.insert(trigger); + const actionId = Actions.insert({ + actionType: 'addChecklistWithItems', + checklistName, + checklistItems, + boardId, + desc, + }); + Rules.insert({ + title: ruleName, + triggerId, + actionId, + boardId, + }); + + }, 'click .js-add-checklist-action' (event) { const ruleName = this.data().ruleName.get(); const trigger = this.data().triggerVar.get(); diff --git a/client/components/rules/rules.styl b/client/components/rules/rules.styl index b52f84a7..27463d12 100644 --- a/client/components/rules/rules.styl +++ b/client/components/rules/rules.styl @@ -10,7 +10,10 @@ display: inline-block float: left margin: revert - +.hide-element + display:none !important +.user-details + display:inline-block .rules-btns-group position: absolute right: 0 @@ -120,6 +123,15 @@ .trigger-text font-size: 16px display:inline-block + .trigger-inline-button + font-size: 16px + display: inline; + padding: 6px; + border: 1px solid #eee + border-radius: 4px + box-shadow: inset -1px -1px 3px rgba(0,0,0,.05) + &:hover, &.is-active + box-shadow: 0 0 0 2px darken(white, 60%) inset .trigger-text.trigger-text-email margin-left: 5px; margin-top: 10px; @@ -160,6 +172,8 @@ box-shadow: 0 0 0 2px darken(white, 60%) inset .trigger-button.trigger-button-email top:30px + .trigger-button.trigger-button-person + right:-40px .trigger-item.trigger-item-mail height:300px diff --git a/client/components/rules/rulesMain.js b/client/components/rules/rulesMain.js index 0752a541..2e125960 100644 --- a/client/components/rules/rulesMain.js +++ b/client/components/rules/rulesMain.js @@ -1,4 +1,4 @@ -BlazeComponent.extendComponent({ +const rulesMainComponent = BlazeComponent.extendComponent({ onCreated() { this.rulesCurrentTab = new ReactiveVar('rulesList'); this.ruleName = new ReactiveVar(''); @@ -9,7 +9,13 @@ BlazeComponent.extendComponent({ setTrigger() { this.rulesCurrentTab.set('trigger'); }, - + sanitizeObject(obj){ + Object.keys(obj).forEach((key) => { + if(obj[key] == '' || obj[key] == undefined){ + obj[key] = '*'; + }} + ); + }, setRulesList() { this.rulesCurrentTab.set('rulesList'); }, @@ -42,8 +48,27 @@ BlazeComponent.extendComponent({ }, 'click .js-goto-action' (event) { event.preventDefault(); + // Add user to the trigger + const username = $(event.currentTarget.offsetParent).find('.user-name').val(); + let trigger = this.triggerVar.get(); + trigger.userId = '*'; + if(username != undefined ){ + const userFound = Users.findOne({username}); + if(userFound != undefined){ + trigger.userId = userFound._id; + this.triggerVar.set(trigger); + } + } + // Sanitize trigger + trigger = this.triggerVar.get(); + this.sanitizeObject(trigger); + this.triggerVar.set(trigger); this.setAction(); }, + 'click .js-show-user-field' (event) { + event.preventDefault(); + $(event.currentTarget.offsetParent).find('.user-details').removeClass('hide-element'); + }, 'click .js-goto-rules' (event) { event.preventDefault(); this.setRulesList(); @@ -68,3 +93,5 @@ BlazeComponent.extendComponent({ }, }).register('rulesMain'); + + diff --git a/client/components/rules/triggers/boardTriggers.jade b/client/components/rules/triggers/boardTriggers.jade index 48b9345c..c39ff6d0 100644 --- a/client/components/rules/triggers/boardTriggers.jade +++ b/client/components/rules/triggers/boardTriggers.jade @@ -1,43 +1,58 @@ template(name="boardTriggers") - div.trigger-item + div.trigger-item#trigger-two div.trigger-content div.trigger-text - | {{_'r-when-a-card-is'}} - div.trigger-dropdown - select(id="gen-action") - option(value="created") {{_'r-added-to'}} - option(value="removed") {{_'r-removed-from'}} + | {{_'r-when-a-card'}} + div.trigger-inline-button.js-open-card-title-popup + i.fa.fa-filter div.trigger-text - | {{_'r-the-board'}} - div.trigger-button.js-add-gen-trigger.js-goto-action - i.fa.fa-plus - - div.trigger-item - div.trigger-content + | {{_'r-is'}} div.trigger-text - | {{_'r-when-a-card-is'}} - div.trigger-dropdown - select(id="create-action") - option(value="created") {{_'r-added-to'}} - option(value="removed") {{_'r-removed-from'}} + | {{_'r-added-to'}} div.trigger-text | {{_'r-list'}} div.trigger-dropdown - input(id="create-list-name",type=text,placeholder="{{_'r-list-name'}}") + input(id="create-list-name",type=text,placeholder="{{_'r-list-name'}}") + div.trigger-text + | {{_'r-swimlane'}} + div.trigger-dropdown + input(id="create-swimlane-name",type=text,placeholder="{{_'r-swimlane-name'}}") + div.trigger-button.trigger-button-person.js-show-user-field + i.fa.fa-user + div.user-details.hide-element + div.trigger-text + | {{_'r-by'}} + div.trigger-dropdown + input(class="user-name",type=text,placeholder="{{_'r-user-name'}}") div.trigger-button.js-add-create-trigger.js-goto-action i.fa.fa-plus - div.trigger-item + div.trigger-item#trigger-three div.trigger-content div.trigger-text - | {{_'r-when-a-card-is-moved'}} + | {{_'r-when-a-card'}} + div.trigger-inline-button.js-open-card-title-popup + i.fa.fa-filter + div.trigger-text + | {{_'r-is-moved'}} + div.trigger-button.trigger-button-person.js-show-user-field + i.fa.fa-user + div.user-details.hide-element + div.trigger-text + | {{_'r-by'}} + div.trigger-dropdown + input(class="user-name",type=text,placeholder="{{_'r-user-name'}}") div.trigger-button.js-add-gen-moved-trigger.js-goto-action i.fa.fa-plus - div.trigger-item + div.trigger-item#trigger-four div.trigger-content div.trigger-text - | {{_'r-when-a-card-is'}} + | {{_'r-when-a-card'}} + div.trigger-inline-button.js-open-card-title-popup + i.fa.fa-filter + div.trigger-text + | {{_'r-is'}} div.trigger-dropdown select(id="move-action") option(value="moved-to") {{_'r-moved-to'}} @@ -45,21 +60,55 @@ template(name="boardTriggers") div.trigger-text | {{_'r-list'}} div.trigger-dropdown - input(id="move-list-name",type=text,placeholder="{{_'r-list-name'}}") + input(id="move-list-name",type=text,placeholder="{{_'r-list-name'}}") + div.trigger-text + | {{_'r-swimlane'}} + div.trigger-dropdown + input(id="create-swimlane-name",type=text,placeholder="{{_'r-swimlane-name'}}") + div.trigger-button.trigger-button-person.js-show-user-field + div.trigger-button.trigger-button-person.js-show-user-field + i.fa.fa-user + div.user-details.hide-element + div.trigger-text + | {{_'r-by'}} + div.trigger-dropdown + input(class="user-name",type=text,placeholder="{{_'r-user-name'}}") div.trigger-button.js-add-moved-trigger.js-goto-action i.fa.fa-plus - div.trigger-item + div.trigger-item#trigger-five div.trigger-content div.trigger-text - | {{_'r-when-a-card-is'}} + | {{_'r-when-a-card'}} + div.trigger-inline-button.js-open-card-title-popup + i.fa.fa-filter + div.trigger-text + | {{_'r-is'}} div.trigger-dropdown select(id="arch-action") option(value="archived") {{_'r-archived'}} option(value="unarchived") {{_'r-unarchived'}} + div.trigger-button.trigger-button-person.js-show-user-field + i.fa.fa-user + div.user-details.hide-element + div.trigger-text + | {{_'r-by'}} + div.trigger-dropdown + input(class="user-name",type=text,placeholder="{{_'r-user-name'}}") div.trigger-button.js-add-arch-trigger.js-goto-action i.fa.fa-plus + div.trigger-item + div.trigger-content + div.trigger-text + | {{{_'r-board-note'}}} + +template(name="boardCardTitlePopup") + form + label + | Card Title Filter + input.js-card-filter-name(type="text" value=title autofocus) + input.js-card-filter-button.primary.wide(type="submit" value="{{_ 'set-filter'}}") diff --git a/client/components/rules/triggers/boardTriggers.js b/client/components/rules/triggers/boardTriggers.js index 40c5b07e..f9aa57cb 100644 --- a/client/components/rules/triggers/boardTriggers.js +++ b/client/components/rules/triggers/boardTriggers.js @@ -1,59 +1,45 @@ BlazeComponent.extendComponent({ onCreated() { - + this.provaVar = new ReactiveVar(''); + this.currentPopupTriggerId = 'def'; + this.cardTitleFilters = {}; + }, + setNameFilter(name){ + this.cardTitleFilters[this.currentPopupTriggerId] = name; }, events() { return [{ - 'click .js-add-gen-trigger' (event) { - const desc = Utils.getTriggerActionDesc(event, this); - const datas = this.data(); - const actionSelected = this.find('#gen-action').value; - const boardId = Session.get('currentBoard'); - if (actionSelected === 'created') { - datas.triggerVar.set({ - activityType: 'createCard', - boardId, - 'listName': '*', - desc, - }); - } - if (actionSelected === 'removed') { - datas.triggerVar.set({ - activityType: 'removeCard', - boardId, - desc, - }); - } - + 'click .js-open-card-title-popup'(event){ + const funct = Popup.open('boardCardTitle'); + const divId = $(event.currentTarget.parentNode.parentNode).attr('id'); + console.log('current popup'); + console.log(this.currentPopupTriggerId); + this.currentPopupTriggerId = divId; + funct.call(this, event); }, 'click .js-add-create-trigger' (event) { const desc = Utils.getTriggerActionDesc(event, this); const datas = this.data(); - const actionSelected = this.find('#create-action').value; const listName = this.find('#create-list-name').value; + const swimlaneName = this.find('#create-swimlane-name').value; const boardId = Session.get('currentBoard'); - if (actionSelected === 'created') { - datas.triggerVar.set({ - activityType: 'createCard', - boardId, - listName, - desc, - }); - } - if (actionSelected === 'removed') { - datas.triggerVar.set({ - activityType: 'removeCard', - boardId, - listName, - desc, - }); - } + const divId = $(event.currentTarget.parentNode).attr('id'); + const cardTitle = this.cardTitleFilters[divId]; + // move to generic funciont + datas.triggerVar.set({ + activityType: 'createCard', + boardId, + cardTitle, + swimlaneName, + listName, + desc, + }); }, 'click .js-add-moved-trigger' (event) { const datas = this.data(); const desc = Utils.getTriggerActionDesc(event, this); - + const swimlaneName = this.find('#create-swimlane-name').value; const actionSelected = this.find('#move-action').value; const listName = this.find('#move-list-name').value; const boardId = Session.get('currentBoard'); @@ -62,6 +48,7 @@ BlazeComponent.extendComponent({ activityType: 'moveCard', boardId, listName, + swimlaneName, 'oldListName': '*', desc, }); @@ -70,6 +57,7 @@ BlazeComponent.extendComponent({ datas.triggerVar.set({ activityType: 'moveCard', boardId, + swimlaneName, 'listName': '*', 'oldListName': listName, desc, @@ -82,8 +70,9 @@ BlazeComponent.extendComponent({ const boardId = Session.get('currentBoard'); datas.triggerVar.set({ - activityType: 'moveCard', + 'activityType': 'moveCard', boardId, + 'swimlaneName': '*', 'listName':'*', 'oldListName': '*', desc, @@ -114,3 +103,13 @@ BlazeComponent.extendComponent({ }, }).register('boardTriggers'); + + +Template.boardCardTitlePopup.events({ + submit(evt, tpl) { + const title = tpl.$('.js-card-filter-name').val().trim(); + Popup.getOpenerComponent().setNameFilter(title); + evt.preventDefault(); + Popup.close(); + }, +}); diff --git a/client/components/rules/triggers/cardTriggers.jade b/client/components/rules/triggers/cardTriggers.jade index 5226e3c4..54133451 100644 --- a/client/components/rules/triggers/cardTriggers.jade +++ b/client/components/rules/triggers/cardTriggers.jade @@ -9,6 +9,13 @@ template(name="cardTriggers") option(value="removed") {{_'r-removed-from'}} div.trigger-text | {{_'r-a-card'}} + div.trigger-button.trigger-button-person.js-show-user-field + i.fa.fa-user + div.user-details.hide-element + div.trigger-text + | {{_'r-by'}} + div.trigger-dropdown + input(class="user-name",type=text,placeholder="{{_'r-user-name'}}") div.trigger-button.js-add-gen-label-trigger.js-goto-action i.fa.fa-plus @@ -29,6 +36,13 @@ template(name="cardTriggers") option(value="removed") {{_'r-removed-from'}} div.trigger-text | {{_'r-a-card'}} + div.trigger-button.trigger-button-person.js-show-user-field + i.fa.fa-user + div.user-details.hide-element + div.trigger-text + | {{_'r-by'}} + div.trigger-dropdown + input(class="user-name",type=text,placeholder="{{_'r-user-name'}}") div.trigger-button.js-add-spec-label-trigger.js-goto-action i.fa.fa-plus @@ -42,6 +56,13 @@ template(name="cardTriggers") option(value="removed") {{_'r-removed-from'}} div.trigger-text | {{_'r-a-card'}} + div.trigger-button.trigger-button-person.js-show-user-field + i.fa.fa-user + div.user-details.hide-element + div.trigger-text + | {{_'r-by'}} + div.trigger-dropdown + input(class="user-name",type=text,placeholder="{{_'r-user-name'}}") div.trigger-button.js-add-gen-member-trigger.js-goto-action i.fa.fa-plus @@ -60,6 +81,13 @@ template(name="cardTriggers") option(value="removed") {{_'r-removed-from'}} div.trigger-text | {{_'r-a-card'}} + div.trigger-button.trigger-button-person.js-show-user-field + i.fa.fa-user + div.user-details.hide-element + div.trigger-text + | {{_'r-by'}} + div.trigger-dropdown + input(class="user-name",type=text,placeholder="{{_'r-user-name'}}") div.trigger-button.js-add-spec-member-trigger.js-goto-action i.fa.fa-plus @@ -75,5 +103,12 @@ template(name="cardTriggers") option(value="removed") {{_'r-removed-from'}} div.trigger-text | {{_'r-a-card'}} + div.trigger-button.trigger-button-person.js-show-user-field + i.fa.fa-user + div.user-details.hide-element + div.trigger-text + | {{_'r-by'}} + div.trigger-dropdown + input(class="user-name",type=text,placeholder="{{_'r-user-name'}}") div.trigger-button.js-add-attachment-trigger.js-goto-action i.fa.fa-plus diff --git a/client/components/rules/triggers/checklistTriggers.jade b/client/components/rules/triggers/checklistTriggers.jade index c6cd99a6..8745b364 100644 --- a/client/components/rules/triggers/checklistTriggers.jade +++ b/client/components/rules/triggers/checklistTriggers.jade @@ -9,6 +9,13 @@ template(name="checklistTriggers") option(value="removed") {{_'r-removed-from'}} div.trigger-text | {{_'r-a-card'}} + div.trigger-button.trigger-button-person.js-show-user-field + i.fa.fa-user + div.user-details.hide-element + div.trigger-text + | {{_'r-by'}} + div.trigger-dropdown + input(class="user-name",type=text,placeholder="{{_'r-user-name'}}") div.trigger-button.js-add-gen-check-trigger.js-goto-action i.fa.fa-plus @@ -27,6 +34,13 @@ template(name="checklistTriggers") option(value="removed") {{_'r-removed-from'}} div.trigger-text | {{_'r-a-card'}} + div.trigger-button.trigger-button-person.js-show-user-field + i.fa.fa-user + div.user-details.hide-element + div.trigger-text + | {{_'r-by'}} + div.trigger-dropdown + input(class="user-name",type=text,placeholder="{{_'r-user-name'}}") div.trigger-button.js-add-spec-check-trigger.js-goto-action i.fa.fa-plus @@ -38,6 +52,13 @@ template(name="checklistTriggers") select(id="gen-comp-check-action") option(value="completed") {{_'r-completed'}} option(value="uncompleted") {{_'r-made-incomplete'}} + div.trigger-button.trigger-button-person.js-show-user-field + i.fa.fa-user + div.user-details.hide-element + div.trigger-text + | {{_'r-by'}} + div.trigger-dropdown + input(class="user-name",type=text,placeholder="{{_'r-user-name'}}") div.trigger-button.js-add-gen-comp-trigger.js-goto-action i.fa.fa-plus @@ -53,6 +74,13 @@ template(name="checklistTriggers") select(id="spec-comp-check-action") option(value="completed") {{_'r-completed'}} option(value="uncompleted") {{_'r-made-incomplete'}} + div.trigger-button.trigger-button-person.js-show-user-field + i.fa.fa-user + div.user-details.hide-element + div.trigger-text + | {{_'r-by'}} + div.trigger-dropdown + input(class="user-name",type=text,placeholder="{{_'r-user-name'}}") div.trigger-button.js-add-spec-comp-trigger.js-goto-action i.fa.fa-plus @@ -64,6 +92,13 @@ template(name="checklistTriggers") select(id="check-item-gen-action") option(value="checked") {{_'r-checked'}} option(value="unchecked") {{_'r-unchecked'}} + div.trigger-button.trigger-button-person.js-show-user-field + i.fa.fa-user + div.user-details.hide-element + div.trigger-text + | {{_'r-by'}} + div.trigger-dropdown + input(class="user-name",type=text,placeholder="{{_'r-user-name'}}") div.trigger-button.js-add-gen-check-item-trigger.js-goto-action i.fa.fa-plus @@ -79,5 +114,12 @@ template(name="checklistTriggers") select(id="check-item-spec-action") option(value="checked") {{_'r-checked'}} option(value="unchecked") {{_'r-unchecked'}} + div.trigger-button.trigger-button-person.js-show-user-field + i.fa.fa-user + div.user-details.hide-element + div.trigger-text + | {{_'r-by'}} + div.trigger-dropdown + input(class="user-name",type=text,placeholder="{{_'r-user-name'}}") div.trigger-button.js-add-spec-check-item-trigger.js-goto-action i.fa.fa-plus |