Fix custom attributes
parent
d905b05977
commit
2c729b2edf
|
@ -374,6 +374,27 @@ module.directive("tgColorSelection", ColorSelectionDirective)
|
||||||
## Custom Attributes Controller
|
## Custom Attributes Controller
|
||||||
#############################################################################
|
#############################################################################
|
||||||
|
|
||||||
|
# Custom attributes types (see taiga-back/taiga/projects/custom_attributes/choices.py)
|
||||||
|
TEXT_TYPE = "text"
|
||||||
|
MULTILINE_TYPE = "multiline"
|
||||||
|
DATE_TYPE = "date"
|
||||||
|
|
||||||
|
|
||||||
|
TYPE_CHOICES = [
|
||||||
|
{
|
||||||
|
key: TEXT_TYPE,
|
||||||
|
name: "ADMIN.CUSTOM_FIELDS.FIELD_TYPE_TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: MULTILINE_TYPE,
|
||||||
|
name: "ADMIN.CUSTOM_FIELDS.FIELD_TYPE_MULTI"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: DATE_TYPE,
|
||||||
|
name: "ADMIN.CUSTOM_FIELDS.FIELD_TYPE_DATE"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
class ProjectCustomAttributesController extends mixOf(taiga.Controller, taiga.PageMixin)
|
class ProjectCustomAttributesController extends mixOf(taiga.Controller, taiga.PageMixin)
|
||||||
@.$inject = [
|
@.$inject = [
|
||||||
"$scope",
|
"$scope",
|
||||||
|
@ -390,6 +411,8 @@ class ProjectCustomAttributesController extends mixOf(taiga.Controller, taiga.Pa
|
||||||
|
|
||||||
constructor: (@scope, @rootscope, @repo, @rs, @params, @q, @location, @navUrls, @appMetaService,
|
constructor: (@scope, @rootscope, @repo, @rs, @params, @q, @location, @navUrls, @appMetaService,
|
||||||
@translate) ->
|
@translate) ->
|
||||||
|
@scope.TYPE_CHOICES = TYPE_CHOICES
|
||||||
|
|
||||||
@scope.project = {}
|
@scope.project = {}
|
||||||
|
|
||||||
@rootscope.$on "project:loaded", =>
|
@rootscope.$on "project:loaded", =>
|
||||||
|
|
|
@ -27,6 +27,28 @@ generateHash = taiga.generateHash
|
||||||
|
|
||||||
module = angular.module("taigaCommon")
|
module = angular.module("taigaCommon")
|
||||||
|
|
||||||
|
# Custom attributes types (see taiga-back/taiga/projects/custom_attributes/choices.py)
|
||||||
|
TEXT_TYPE = "text"
|
||||||
|
MULTILINE_TYPE = "multiline"
|
||||||
|
DATE_TYPE = "date"
|
||||||
|
|
||||||
|
|
||||||
|
TYPE_CHOICES = [
|
||||||
|
{
|
||||||
|
key: TEXT_TYPE,
|
||||||
|
name: "ADMIN.CUSTOM_FIELDS.FIELD_TYPE_TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: MULTILINE_TYPE,
|
||||||
|
name: "ADMIN.CUSTOM_FIELDS.FIELD_TYPE_MULTI"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: DATE_TYPE,
|
||||||
|
name: "ADMIN.CUSTOM_FIELDS.FIELD_TYPE_DATE"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class CustomAttributesValuesController extends taiga.Controller
|
class CustomAttributesValuesController extends taiga.Controller
|
||||||
@.$inject = ["$scope", "$rootScope", "$tgRepo", "$tgResources", "$tgConfirm", "$q"]
|
@.$inject = ["$scope", "$rootScope", "$tgRepo", "$tgResources", "$tgConfirm", "$q"]
|
||||||
|
@ -118,7 +140,8 @@ CustomAttributesValuesDirective = ($templates, $storage) ->
|
||||||
template: templateFn
|
template: templateFn
|
||||||
}
|
}
|
||||||
|
|
||||||
module.directive("tgCustomAttributesValues", ["$tgTemplate", "$tgStorage", "$translate", CustomAttributesValuesDirective])
|
module.directive("tgCustomAttributesValues", ["$tgTemplate", "$tgStorage", "$translate",
|
||||||
|
CustomAttributesValuesDirective])
|
||||||
|
|
||||||
|
|
||||||
CustomAttributeValueDirective = ($template, $selectedText, $compile, $translate, datePickerConfigService) ->
|
CustomAttributeValueDirective = ($template, $selectedText, $compile, $translate, datePickerConfigService) ->
|
||||||
|
@ -130,7 +153,6 @@ CustomAttributeValueDirective = ($template, $selectedText, $compile, $translate,
|
||||||
|
|
||||||
render = (attributeValue, edit=false) ->
|
render = (attributeValue, edit=false) ->
|
||||||
value = attributeValue.value
|
value = attributeValue.value
|
||||||
innerText = attributeValue.value
|
|
||||||
editable = isEditable()
|
editable = isEditable()
|
||||||
ctx = {
|
ctx = {
|
||||||
id: attributeValue.id
|
id: attributeValue.id
|
||||||
|
@ -138,7 +160,7 @@ CustomAttributeValueDirective = ($template, $selectedText, $compile, $translate,
|
||||||
description: attributeValue.description
|
description: attributeValue.description
|
||||||
value: value
|
value: value
|
||||||
isEditable: editable
|
isEditable: editable
|
||||||
field_type: attributeValue.field_type
|
type: attributeValue.type
|
||||||
}
|
}
|
||||||
|
|
||||||
if editable and (edit or not value)
|
if editable and (edit or not value)
|
||||||
|
@ -150,18 +172,17 @@ CustomAttributeValueDirective = ($template, $selectedText, $compile, $translate,
|
||||||
|
|
||||||
$el.html(html)
|
$el.html(html)
|
||||||
|
|
||||||
if attributeValue.field_type == "DATE"
|
if attributeValue.type == DATE_TYPE
|
||||||
datePickerConfig = datePickerConfigService.get()
|
datePickerConfig = datePickerConfigService.get()
|
||||||
|
|
||||||
_.merge(datePickerConfig, {
|
_.merge(datePickerConfig, {
|
||||||
field: $el.find('input')[0]
|
field: $el.find("input[name=value]")[0]
|
||||||
onSelect: (date) =>
|
onSelect: (date) =>
|
||||||
selectedDate = date
|
selectedDate = date
|
||||||
onOpen: =>
|
onOpen: =>
|
||||||
$el.picker.setDate(selectedDate) if selectedDate?
|
$el.picker.setDate(selectedDate) if selectedDate?
|
||||||
})
|
})
|
||||||
|
|
||||||
selectedDate = null
|
|
||||||
$el.picker = new Pikaday(datePickerConfig)
|
$el.picker = new Pikaday(datePickerConfig)
|
||||||
|
|
||||||
isEditable = ->
|
isEditable = ->
|
||||||
|
@ -170,28 +191,32 @@ CustomAttributeValueDirective = ($template, $selectedText, $compile, $translate,
|
||||||
return permissions.indexOf(requiredEditionPerm) > -1
|
return permissions.indexOf(requiredEditionPerm) > -1
|
||||||
|
|
||||||
saveAttributeValue = ->
|
saveAttributeValue = ->
|
||||||
attributeValue.value = $el.find("input, textarea").val()
|
attributeValue.value = $el.find("input[name=value], textarea[name='value']").val()
|
||||||
|
|
||||||
if attributeValue.field_type == "DATE"
|
|
||||||
if attributeValue.value
|
|
||||||
return if moment(attributeValue.value).isValid() != true
|
|
||||||
|
|
||||||
|
if attributeValue.type is DATE_TYPE
|
||||||
|
if moment(attributeValue.value, prettyDate).isValid()
|
||||||
attributeValue.value = moment(attributeValue.value, prettyDate).format("YYYY-MM-DD")
|
attributeValue.value = moment(attributeValue.value, prettyDate).format("YYYY-MM-DD")
|
||||||
|
else
|
||||||
|
attributeValue.reset()
|
||||||
|
return
|
||||||
|
|
||||||
$scope.$apply ->
|
$scope.$apply ->
|
||||||
$ctrl.updateAttributeValue(attributeValue).then ->
|
$ctrl.updateAttributeValue(attributeValue).then ->
|
||||||
if attributeValue.field_type == "DATE" and attributeValue.value
|
if attributeValue.type is "DATE_TYPE" and attributeValue.value
|
||||||
attributeValue.value = moment(attributeValue.value, "YYYY-MM-DD").format(prettyDate)
|
attributeValue.value = moment(attributeValue.value, "YYYY-MM-DD").format(prettyDate)
|
||||||
|
|
||||||
render(attributeValue, false)
|
render(attributeValue, false)
|
||||||
|
|
||||||
$el.on "keyup", "input[name=description], textarea[name='description']", (event) ->
|
submit = debounce 2000, (event) =>
|
||||||
if event.keyCode == 13 and event.currentTarget.type != "textarea"
|
event.preventDefault()
|
||||||
submit(event)
|
saveAttributeValue()
|
||||||
else if event.keyCode == 27
|
|
||||||
return if attributeValue.field_type == "DATE" and moment(attributeValue.value).isValid() != true
|
|
||||||
|
|
||||||
render(attributeValue, false)
|
# Bootstrap
|
||||||
|
attributeValue = $scope.$eval($attrs.tgCustomAttributeValue)
|
||||||
|
if attributeValue.type is DATE_TYPE and attributeValue.value
|
||||||
|
attributeValue.value = moment(attributeValue.value, "YYYY-MM-DD").format(prettyDate)
|
||||||
|
|
||||||
|
render(attributeValue)
|
||||||
|
|
||||||
## Actions (on view mode)
|
## Actions (on view mode)
|
||||||
$el.on "click", ".custom-field-value.read-mode", ->
|
$el.on "click", ".custom-field-value.read-mode", ->
|
||||||
|
@ -206,28 +231,24 @@ CustomAttributeValueDirective = ($template, $selectedText, $compile, $translate,
|
||||||
$el.find("input[name='description'], textarea[name='description']").focus().select()
|
$el.find("input[name='description'], textarea[name='description']").focus().select()
|
||||||
|
|
||||||
## Actions (on edit mode)
|
## Actions (on edit mode)
|
||||||
submit = debounce 2000, (event) =>
|
$el.on "keyup", "input[name=value], textarea[name='value']", (event) ->
|
||||||
event.preventDefault()
|
if event.keyCode is 13 and event.currentTarget.type isnt "textarea"
|
||||||
saveAttributeValue()
|
submit(event)
|
||||||
|
else if event.keyCode == 27
|
||||||
|
render(attributeValue, false)
|
||||||
|
|
||||||
$el.on "submit", "form", submit
|
$el.on "submit", "form", submit
|
||||||
|
|
||||||
$el.on "click", "a.icon-floppy", submit
|
$el.on "click", "a.icon-floppy", submit
|
||||||
|
|
||||||
$scope.$on "$destroy", ->
|
$scope.$on "$destroy", ->
|
||||||
$el.off()
|
$el.off()
|
||||||
|
|
||||||
# Bootstrap
|
|
||||||
attributeValue = $scope.$eval($attrs.tgCustomAttributeValue)
|
|
||||||
|
|
||||||
if attributeValue.field_type == "DATE" and attributeValue.value
|
|
||||||
attributeValue.value = moment(attributeValue.value, "YYYY-MM-DD").format(prettyDate)
|
|
||||||
|
|
||||||
render(attributeValue)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
link: link
|
link: link
|
||||||
require: "^tgCustomAttributesValues"
|
require: "^tgCustomAttributesValues"
|
||||||
restrict: "AE"
|
restrict: "AE"
|
||||||
}
|
}
|
||||||
|
|
||||||
module.directive("tgCustomAttributeValue", ["$tgTemplate", "$selectedText", "$compile", "$translate", "tgDatePickerConfigService", CustomAttributeValueDirective])
|
module.directive("tgCustomAttributeValue", ["$tgTemplate", "$selectedText", "$compile", "$translate",
|
||||||
|
"tgDatePickerConfigService", CustomAttributeValueDirective])
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
form.custom-field-single.editable
|
form.custom-field-single.editable
|
||||||
div.custom-field-data
|
div.custom-field-data
|
||||||
label.custom-field-name(for="custom-field-description")
|
label.custom-field-name(for="custom-field-value")
|
||||||
<%- name %>
|
<%- name %>
|
||||||
<% if (description){ %>
|
<% if (description){ %>
|
||||||
span.custom-field-description
|
span.custom-field-description
|
||||||
|
@ -8,22 +8,15 @@ form.custom-field-single.editable
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
||||||
div.custom-field-value
|
div.custom-field-value
|
||||||
|
//- See TYPE_CHOICES in app/coffee/modules/common/custom-field-values.coffee
|
||||||
<% if (field_type=="MULTI") { %>
|
<% if (type=="text") { %>
|
||||||
textarea#custom-field-description(name="description")
|
input#custom-field-value(name="value", type="text", value!="<%- value %>")
|
||||||
<%- value %>
|
<% } else if (type=="multiline") { %>
|
||||||
<% } %>
|
textarea#custom-field-value(name="value") <%- value %>
|
||||||
|
<% } else if (type=="date") { %>
|
||||||
<% if (field_type=="TEXT") { %>
|
input#custom-field-value(name="value", type="text", value!="<%- value %>")
|
||||||
input#custom-field-description(name="description", type="text", value!="<%- value %>")
|
<% } else { %>
|
||||||
<% } %>
|
input#custom-field-value(name="value", type="text", value!="<%- value %>")
|
||||||
|
|
||||||
<% if (field_type=="DATE" && value!="") { %>
|
|
||||||
input#custom-field-description(name="description", type="text", value!="<%- moment(value).format('DD MMM YYYY') %>")
|
|
||||||
<% } %>
|
|
||||||
|
|
||||||
<% if (field_type=="DATE" && value=="") { %>
|
|
||||||
input#custom-field-description(name="description", type="text", value!="")
|
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
||||||
div.custom-field-options
|
div.custom-field-options
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
section.custom-fields-table.basic-table
|
section.custom-fields-table.basic-table
|
||||||
div.project-values-title
|
div.project-values-title
|
||||||
h2 {{ customFieldSectionTitle | translate }}
|
h2 {{ customFieldSectionTitle | translate }}
|
||||||
a.button.button-gray.show-add-new.js-add-custom-field-button(href="", title="{{ customFieldButtonTitle | translate }}")
|
a.button.button-gray.show-add-new.js-add-custom-field-button(
|
||||||
|
href=""
|
||||||
|
title="{{ customFieldButtonTitle | translate }}"
|
||||||
|
)
|
||||||
span(translate="ADMIN.CUSTOM_ATTRIBUTES.ADD")
|
span(translate="ADMIN.CUSTOM_ATTRIBUTES.ADD")
|
||||||
|
|
||||||
div.table-header
|
div.table-header
|
||||||
|
@ -24,40 +27,84 @@ section.custom-fields-table.basic-table
|
||||||
span {{ attr.name }}
|
span {{ attr.name }}
|
||||||
div.custom-description
|
div.custom-description
|
||||||
span {{ attr.description }}
|
span {{ attr.description }}
|
||||||
div.custom-field-type
|
div.custom-field-type(ng-switch on="attr.type")
|
||||||
span(translate="ADMIN.CUSTOM_FIELDS.FIELD_TYPE_{{ attr.field_type }}")
|
//- See TYPE_CHOICES in app/coffee/modules/admin/project-values.coffee
|
||||||
|
span(ng-switch-default, translate="ADMIN.CUSTOM_FIELDS.FIELD_TYPE_TEXT")
|
||||||
|
span(ng-switch-when="multiline", translate="ADMIN.CUSTOM_FIELDS.FIELD_TYPE_MULTI")
|
||||||
|
span(ng-switch-when="date", translate="ADMIN.CUSTOM_FIELDS.FIELD_TYPE_DATE")
|
||||||
div.custom-options
|
div.custom-options
|
||||||
div.custom-options-wrapper
|
div.custom-options-wrapper
|
||||||
a.js-edit-custom-field-button.icon.icon-edit(href="", title="{{'ADMIN.CUSTOM_ATTRIBUTES.EDIT' | translate}}")
|
a.js-edit-custom-field-button.icon.icon-edit(
|
||||||
a.js-delete-custom-field-button.icon.icon-delete(href="", title="{{'ADMIN.CUSTOM_ATTRIBUTES.DELETE' | translate}}")
|
href=""
|
||||||
|
title="{{'ADMIN.CUSTOM_ATTRIBUTES.EDIT' | translate}}"
|
||||||
|
)
|
||||||
|
a.js-delete-custom-field-button.icon.icon-delete(
|
||||||
|
href=""
|
||||||
|
title="{{'ADMIN.CUSTOM_ATTRIBUTES.DELETE' | translate}}"
|
||||||
|
)
|
||||||
|
|
||||||
div.row.single-custom-field.js-edit-custom-field.hidden
|
div.row.single-custom-field.js-edit-custom-field.hidden
|
||||||
fieldset.custom-name
|
fieldset.custom-name
|
||||||
input(type="text", name="name", placeholder="{{'ADMIN.CUSTOM_ATTRIBUTES.SET_FIELD_NAME' | translate}}",
|
input(
|
||||||
ng-model="attr.name", data-required="true" data-maxlength="64")
|
type="text"
|
||||||
|
name="name"
|
||||||
|
placeholder="{{'ADMIN.CUSTOM_ATTRIBUTES.SET_FIELD_NAME' | translate}}"
|
||||||
|
ng-model="attr.name"
|
||||||
|
data-required="true"
|
||||||
|
data-maxlength="64"
|
||||||
|
)
|
||||||
fieldset.custom-description
|
fieldset.custom-description
|
||||||
input(type="text", name="description", placeholder="{{'ADMIN.CUSTOM_ATTRIBUTES.SET_FIELD_DESCRIPTION' | translate}}",
|
input(
|
||||||
ng-model="attr.description")
|
type="text"
|
||||||
|
name="description"
|
||||||
|
placeholder="{{'ADMIN.CUSTOM_ATTRIBUTES.SET_FIELD_DESCRIPTION' | translate}}"
|
||||||
|
ng-model="attr.description"
|
||||||
|
)
|
||||||
fieldset.custom-field-type
|
fieldset.custom-field-type
|
||||||
select(ng-model="attr.field_type",
|
select(
|
||||||
ng-options="e.id as e.name | translate for e in [{'id':'TEXT', 'name': 'ADMIN.CUSTOM_FIELDS.FIELD_TYPE_TEXT'},{'id':'MULTI', 'name': 'ADMIN.CUSTOM_FIELDS.FIELD_TYPE_MULTI'},{'id':'DATE', 'name': 'ADMIN.CUSTOM_FIELDS.FIELD_TYPE_DATE'}]")
|
ng-model="attr.type"
|
||||||
|
ng-options="type.key as type.name | translate for type in TYPE_CHOICES"
|
||||||
|
)
|
||||||
fieldset.custom-options
|
fieldset.custom-options
|
||||||
div.custom-options-wrapper
|
div.custom-options-wrapper
|
||||||
a.js-update-custom-field-button.icon.icon-floppy(href="", title="{{'ADMIN.CUSTOM_ATTRIBUTES.ACTION_UPDATE' | translate}}")
|
a.js-update-custom-field-button.icon.icon-floppy(
|
||||||
a.js-cancel-edit-custom-field-button.icon.icon-delete(href="", title="{{'ADMIN.CUSTOM_ATTRIBUTES.ACTION_CANCEL_EDITION' | translate}}")
|
href=""
|
||||||
|
title="{{'ADMIN.CUSTOM_ATTRIBUTES.ACTION_UPDATE' | translate}}"
|
||||||
|
)
|
||||||
|
a.js-cancel-edit-custom-field-button.icon.icon-delete(
|
||||||
|
href=""
|
||||||
|
title="{{'ADMIN.CUSTOM_ATTRIBUTES.ACTION_CANCEL_EDITION' | translate}}"
|
||||||
|
)
|
||||||
|
|
||||||
form.row.single-custom-field.js-new-custom-field.hidden
|
form.row.single-custom-field.js-new-custom-field.hidden
|
||||||
fieldset.custom-name
|
fieldset.custom-name
|
||||||
input(type="text", name="name", placeholder="{{'ADMIN.CUSTOM_ATTRIBUTES.SET_FIELD_NAME' | translate}}",
|
input(
|
||||||
ng-model="newAttr.name", data-required="true", data-maxlength="64")
|
type="text"
|
||||||
|
name="name"
|
||||||
|
placeholder="{{'ADMIN.CUSTOM_ATTRIBUTES.SET_FIELD_NAME' | translate}}"
|
||||||
|
ng-model="newAttr.name"
|
||||||
|
data-required="true"
|
||||||
|
data-maxlength="64"
|
||||||
|
)
|
||||||
fieldset.custom-description
|
fieldset.custom-description
|
||||||
input(type="text", name="description", placeholder="{{'ADMIN.CUSTOM_ATTRIBUTES.SET_FIELD_DESCRIPTION' | translate}}",
|
input(
|
||||||
ng-model="newAttr.description")
|
type="text"
|
||||||
|
name="description"
|
||||||
|
placeholder="{{'ADMIN.CUSTOM_ATTRIBUTES.SET_FIELD_DESCRIPTION' | translate}}"
|
||||||
|
ng-model="newAttr.description"
|
||||||
|
)
|
||||||
fieldset.custom-field-type
|
fieldset.custom-field-type
|
||||||
select(ng-model="newAttr.field_type",
|
select(
|
||||||
ng-options="e.id as e.name | translate for e in [{'id':'TEXT', 'name': 'ADMIN.CUSTOM_FIELDS.FIELD_TYPE_TEXT'},{'id':'MULTI', 'name': 'ADMIN.CUSTOM_FIELDS.FIELD_TYPE_MULTI'},{'id':'DATE', 'name': 'ADMIN.CUSTOM_FIELDS.FIELD_TYPE_DATE'}]")
|
ng-model="newAttr.type"
|
||||||
|
ng-options="type.key as type.name for type in TYPE_CHOICES"
|
||||||
|
)
|
||||||
fieldset.custom-options
|
fieldset.custom-options
|
||||||
div.custom-options-wrapper
|
div.custom-options-wrapper
|
||||||
a.js-create-custom-field-button.icon.icon-floppy(href="", title="{{'ADMIN.CUSTOM_ATTRIBUTES.SAVE_TITLE' | translate}}")
|
a.js-create-custom-field-button.icon.icon-floppy(
|
||||||
a.js-cancel-new-custom-field-button.icon.icon-delete(href="", title="{{'ADMIN.CUSTOM_ATTRIBUTES.CANCEL_TITLE' | translate}}")
|
href=""
|
||||||
|
title="{{'ADMIN.CUSTOM_ATTRIBUTES.SAVE_TITLE' | translate}}"
|
||||||
|
)
|
||||||
|
a.js-cancel-new-custom-field-button.icon.icon-delete(
|
||||||
|
href=""
|
||||||
|
title="{{'ADMIN.CUSTOM_ATTRIBUTES.CANCEL_TITLE' | translate}}"
|
||||||
|
)
|
||||||
|
|
Loading…
Reference in New Issue