Redesign Taiga modules

stable
Xavier Julián 2016-02-22 16:30:00 +01:00 committed by David Barragán Merino
parent 8cc02a9cbf
commit fd45a02fef
8 changed files with 252 additions and 182 deletions

View File

@ -6,6 +6,7 @@
### Features ### Features
- Ability to create url custom fields. (thanks to [@astagi](https://github.com/astagi)). - Ability to create url custom fields. (thanks to [@astagi](https://github.com/astagi)).
- Moved from iconfont to SVG sprite icon system and redesign. - Moved from iconfont to SVG sprite icon system and redesign.
- Redesign 'Admin > Project > Modules' panel.
- Add badge to project owners - Add badge to project owners
### Misc ### Misc

View File

@ -207,41 +207,51 @@ ProjectModulesDirective = ($repo, $confirm, $loading, projectService) ->
link = ($scope, $el, $attrs) -> link = ($scope, $el, $attrs) ->
submit = => submit = =>
form = $el.find("form").checksley() form = $el.find("form").checksley()
form.initializeFields() # Need to reset the form constrains
form.reset() # Need to reset the form constrains
return if not form.validate() return if not form.validate()
target = angular.element(".admin-functionalities .submit-button")
currentLoading = $loading()
.target(target)
.start()
promise = $repo.save($scope.project) promise = $repo.save($scope.project)
promise.then -> promise.then ->
currentLoading.finish()
$confirm.notify("success")
$scope.$emit("project:loaded", $scope.project) $scope.$emit("project:loaded", $scope.project)
$confirm.notify("success")
projectService.fetchProject() projectService.fetchProject()
promise.then null, (data) -> promise.then null, (data) ->
currentLoading.finish() form.setErrors(data)
$confirm.notify("error", data._error_message) if data._error_message
$confirm.notify("error", data._error_message)
$el.on "change", ".module-activation.module-direct-active input", (event) ->
event.preventDefault()
submit()
$el.on "submit", "form", (event) -> $el.on "submit", "form", (event) ->
event.preventDefault() event.preventDefault()
submit() submit()
$el.on "click", ".admin-functionalities a.button-green", (event) -> $el.on "click", ".icon-save", (event) ->
event.preventDefault() event.preventDefault()
submit() submit()
$scope.$watch "isVideoconferenceActivated", (isVideoconferenceActivated) -> $el.on "keydown", ".videoconference-attributes input", (e) ->
if isVideoconferenceActivated return e.which != 32
$el.find(".videoconference-attributes").removeClass("hidden")
else $scope.$watch "project.videoconferences", (newVal, oldVal) ->
$el.find(".videoconference-attributes").addClass("hidden") # Reset videoconferences_extra_data if videoconference system change
if newVal? and oldVal? and newVal != oldVal
$scope.project.videoconferences_extra_data = ""
$scope.$watch "isVideoconferenceActivated", (newValue, oldValue) ->
if newValue == false
# Reset videoconference attributes
$scope.project.videoconferences = null $scope.project.videoconferences = null
$scope.project.videoconferences_extra_data = "" $scope.project.videoconferences_extra_data = ""
# Save when videoconference is desactivated
submit() if oldValue == true
$scope.$watch "project", (project) -> $scope.$watch "project", (project) ->
if project.videoconferences? if project.videoconferences?
$scope.isVideoconferenceActivated = true $scope.isVideoconferenceActivated = true

View File

@ -430,6 +430,10 @@
"DISABLE": "Disable", "DISABLE": "Disable",
"BACKLOG": "Backlog", "BACKLOG": "Backlog",
"BACKLOG_DESCRIPTION": "Manage your user stories to maintain an organized view of upcoming and prioritized work.", "BACKLOG_DESCRIPTION": "Manage your user stories to maintain an organized view of upcoming and prioritized work.",
"NUMBER_SPRINTS": "Expected number of sprints",
"NUMBER_SPRINTS_HELP": "0 for an undetermined quantity",
"NUMBER_US_POINTS": "Expected total of story points",
"NUMBER_US_POINTS_HELP": "0 for an undetermined quantity",
"KANBAN": "Kanban", "KANBAN": "Kanban",
"KANBAN_DESCRIPTION": "Organize your project in a lean way with this board.", "KANBAN_DESCRIPTION": "Organize your project in a lean way with this board.",
"ISSUES": "Issues", "ISSUES": "Issues",
@ -437,9 +441,9 @@
"WIKI": "Wiki", "WIKI": "Wiki",
"WIKI_DESCRIPTION": "Add, modify, or delete content in collaboration with others. This is the right place for your project documentation.", "WIKI_DESCRIPTION": "Add, modify, or delete content in collaboration with others. This is the right place for your project documentation.",
"MEETUP": "Meet Up", "MEETUP": "Meet Up",
"MEETUP_DESCRIPTION": "Choose your videoconference system. Even developers need face to face contact.", "MEETUP_DESCRIPTION": "Choose your videoconference system.",
"SELECT_VIDEOCONFERENCE": "Select a videoconference system", "SELECT_VIDEOCONFERENCE": "Select a videoconference system",
"SALT_CHAT_ROOM": "If you want you can append a salt code to the name of the chat room", "SALT_CHAT_ROOM": "Add a prefix to the chat room name",
"JITSI_CHAT_ROOM": "Jitsi", "JITSI_CHAT_ROOM": "Jitsi",
"APPEARIN_CHAT_ROOM": "AppearIn", "APPEARIN_CHAT_ROOM": "AppearIn",
"TALKY_CHAT_ROOM": "Talky", "TALKY_CHAT_ROOM": "Talky",
@ -451,8 +455,6 @@
"PROJECT_DETAILS": "Project details", "PROJECT_DETAILS": "Project details",
"PROJECT_NAME": "Project name", "PROJECT_NAME": "Project name",
"PROJECT_SLUG": "Project slug", "PROJECT_SLUG": "Project slug",
"NUMBER_SPRINTS": "Number of sprints (0 for an undetermined quantity)",
"NUMBER_US_POINTS": "Number of US points (0 for an undetermined quantity)",
"TAGS": "Tags", "TAGS": "Tags",
"DESCRIPTION": "Description", "DESCRIPTION": "Description",
"RECRUITING": "Is this project looking for people?", "RECRUITING": "Is this project looking for people?",

View File

@ -1,7 +1,10 @@
doctype html doctype html
div.wrapper(tg-project-modules, ng-controller="ProjectProfileController as ctrl", div.wrapper(
ng-init="section='admin'; sectionName='ADMIN.MODULES.TITLE'") tg-project-modules
ng-controller="ProjectProfileController as ctrl"
ng-init="section='admin'; sectionName='ADMIN.MODULES.TITLE'"
)
tg-project-menu tg-project-menu
sidebar.menu-secondary.sidebar.settings-nav(tg-admin-navigation="project-profile") sidebar.menu-secondary.sidebar.settings-nav(tg-admin-navigation="project-profile")
include ../includes/modules/admin-menu include ../includes/modules/admin-menu
@ -13,94 +16,159 @@ div.wrapper(tg-project-modules, ng-controller="ProjectProfileController as ctrl"
header header
include ../includes/components/mainTitle include ../includes/components/mainTitle
form form.module-container
div.functionality(ng-class="{true:'active', false:''}[project.is_backlog_activated]") .module.module-scrum(ng-class="{true:'active', false:''}[project.is_backlog_activated]")
svg.icon.icon-scrum .module-icon
use(xlink:href="#icon-scrum") svg.icon.icon-scrum
div.desc use(xlink:href="#icon-scrum")
p .module-name(translate="ADMIN.MODULES.BACKLOG")
span.title(translate="ADMIN.MODULES.BACKLOG") .module-desc
span(translate="ADMIN.MODULES.BACKLOG_DESCRIPTION") p(translate="ADMIN.MODULES.BACKLOG_DESCRIPTION")
div.activate .module-desc-options(ng-if="project.is_backlog_activated")
input.activate-input(type="checkbox", id="functionality-backlog", fieldset
ng-model="project.is_backlog_activated") label(for="total-sprints") {{ 'ADMIN.MODULES.NUMBER_SPRINTS' | translate }}
label.button.button-gray(ng-switch="project.is_backlog_activated", input(
for="functionality-backlog") id="total-sprints"
span(ng-switch-when="true", translate="ADMIN.MODULES.DISABLE") name="total-sprints"
span(ng-switch-when="false", translate="ADMIN.MODULES.ENABLE") type="number"
min="0"
placeholder="{{'ADMIN.MODULES.NUMBER_SPRINTS_HELP' | translate}}"
ng-model="project.total_milestones"
data-type="digits"
)
div.functionality(ng-class="{true:'active', false:''}[project.is_kanban_activated]") fieldset
svg.icon.icon-kanban label(for="total-story-points") {{ 'ADMIN.MODULES.NUMBER_US_POINTS' | translate }}
use(xlink:href="#icon-kanban") input(
div.desc id="total-story-points"
p name="total-story-points"
span.title(translate="ADMIN.MODULES.KANBAN") type="number"
span(translate="ADMIN.MODULES.KANBAN_DESCRIPTION") min="0"
div.activate placeholder="{{'ADMIN.MODULES.NUMBER_US_POINTS_HELP' | translate}}"
input.activate-input(type="checkbox", id="functionality-kanban", ng-model="project.total_story_points"
ng-model="project.is_kanban_activated") data-type="digits"
label.button.button-gray(ng-switch="project.is_kanban_activated", )
for="functionality-kanban") svg.icon.icon-save(ng-if="project.is_backlog_activated")
span(ng-switch-when="true", translate="ADMIN.MODULES.DISABLE") use(xlink:href="#icon-save")
span(ng-switch-when="false", translate="ADMIN.MODULES.ENABLE") .module-activation.module-direct-active
div.check
input.activate-input(
id="functionality-backlog"
name="functionality-backlog"
type="checkbox"
ng-checked="project.is_backlog_activated"
ng-model="project.is_backlog_activated"
)
div
span.check-text.check-yes(translate="COMMON.YES")
span.check-text.check-no(translate="COMMON.NO")
div.functionality(ng-class="{true:'active', false:''}[project.is_issues_activated]") .module.module-kanban(ng-class="{true:'active', false:''}[project.is_kanban_activated]")
svg.icon.icon-issues .module-icon
use(xlink:href="#icon-issues") svg.icon.icon-kanban
div.desc use(xlink:href="#icon-kanban")
p .module-name(translate="ADMIN.MODULES.KANBAN")
span.title(translate="ADMIN.MODULES.ISSUES") .module-desc(translate="ADMIN.MODULES.KANBAN_DESCRIPTION")
span(translate="ADMIN.MODULES.ISSUES_DESCRIPTION") .module-activation.module-direct-active
div.activate div.check
input.activate-input(type="checkbox", id="functionality-issues", input.activate-input(
ng-model="project.is_issues_activated") id="functionality-kanban"
label.button.button-gray(ng-switch="project.is_issues_activated", name="functionality-kanban"
for="functionality-issues") type="checkbox"
span(ng-switch-when="true", translate="ADMIN.MODULES.DISABLE") ng-checked="project.is_kanban_activated"
span(ng-switch-when="false", translate="ADMIN.MODULES.ENABLE") ng-model="project.is_kanban_activated"
)
div
span.check-text.check-yes(translate="COMMON.YES")
span.check-text.check-no(translate="COMMON.NO")
div.functionality(ng-class="{true:'active', false:''}[project.is_wiki_activated]") .module.module-issues(ng-class="{true:'active', false:''}[project.is_issues_activated]")
svg.icon.icon-wiki .module-icon
use(xlink:href="#icon-wiki") svg.icon.icon-issues
div.desc use(xlink:href="#icon-issues")
p .module-name(translate="ADMIN.MODULES.ISSUES")
span.title(translate="ADMIN.MODULES.WIKI") .module-desc(translate="ADMIN.MODULES.ISSUES_DESCRIPTION")
span(translate="ADMIN.MODULES.WIKI_DESCRIPTION") .module-activation.module-direct-active
div.activate div.check
input.activate-input(type="checkbox", id="functionality-wiki", input.activate-input(
ng-model="project.is_wiki_activated") id="functionality-issues"
label.button.button-gray(ng-switch="project.is_wiki_activated", name="functionality-issues"
for="functionality-wiki") type="checkbox"
span(ng-switch-when="true", translate="ADMIN.MODULES.DISABLE") ng-checked="project.is_issues_activated"
span(ng-switch-when="false", translate="ADMIN.MODULES.ENABLE") ng-model="project.is_issues_activated"
)
div
span.check-text.check-yes(translate="COMMON.YES")
span.check-text.check-no(translate="COMMON.NO")
div.functionality(ng-class="{true:'active', false:''}[isVideoconferenceActivated]") .module.module-wiki(ng-class="{true:'active', false:''}[project.is_wiki_activated]")
svg.icon.icon-bubble-empty .module-icon
use(xlink:href="#icon-bubble-empty") svg.icon.icon-wiki
div.desc use(xlink:href="#icon-wiki")
p .module-name(translate="ADMIN.MODULES.WIKI")
span.title(translate="ADMIN.MODULES.MEETUP") .module-desc(translate="ADMIN.MODULES.WIKI_DESCRIPTION")
span(translate="ADMIN.MODULES.MEETUP_DESCRIPTION") .module-activation.module-direct-active
div.activate div.check
input.activate-input(type="checkbox", id="functionality-video", input.activate-input(
ng-model="isVideoconferenceActivated") id="functionality-wiki"
label.button.button-gray(ng-switch="isVideoconferenceActivated", name="functionality-wiki"
for="functionality-video") type="checkbox"
span(ng-switch-when="true", translate="ADMIN.MODULES.DISABLE") ng-checked="project.is_wiki_activated"
span(ng-switch-when="false", translate="ADMIN.MODULES.ENABLE") ng-model="project.is_wiki_activated"
)
div
span.check-text.check-yes(translate="COMMON.YES")
span.check-text.check-no(translate="COMMON.NO")
div.videoconference-attributes.hidden .module.module-videoconference(ng-class="{true:'active', false:''}[isVideoconferenceActivated]")
select(ng-model="project.videoconferences", .module-icon
ng-options="e.id as e.name|translate for e in [{'id':'appear-in', 'name':'ADMIN.MODULES.APPEARIN_CHAT_ROOM'},{'id':'jitsi', 'name': 'ADMIN.MODULES.JITSI_CHAT_ROOM'},{'id':'talky', 'name': 'ADMIN.MODULES.TALKY_CHAT_ROOM'},{'id':'custom', 'name': 'ADMIN.MODULES.CUSTOM_CHAT_ROOM'}]") svg.icon.icon-bubble-empty
option(value="", translate="ADMIN.MODULES.SELECT_VIDEOCONFERENCE") use(xlink:href="#icon-bubble-empty")
input(ng-if="project.videoconferences && project.videoconferences != 'custom'", .module-name(translate="ADMIN.MODULES.MEETUP")
type="text", .module-desc
ng-model="project.videoconferences_extra_data", p(translate="ADMIN.MODULES.MEETUP_DESCRIPTION")
data-maxlength="255", div.videoconference-attributes(ng-if="isVideoconferenceActivated")
placeholder="{{'ADMIN.MODULES.SALT_CHAT_ROOM' | translate}}") select(
input(ng-if="project.videoconferences == 'custom'", id="videoconference-type"
type="text", name="videoconference-type"
ng-model="project.videoconferences_extra_data", ng-model="project.videoconferences"
data-maxlength="255", ng-options="e.id as e.name|translate for e in [{'id':'appear-in', 'name':'ADMIN.MODULES.APPEARIN_CHAT_ROOM'},{'id':'jitsi', 'name': 'ADMIN.MODULES.JITSI_CHAT_ROOM'},{'id':'talky', 'name': 'ADMIN.MODULES.TALKY_CHAT_ROOM'},{'id':'custom', 'name': 'ADMIN.MODULES.CUSTOM_CHAT_ROOM'}]")
placeholder="{{'ADMIN.MODULES.URL_CHAT_ROOM' | translate}}") option(
button.button-green.submit-button(type="submit", title="{{'COMMON.SAVE' | translate}}", translate="COMMON.SAVE") value=""
translate="ADMIN.MODULES.SELECT_VIDEOCONFERENCE"
)
fieldset(ng-if="project.videoconferences && project.videoconferences != 'custom'")
input(
id="videoconference-prefix"
name="videoconference-prefix"
type="text"
ng-model="project.videoconferences_extra_data"
data-maxlength="250"
placeholder="{{'ADMIN.MODULES.SALT_CHAT_ROOM' | translate}}"
)
fieldset(ng-if="project.videoconferences == 'custom'")
input(
id="videoconference-url"
name="videoconference-url"
type="url"
ng-model="project.videoconferences_extra_data"
data-maxlength="250"
placeholder="{{'ADMIN.MODULES.URL_CHAT_ROOM' | translate}}"
data-type="url"
data-required="true"
)
svg.icon.icon-save(ng-if="project.videoconferences")
use(xlink:href="#icon-save")
.module-activation
div.check
input.activate-input(
id="functionality-video"
name="functionality-video"
type="checkbox"
ng-checked="project.isVideoconferenceActivated"
ng-model="isVideoconferenceActivated"
)
div
span.check-text.check-yes(translate="COMMON.YES")
span.check-text.check-no(translate="COMMON.NO")

View File

@ -78,30 +78,6 @@ div.wrapper(
ng-model="project.tags" ng-model="project.tags"
) )
fieldset
label(for="project-sprints") {{ 'ADMIN.PROJECT_PROFILE.NUMBER_SPRINTS' | translate }}
input(
type="number"
name="total_milestones"
min="0"
placeholder="{{'ADMIN.PROJECT_PROFILE.NUMBER_SPRINTS' | translate}}"
id="project-sprints"
ng-model="project.total_milestones"
data-type="digits"
)
fieldset
label(for="total-story-points") {{ 'ADMIN.PROJECT_PROFILE.NUMBER_US_POINTS' | translate }}
input(
type="number"
name="total_story_points"
min="0"
placeholder="{{'ADMIN.PROJECT_PROFILE.NUMBER_US_POINTS' | translate}}"
id="total-story-points"
ng-model="project.total_story_points"
data-type="digits"
)
fieldset.looking-for-people fieldset.looking-for-people
.looking-for-people-selector .looking-for-people-selector
span {{ 'ADMIN.PROJECT_PROFILE.RECRUITING' | translate }} span {{ 'ADMIN.PROJECT_PROFILE.RECRUITING' | translate }}

View File

@ -16,7 +16,7 @@ div.wrapper(tg-backlog, ng-controller="BacklogController as ctrl",
use(xlink:href="#icon-graph") use(xlink:href="#icon-graph")
div.empty-text div.empty-text
p.title(translate="BACKLOG.CUSTOMIZE_GRAPH") p.title(translate="BACKLOG.CUSTOMIZE_GRAPH")
p {{'BACKLOG.CUSTOMIZE_GRAPH_TEXT' | translate}} #[a(href="", tg-nav="project-admin-project-profile-details:project=project.slug", title="{{'BACKLOG.CUSTOMIZE_GRAPH_TITLE' | translate}}") {{'BACKLOG.CUSTOMIZE_GRAPH_ADMIN' | translate}}] p {{'BACKLOG.CUSTOMIZE_GRAPH_TEXT' | translate}} #[a(href="", tg-nav="project-admin-project-profile-modules:project=project.slug", title="{{'BACKLOG.CUSTOMIZE_GRAPH_TITLE' | translate}}") {{'BACKLOG.CUSTOMIZE_GRAPH_ADMIN' | translate}}]
div.graphics-container.js-burndown-graph div.graphics-container.js-burndown-graph
div.burndown(tg-burndown-backlog-graph) div.burndown(tg-burndown-backlog-graph)

View File

@ -8,12 +8,12 @@
width: 65px; width: 65px;
input { input {
cursor: pointer; cursor: pointer;
height: 500px; height: 50px;
left: -10px; left: -10px;
opacity: 0; opacity: 0;
position: absolute; position: absolute;
top: -10px; top: -10px;
width: 500px; width: 100px;
z-index: 999; z-index: 999;
+ div { + div {
background-color: $gray; background-color: $gray;

View File

@ -1,62 +1,75 @@
.admin-functionalities { .admin-functionalities {
form { .module-container {
display: flex; max-width: 900px;
flex-wrap: wrap; width: 100%;
} }
.functionality { .module {
align-content: center; align-content: center;
align-items: center; align-items: flex-start;
background-color: $whitish; border-bottom: 1px solid $whitish;
display: flex; display: flex;
flex-direction: column; padding: 1rem 0;
justify-content: center;
margin-bottom: .3rem;
margin-right: .3rem;
opacity: .5;
padding: 1rem;
position: relative;
transition: all .2s linear;
vertical-align: top;
width: 32%;
&.active { &.active {
background-color: rgba($primary, .3); .module-icon .icon,
opacity: 1; .module-name {
} color: $primary;
.icon { fill: $primary;
fill: $gray;
height: 3rem;
margin: 1rem auto;
width: 3rem;
}
.desc {
text-align: center;
width: 100%;
}
.activate-input {
display: none;
+label {
color: $white;
cursor: pointer;
display: block;
text-align: center;
} }
} }
.title { }
@extend %bold; .module-icon {
display: block; flex-basis: 2rem;
} flex-shrink: 0;
select { margin: 0 .5rem 0 0;
margin-top: 1rem; .icon {
@include svg-size(3rem);
fill: $gray-light;
} }
} }
.module-name {
@extend %bold;
@extend %large;
color: $gray-light;
flex-basis: 100px;
flex-shrink: 0;
margin: 0 .5rem;
}
.module-desc {
@extend %small;
color: $gray-light;
flex: 1;
margin: 0 2rem 0 0;
p {
margin: 0;
}
}
.module-desc-options,
.videoconference-attributes { .videoconference-attributes {
select { align-items: flex-start;
margin-bottom: .5rem; display: flex;
margin-top: .5rem;
fieldset,
.icon {
margin: 0 .5rem;
}
.icon {
@include svg-size(2.5rem);
align-self: center;
cursor: pointer;
fill: $gray-light;
&:hover {
fill: $primary;
}
} }
} }
.button-green { .module-scrum {
color: $white; .icon {
display: block; align-self: flex-end;
text-align: center; }
}
.module-videoconference {
.icon {
align-self: flex-start;
}
} }
} }