Fix custom attributes
parent
d905b05977
commit
2c729b2edf
|
@ -374,6 +374,27 @@ module.directive("tgColorSelection", ColorSelectionDirective)
|
|||
## 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)
|
||||
@.$inject = [
|
||||
"$scope",
|
||||
|
@ -390,6 +411,8 @@ class ProjectCustomAttributesController extends mixOf(taiga.Controller, taiga.Pa
|
|||
|
||||
constructor: (@scope, @rootscope, @repo, @rs, @params, @q, @location, @navUrls, @appMetaService,
|
||||
@translate) ->
|
||||
@scope.TYPE_CHOICES = TYPE_CHOICES
|
||||
|
||||
@scope.project = {}
|
||||
|
||||
@rootscope.$on "project:loaded", =>
|
||||
|
|
|
@ -27,6 +27,28 @@ generateHash = taiga.generateHash
|
|||
|
||||
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
|
||||
@.$inject = ["$scope", "$rootScope", "$tgRepo", "$tgResources", "$tgConfirm", "$q"]
|
||||
|
@ -118,7 +140,8 @@ CustomAttributesValuesDirective = ($templates, $storage) ->
|
|||
template: templateFn
|
||||
}
|
||||
|
||||
module.directive("tgCustomAttributesValues", ["$tgTemplate", "$tgStorage", "$translate", CustomAttributesValuesDirective])
|
||||
module.directive("tgCustomAttributesValues", ["$tgTemplate", "$tgStorage", "$translate",
|
||||
CustomAttributesValuesDirective])
|
||||
|
||||
|
||||
CustomAttributeValueDirective = ($template, $selectedText, $compile, $translate, datePickerConfigService) ->
|
||||
|
@ -130,7 +153,6 @@ CustomAttributeValueDirective = ($template, $selectedText, $compile, $translate,
|
|||
|
||||
render = (attributeValue, edit=false) ->
|
||||
value = attributeValue.value
|
||||
innerText = attributeValue.value
|
||||
editable = isEditable()
|
||||
ctx = {
|
||||
id: attributeValue.id
|
||||
|
@ -138,7 +160,7 @@ CustomAttributeValueDirective = ($template, $selectedText, $compile, $translate,
|
|||
description: attributeValue.description
|
||||
value: value
|
||||
isEditable: editable
|
||||
field_type: attributeValue.field_type
|
||||
type: attributeValue.type
|
||||
}
|
||||
|
||||
if editable and (edit or not value)
|
||||
|
@ -150,18 +172,17 @@ CustomAttributeValueDirective = ($template, $selectedText, $compile, $translate,
|
|||
|
||||
$el.html(html)
|
||||
|
||||
if attributeValue.field_type == "DATE"
|
||||
if attributeValue.type == DATE_TYPE
|
||||
datePickerConfig = datePickerConfigService.get()
|
||||
|
||||
_.merge(datePickerConfig, {
|
||||
field: $el.find('input')[0]
|
||||
field: $el.find("input[name=value]")[0]
|
||||
onSelect: (date) =>
|
||||
selectedDate = date
|
||||
onOpen: =>
|
||||
$el.picker.setDate(selectedDate) if selectedDate?
|
||||
})
|
||||
|
||||
selectedDate = null
|
||||
$el.picker = new Pikaday(datePickerConfig)
|
||||
|
||||
isEditable = ->
|
||||
|
@ -170,28 +191,32 @@ CustomAttributeValueDirective = ($template, $selectedText, $compile, $translate,
|
|||
return permissions.indexOf(requiredEditionPerm) > -1
|
||||
|
||||
saveAttributeValue = ->
|
||||
attributeValue.value = $el.find("input, textarea").val()
|
||||
|
||||
if attributeValue.field_type == "DATE"
|
||||
if attributeValue.value
|
||||
return if moment(attributeValue.value).isValid() != true
|
||||
attributeValue.value = $el.find("input[name=value], textarea[name='value']").val()
|
||||
|
||||
if attributeValue.type is DATE_TYPE
|
||||
if moment(attributeValue.value, prettyDate).isValid()
|
||||
attributeValue.value = moment(attributeValue.value, prettyDate).format("YYYY-MM-DD")
|
||||
else
|
||||
attributeValue.reset()
|
||||
return
|
||||
|
||||
$scope.$apply ->
|
||||
$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)
|
||||
|
||||
render(attributeValue, false)
|
||||
|
||||
$el.on "keyup", "input[name=description], textarea[name='description']", (event) ->
|
||||
if event.keyCode == 13 and event.currentTarget.type != "textarea"
|
||||
submit(event)
|
||||
else if event.keyCode == 27
|
||||
return if attributeValue.field_type == "DATE" and moment(attributeValue.value).isValid() != true
|
||||
submit = debounce 2000, (event) =>
|
||||
event.preventDefault()
|
||||
saveAttributeValue()
|
||||
|
||||
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)
|
||||
$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()
|
||||
|
||||
## Actions (on edit mode)
|
||||
submit = debounce 2000, (event) =>
|
||||
event.preventDefault()
|
||||
saveAttributeValue()
|
||||
$el.on "keyup", "input[name=value], textarea[name='value']", (event) ->
|
||||
if event.keyCode is 13 and event.currentTarget.type isnt "textarea"
|
||||
submit(event)
|
||||
else if event.keyCode == 27
|
||||
render(attributeValue, false)
|
||||
|
||||
$el.on "submit", "form", submit
|
||||
|
||||
$el.on "click", "a.icon-floppy", submit
|
||||
|
||||
$scope.$on "$destroy", ->
|
||||
$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 {
|
||||
link: link
|
||||
require: "^tgCustomAttributesValues"
|
||||
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
|
||||
div.custom-field-data
|
||||
label.custom-field-name(for="custom-field-description")
|
||||
label.custom-field-name(for="custom-field-value")
|
||||
<%- name %>
|
||||
<% if (description){ %>
|
||||
span.custom-field-description
|
||||
|
@ -8,22 +8,15 @@ form.custom-field-single.editable
|
|||
<% } %>
|
||||
|
||||
div.custom-field-value
|
||||
|
||||
<% if (field_type=="MULTI") { %>
|
||||
textarea#custom-field-description(name="description")
|
||||
<%- value %>
|
||||
<% } %>
|
||||
|
||||
<% if (field_type=="TEXT") { %>
|
||||
input#custom-field-description(name="description", 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!="")
|
||||
//- See TYPE_CHOICES in app/coffee/modules/common/custom-field-values.coffee
|
||||
<% if (type=="text") { %>
|
||||
input#custom-field-value(name="value", type="text", value!="<%- value %>")
|
||||
<% } else if (type=="multiline") { %>
|
||||
textarea#custom-field-value(name="value") <%- value %>
|
||||
<% } else if (type=="date") { %>
|
||||
input#custom-field-value(name="value", type="text", value!="<%- value %>")
|
||||
<% } else { %>
|
||||
input#custom-field-value(name="value", type="text", value!="<%- value %>")
|
||||
<% } %>
|
||||
|
||||
div.custom-field-options
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
section.custom-fields-table.basic-table
|
||||
div.project-values-title
|
||||
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")
|
||||
|
||||
div.table-header
|
||||
|
@ -24,40 +27,84 @@ section.custom-fields-table.basic-table
|
|||
span {{ attr.name }}
|
||||
div.custom-description
|
||||
span {{ attr.description }}
|
||||
div.custom-field-type
|
||||
span(translate="ADMIN.CUSTOM_FIELDS.FIELD_TYPE_{{ attr.field_type }}")
|
||||
div.custom-field-type(ng-switch on="attr.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-wrapper
|
||||
a.js-edit-custom-field-button.icon.icon-edit(href="", title="{{'ADMIN.CUSTOM_ATTRIBUTES.EDIT' | translate}}")
|
||||
a.js-delete-custom-field-button.icon.icon-delete(href="", title="{{'ADMIN.CUSTOM_ATTRIBUTES.DELETE' | translate}}")
|
||||
a.js-edit-custom-field-button.icon.icon-edit(
|
||||
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
|
||||
fieldset.custom-name
|
||||
input(type="text", name="name", placeholder="{{'ADMIN.CUSTOM_ATTRIBUTES.SET_FIELD_NAME' | translate}}",
|
||||
ng-model="attr.name", data-required="true" data-maxlength="64")
|
||||
input(
|
||||
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
|
||||
input(type="text", name="description", placeholder="{{'ADMIN.CUSTOM_ATTRIBUTES.SET_FIELD_DESCRIPTION' | translate}}",
|
||||
ng-model="attr.description")
|
||||
input(
|
||||
type="text"
|
||||
name="description"
|
||||
placeholder="{{'ADMIN.CUSTOM_ATTRIBUTES.SET_FIELD_DESCRIPTION' | translate}}"
|
||||
ng-model="attr.description"
|
||||
)
|
||||
fieldset.custom-field-type
|
||||
select(ng-model="attr.field_type",
|
||||
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'}]")
|
||||
select(
|
||||
ng-model="attr.type"
|
||||
ng-options="type.key as type.name | translate for type in TYPE_CHOICES"
|
||||
)
|
||||
fieldset.custom-options
|
||||
div.custom-options-wrapper
|
||||
a.js-update-custom-field-button.icon.icon-floppy(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}}")
|
||||
a.js-update-custom-field-button.icon.icon-floppy(
|
||||
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
|
||||
fieldset.custom-name
|
||||
input(type="text", name="name", placeholder="{{'ADMIN.CUSTOM_ATTRIBUTES.SET_FIELD_NAME' | translate}}",
|
||||
ng-model="newAttr.name", data-required="true", data-maxlength="64")
|
||||
input(
|
||||
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
|
||||
input(type="text", name="description", placeholder="{{'ADMIN.CUSTOM_ATTRIBUTES.SET_FIELD_DESCRIPTION' | translate}}",
|
||||
ng-model="newAttr.description")
|
||||
input(
|
||||
type="text"
|
||||
name="description"
|
||||
placeholder="{{'ADMIN.CUSTOM_ATTRIBUTES.SET_FIELD_DESCRIPTION' | translate}}"
|
||||
ng-model="newAttr.description"
|
||||
)
|
||||
fieldset.custom-field-type
|
||||
select(ng-model="newAttr.field_type",
|
||||
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'}]")
|
||||
|
||||
select(
|
||||
ng-model="newAttr.type"
|
||||
ng-options="type.key as type.name for type in TYPE_CHOICES"
|
||||
)
|
||||
fieldset.custom-options
|
||||
div.custom-options-wrapper
|
||||
a.js-create-custom-field-button.icon.icon-floppy(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}}")
|
||||
a.js-create-custom-field-button.icon.icon-floppy(
|
||||
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